From 3d6b9255b320a814bfb6bc3777a68bc867d0f9f8 Mon Sep 17 00:00:00 2001 From: fiore Date: Wed, 19 Mar 2025 11:24:38 +0900 Subject: [PATCH 01/10] =?UTF-8?q?DO-31=20Feat:=20=EA=B8=88=EC=88=98=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EC=9D=B4=EC=A0=84=20=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EB=B3=B5=EC=A0=9C=ED=95=98=EC=97=AC=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 금수 검사 전 보드 복사하여 임시 보드 넘김 --- Assets/Script/Renju/RenjuForbiddenMoveDetector.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs index 88e97a3..52ddf34 100644 --- a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs +++ b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs @@ -14,6 +14,7 @@ public class RenjuForbiddenMoveDetector /// 금수 좌표를 담은 리스트 public List RenjuForbiddenMove(Enums.PlayerType[,] board) { + var tempBoard = (Enums.PlayerType[,])board.Clone(); return _ruleChecker.GetForbiddenMoves(board); } } \ No newline at end of file From ffdd4e9aa872a947afd695b6001648c03e4b3083 Mon Sep 17 00:00:00 2001 From: fiore Date: Wed, 19 Mar 2025 13:19:12 +0900 Subject: [PATCH 02/10] =?UTF-8?q?DO-31=20Feat:=20=EC=8C=8D=EC=82=BC=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 쌍삼 감지기 추가 - 통합 클래스에서 임시 보드 복제하여 전달 --- Assets/Script/Renju/ForbiddenDetectorBase.cs | 1 + .../Script/Renju/RenjuDoubleThreeDetector.cs | 269 +++++++++++++++++- .../Renju/RenjuForbiddenMoveDetector.cs | 2 +- 3 files changed, 270 insertions(+), 2 deletions(-) diff --git a/Assets/Script/Renju/ForbiddenDetectorBase.cs b/Assets/Script/Renju/ForbiddenDetectorBase.cs index 24741c8..7c342c6 100644 --- a/Assets/Script/Renju/ForbiddenDetectorBase.cs +++ b/Assets/Script/Renju/ForbiddenDetectorBase.cs @@ -2,6 +2,7 @@ { private protected Enums.PlayerType Black = Enums.PlayerType.PlayerA; private protected Enums.PlayerType Space = Enums.PlayerType.None; + private protected Enums.PlayerType White = Enums.PlayerType.PlayerB; // 8방향을 나타내는 델타 배열 (가로, 세로, 대각선 방향) private protected readonly int[,] Directions = new int[8, 2] diff --git a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs index 943063e..03eab22 100644 --- a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs +++ b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs @@ -16,11 +16,278 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase board[row, col] = Black; // 쌍삼 검사 - // bool isThreeThree = CheckThreeThree(board, row, col); + bool isDoubleThree = CheckDoubleThree(board, row, col); // 원래 상태로 되돌림 board[row, col] = Space; return false; } + + /// + /// 쌍삼(3-3) 여부를 검사합니다. + /// + private bool CheckDoubleThree(Enums.PlayerType[,] board, int row, int col) + { + int openThreeCount = 0; + + // 4개의 방향 쌍에 대해 검사 (대각선 및 직선 포함) + for (int i = 0; i < 4; i++) + { + int dir1 = DirectionPairs[i, 0]; + int dir2 = DirectionPairs[i, 1]; + + // 해당 방향에서 열린 3의 개수 계산 + if (CheckOpenThreeInDirection(board, row, col, dir1, dir2)) + { + openThreeCount++; + + // 이미 열린 3이 2개 이상 발견되면 쌍삼으로 판정 + if (openThreeCount >= 2) + { + return true; + } + } + } + + return false; + } + + /// + /// 특정 방향에서 열린 3이 형성되는지 확인합니다. + /// + private bool CheckOpenThreeInDirection(Enums.PlayerType[,] board, int row, int col, int dir1, int dir2) + { + // 각 방향으로 최대 5칸까지의 범위를 검사 (현재 위치 포함 총 11칸) + Enums.PlayerType[] linePattern = new Enums.PlayerType[11]; + int centerIndex = 5; // 중앙 인덱스 (현재 위치) + + // 현재 위치 설정 + linePattern[centerIndex] = Black; + + // dir1 방향으로 패턴 채우기 + for (int i = 1; i <= 5; i++) + { + int newRow = row + Directions[dir1, 0] * i; + int newCol = col + Directions[dir1, 1] * i; + + if (IsInBounds(newRow, newCol)) + { + linePattern[centerIndex + i] = board[newRow, newCol]; + } + else + { + linePattern[centerIndex + i] = White; // 범위 밖은 막힌 것으로 처리 + } + } + + // dir2 방향으로 패턴 채우기 + for (int i = 1; i <= 5; i++) + { + int newRow = row + Directions[dir2, 0] * i; + int newCol = col + Directions[dir2, 1] * i; + + if (IsInBounds(newRow, newCol)) + { + linePattern[centerIndex - i] = board[newRow, newCol]; + } + else + { + linePattern[centerIndex - i] = White; // 범위 밖은 막힌 것으로 처리 + } + } + + // 열린 3 패턴 확인 + return CheckForOpenThree(linePattern, centerIndex); + } + + /// + /// 라인 패턴에서 열린 3 패턴을 확인합니다. + /// + private bool CheckForOpenThree(Enums.PlayerType[] linePattern, int centerIndex) + { + // 연속된 열린 3 확인 + if (CheckConsecutiveOpenThree(linePattern, centerIndex)) + { + return true; + } + + // 한 칸 떨어진 열린 3 확인 + if (CheckGappedOpenThree(linePattern, centerIndex)) + { + return true; + } + + return false; + } + + /// + /// 연속된 열린 3 패턴을 확인합니다. + /// + private bool CheckConsecutiveOpenThree(Enums.PlayerType[] linePattern, int centerIndex) + { + // 연속된 3개의 돌 패턴 + // 시작 인덱스를 조정하여 센터가 패턴 내에 있는지 확인 + for (int start = centerIndex - 2; start <= centerIndex; start++) + { + // 범위 체크 + if (start < 0 || start + 2 >= linePattern.Length) + { + continue; + } + + // 3개의 연속된 돌 확인 + bool isConsecutiveThree = true; + for (int i = 0; i < 3; i++) + { + if (linePattern[start + i] != Black) + { + isConsecutiveThree = false; + break; + } + } + + if (isConsecutiveThree) + { + // 양쪽이 모두 열려있는지 확인 + bool isLeftOpen = (start - 1 >= 0) && (linePattern[start - 1] == Space); + bool isRightOpen = (start + 3 < linePattern.Length) && (linePattern[start + 3] == Space); + + // 양쪽이 모두 열려있으면 열린 3 + if (isLeftOpen && isRightOpen) + { + // 추가 검증: 더 확장해서 열려있는지 확인 + bool isExtendedLeftOpen = IsExtendedOpen(linePattern, start - 1, -1); + bool isExtendedRightOpen = IsExtendedOpen(linePattern, start + 3, 1); + + if (isExtendedLeftOpen && isExtendedRightOpen) + { + return true; + } + } + } + } + + return false; + } + + /// + /// 한 칸 떨어진 열린 3 패턴을 확인합니다. + /// + private bool CheckGappedOpenThree(Enums.PlayerType[] linePattern, int centerIndex) + { + // 한 칸 떨어진 패턴 확인 + // 패턴 1: ●●○● (centerIndex가 어느 위치든 가능) + // 패턴 2: ●○●● (centerIndex가 어느 위치든 가능) + + // 윈도우 크기 4로 슬라이딩하면서 검사 + for (int start = Mathf.Max(0, centerIndex - 3); start <= Mathf.Min(linePattern.Length - 4, centerIndex); start++) + { + // 패턴 내에 돌과 빈칸 개수 확인 + int stoneCount = 0; + int gapCount = 0; + int gapPosition = -1; + + for (int i = 0; i < 4; i++) + { + if (linePattern[start + i] == Black) + { + stoneCount++; + } + else if (linePattern[start + i] == Space) + { + gapCount++; + gapPosition = start + i; + } + else + { + // 상대 돌이나 벽이 있으면 패턴이 깨짐 + stoneCount = 0; + break; + } + } + + // 3개의 돌과 1개의 빈칸으로 구성된 패턴 + if (stoneCount == 3 && gapCount == 1) + { + // 빈칸에 돌을 놓았을 때 열린 4가 되는지 확인 + if (CheckIfCreatesOpenFour(linePattern, gapPosition)) + { + return true; + } + } + } + + return false; + } + + /// + /// 빈칸에 돌을 놓았을 때 열린 4가 되는지 확인합니다. + /// + private bool CheckIfCreatesOpenFour(Enums.PlayerType[] linePattern, int position) + { + // 시뮬레이션: 빈칸에 돌을 놓아봄 + Enums.PlayerType[] testPattern = new Enums.PlayerType[linePattern.Length]; + System.Array.Copy(linePattern, testPattern, linePattern.Length); + testPattern[position] = Black; + + // 놓은 위치를 포함해 연속된 4가 있는지 확인 + for (int start = Mathf.Max(0, position - 3); start <= position; start++) + { + // 범위 체크 + if (start + 3 >= testPattern.Length) + { + continue; + } + + // 4개의 연속된 돌 확인 + bool isConsecutiveFour = true; + for (int i = 0; i < 4; i++) + { + if (testPattern[start + i] != Black) + { + isConsecutiveFour = false; + break; + } + } + + if (isConsecutiveFour) + { + // 양쪽이 모두 열려있는지 확인 (열린 4) + bool isLeftOpen = (start - 1 >= 0) && (testPattern[start - 1] == Space); + bool isRightOpen = (start + 4 < testPattern.Length) && (testPattern[start + 4] == Space); + + if (isLeftOpen && isRightOpen) + { + return true; // 열린 4가 됨 + } + } + } + + return false; + } + + /// + /// 특정 방향으로 추가로 열려있는지 확인합니다. + /// + private bool IsExtendedOpen(Enums.PlayerType[] linePattern, int startPos, int direction) + { + // 한 칸 더 확장해서 확인 + int nextPos = startPos + direction; + if (nextPos >= 0 && nextPos < linePattern.Length) + { + // 다음 칸이 상대 돌이나 벽이면 확장 불가 + if (linePattern[nextPos] == White) + { + return false; + } + } + else + { + // 범위를 벗어나면 확장 불가 + return false; + } + + return true; + } } \ No newline at end of file diff --git a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs index 52ddf34..35446af 100644 --- a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs +++ b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs @@ -15,6 +15,6 @@ public class RenjuForbiddenMoveDetector public List RenjuForbiddenMove(Enums.PlayerType[,] board) { var tempBoard = (Enums.PlayerType[,])board.Clone(); - return _ruleChecker.GetForbiddenMoves(board); + return _ruleChecker.GetForbiddenMoves(tempBoard); } } \ No newline at end of file From 5695f2c95d852cd1cdad3b965b4def8e150412ca Mon Sep 17 00:00:00 2001 From: fiore Date: Wed, 19 Mar 2025 17:04:45 +0900 Subject: [PATCH 03/10] =?UTF-8?q?DO-31=20Feat:=20=EC=8C=8D=EC=82=BC?= =?UTF-8?q?=EA=B8=88=EC=88=98=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 쌍삼 금수 여부 반환 - 4-3일 경우 금수에서 제외토록 처리 --- .../Script/Renju/RenjuDoubleThreeDetector.cs | 129 +++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs index 03eab22..327eb39 100644 --- a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs +++ b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs @@ -18,10 +18,23 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase // 쌍삼 검사 bool isDoubleThree = CheckDoubleThree(board, row, col); + // 쌍삼으로 판정된 경우 4-3 상황인지 추가 검사 + if (isDoubleThree) + { + // 4가 만들어지는지 확인 + bool hasFour = CheckForFour(board, row, col); + + // 4-3 상황이면 금수에서 제외 + if (hasFour) + { + isDoubleThree = false; + } + } + // 원래 상태로 되돌림 board[row, col] = Space; - return false; + return isDoubleThree; } /// @@ -290,4 +303,118 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase return true; } + + /// + /// 4가 만들어지는지 확인합니다. + /// + private bool CheckForFour(Enums.PlayerType[,] board, int row, int col) + { + // 4개의 방향 쌍에 대해 검사 + for (int i = 0; i < 4; i++) + { + int dir1 = DirectionPairs[i, 0]; + int dir2 = DirectionPairs[i, 1]; + + // 해당 방향에서 4가 형성되는지 확인 + if (CheckFourInDirection(board, row, col, dir1, dir2)) + { + return true; + } + } + + return false; + } + + /// + /// 특정 방향에서 4가 형성되는지 확인합니다. + /// 떨어져 있는 돌도 고려합니다 (한 칸 또는 두 칸 떨어진 패턴 포함). + /// + private bool CheckFourInDirection(Enums.PlayerType[,] board, int row, int col, int dir1, int dir2) + { + // 각 방향으로 최대 5칸까지의 범위를 검사 (현재 위치 포함 총 11칸) + Enums.PlayerType[] linePattern = ExtractLinePattern(board, row, col, dir1, dir2); + int centerIndex = 5; // 중앙 인덱스 (현재 위치) + + // 모든 가능한 패턴 확인 + return CheckFourOneGap(linePattern, centerIndex); + } + + /// + /// 라인 패턴을 추출합니다. (중복 코드를 방지하기 위한 헬퍼 메서드) + /// + private Enums.PlayerType[] ExtractLinePattern(Enums.PlayerType[,] board, int row, int col, int dir1, int dir2) + { + Enums.PlayerType[] linePattern = new Enums.PlayerType[11]; + int centerIndex = 5; // 중앙 인덱스 (현재 위치) + + // 현재 위치 설정 + linePattern[centerIndex] = Black; + + // dir1 방향으로 패턴 채우기 + for (int i = 1; i <= 5; i++) + { + int newRow = row + Directions[dir1, 0] * i; + int newCol = col + Directions[dir1, 1] * i; + + if (IsInBounds(newRow, newCol)) + { + linePattern[centerIndex + i] = board[newRow, newCol]; + } + else + { + linePattern[centerIndex + i] = Space; // 범위 밖은 빈칸으로 처리 + } + } + + // dir2 방향으로 패턴 채우기 + for (int i = 1; i <= 5; i++) + { + int newRow = row + Directions[dir2, 0] * i; + int newCol = col + Directions[dir2, 1] * i; + + if (IsInBounds(newRow, newCol)) + { + linePattern[centerIndex - i] = board[newRow, newCol]; + } + else + { + linePattern[centerIndex - i] = Space; // 범위 밖은 빈칸으로 처리 + } + } + + return linePattern; + } + + /// + /// 한 칸 떨어진 4 패턴을 확인합니다. + /// + private bool CheckFourOneGap(Enums.PlayerType[] linePattern, int centerIndex) + { + // 윈도우 슬라이딩으로 연속된 5칸을 검사 (한 칸 떨어진 패턴을 위해) + for (int start = 0; start <= 5; start++) + { + // 현재 위치가 이 윈도우에 포함되는지 확인 + bool currentPositionInWindow = (start <= centerIndex && centerIndex < start + 5); + if (!currentPositionInWindow) continue; + + // 윈도우 내의 돌 개수 세기 + int stoneCount = 0; + for (int i = 0; i < 5; i++) + { + if (linePattern[start + i] == Black) + { + stoneCount++; + } + } + + // 정확히 4개의 돌이 있고, 1개의 빈칸이 있으면 4로 판정 + // (현재 위치는 흑으로 이미 설정되어 있음) + if (stoneCount == 4) + { + return true; + } + } + + return false; + } } \ No newline at end of file From ed9e8664a807f7508abbe143212868eec4af4690 Mon Sep 17 00:00:00 2001 From: fiore Date: Wed, 19 Mar 2025 17:10:53 +0900 Subject: [PATCH 04/10] =?UTF-8?q?DO-31=20Refactor:=20=EC=A4=91=EB=B3=B5?= =?UTF-8?q?=EB=90=98=EB=8A=94=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RenjuRuleChecker.cs 삭제 - RenjuForbiddenMoveDetector.cs로 통합 --- .../Renju/RenjuForbiddenMoveDetector.cs | 42 +++++++++++++-- Assets/Script/Renju/RenjuRuleChecker.cs | 51 ------------------- Assets/Script/Renju/RenjuRuleChecker.cs.meta | 3 -- 3 files changed, 39 insertions(+), 57 deletions(-) delete mode 100644 Assets/Script/Renju/RenjuRuleChecker.cs delete mode 100644 Assets/Script/Renju/RenjuRuleChecker.cs.meta diff --git a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs index 35446af..fce9c13 100644 --- a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs +++ b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs @@ -2,10 +2,12 @@ using UnityEngine; -public class RenjuForbiddenMoveDetector +public class RenjuForbiddenMoveDetector : ForbiddenDetectorBase { // 렌주 룰 금수 감지기 생성 - private RenjuRuleChecker _ruleChecker = new RenjuRuleChecker(); + private RenjuOverlineDetector _overlineDetactor = new(); + private RenjuDoubleFourDetector _doubleFourDetactor = new(); + private RenjuDoubleThreeDetector _doubleThreeDetector = new(); /// /// 렌주 룰로 금수 리스트를 반환하는 함수 @@ -15,6 +17,40 @@ public class RenjuForbiddenMoveDetector public List RenjuForbiddenMove(Enums.PlayerType[,] board) { var tempBoard = (Enums.PlayerType[,])board.Clone(); - return _ruleChecker.GetForbiddenMoves(tempBoard); + + List forbiddenMoves = new(); + for (int row = 0; row < BoardSize; row++) + { + for (int col = 0; col < BoardSize; col++) + { + // ** 비어 있지 않으면 검사할 필요 없음 ** + if (!IsEmptyPosition(tempBoard, row, col)) continue; + + // 장목 검사 + if (_overlineDetactor.IsOverline(tempBoard, row, col)) + { + Debug.Log("장목 금수 좌표 X축 : " + row + ", Y축 : " + col); + forbiddenMoves.Add(new Vector2Int(row, col)); + continue; + } + + // 4-4 검사 + if (_doubleFourDetactor.IsDoubleFour(tempBoard, row, col)) + { + Debug.Log("사사 금수 좌표 X축 : " + row + ", Y축 : " + col); + forbiddenMoves.Add(new Vector2Int(row, col)); + continue; + } + + // 3-3 검사 + if (_doubleThreeDetector.IsDoubleThree(tempBoard, row, col)) + { + Debug.Log("삼삼 금수 좌표 X축 : " + row + ", Y축 : " + col); + forbiddenMoves.Add(new Vector2Int(row, col)); + } + } + } + + return forbiddenMoves; } } \ No newline at end of file diff --git a/Assets/Script/Renju/RenjuRuleChecker.cs b/Assets/Script/Renju/RenjuRuleChecker.cs deleted file mode 100644 index 8cdf082..0000000 --- a/Assets/Script/Renju/RenjuRuleChecker.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -/// -/// 렌주 규칙의 모든 금수 규칙(3-3, 4-4, 장목)을 검사하는 통합 클래스 -/// -public class RenjuRuleChecker: ForbiddenDetectorBase -{ - private RenjuOverlineDetector _overlineDetactor = new(); - private RenjuDoubleFourDetector _doubleFourDetactor = new(); - private RenjuDoubleThreeDetector _doubleThreeDetector = new(); - - public List GetForbiddenMoves(Enums.PlayerType[,] board) - { - List forbiddenMoves = new(); - for (int row = 0; row < BoardSize; row++) - { - for (int col = 0; col < BoardSize; col++) - { - // ** 비어 있지 않으면 검사할 필요 없음 ** - if (!IsEmptyPosition(board, row, col)) continue; - - // 장목 검사 - if (_overlineDetactor.IsOverline(board, row, col)) - { - Debug.Log("장목 금수 좌표 X축 : " + row + ", Y축 : " + col); - forbiddenMoves.Add(new Vector2Int(row, col)); - continue; - } - - // 4-4 검사 - if (_doubleFourDetactor.IsDoubleFour(board, row, col)) - { - Debug.Log("사사 금수 좌표 X축 : " + row + ", Y축 : " + col); - forbiddenMoves.Add(new Vector2Int(row, col)); - continue; - } - - // 3-3 검사 - if (_doubleThreeDetector.IsDoubleThree(board, row, col)) - { - Debug.Log("삼삼 금수 좌표 X축 : " + row + ", Y축 : " + col); - forbiddenMoves.Add(new Vector2Int(row, col)); - } - } - } - - return forbiddenMoves; - } -} - diff --git a/Assets/Script/Renju/RenjuRuleChecker.cs.meta b/Assets/Script/Renju/RenjuRuleChecker.cs.meta deleted file mode 100644 index a982a5d..0000000 --- a/Assets/Script/Renju/RenjuRuleChecker.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 083e8b9070ed407b8744d4cacd0d53dc -timeCreated: 1742256498 \ No newline at end of file From 7b8db4a2f3423edd387cb3fbd6215fe6509c21a9 Mon Sep 17 00:00:00 2001 From: fiore Date: Wed, 19 Mar 2025 17:46:58 +0900 Subject: [PATCH 05/10] =?UTF-8?q?DO-31=20Docs:=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95,=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Script/Renju/ForbiddenDetectorBase.cs | 26 +++-- .../Script/Renju/RenjuDoubleFourDetector.cs | 7 +- .../Script/Renju/RenjuDoubleThreeDetector.cs | 16 +-- Assets/Trash Can_JY/Renju.unity | 105 +++++++++++++++++- 4 files changed, 124 insertions(+), 30 deletions(-) diff --git a/Assets/Script/Renju/ForbiddenDetectorBase.cs b/Assets/Script/Renju/ForbiddenDetectorBase.cs index 7c342c6..f954c1a 100644 --- a/Assets/Script/Renju/ForbiddenDetectorBase.cs +++ b/Assets/Script/Renju/ForbiddenDetectorBase.cs @@ -1,10 +1,20 @@ public class ForbiddenDetectorBase { + /// + /// 흑색 돌 + /// private protected Enums.PlayerType Black = Enums.PlayerType.PlayerA; + /// + /// 빈칸 + /// private protected Enums.PlayerType Space = Enums.PlayerType.None; + /// + /// 흰색 돌, 렌주룰 내에선 벽으로도 활용 + /// private protected Enums.PlayerType White = Enums.PlayerType.PlayerB; - - // 8방향을 나타내는 델타 배열 (가로, 세로, 대각선 방향) + /// + /// 8방향을 나타내는 델타 배열 (가로, 세로, 대각선 방향) + /// private protected readonly int[,] Directions = new int[8, 2] { { 1, 0 }, // 오른쪽 @@ -17,11 +27,13 @@ { 1, -1 } // 오른쪽 위 }; - // 방향 쌍을 정의 (반대 방향끼리 쌍을 이룸) - // 0-4: 가로 방향 쌍 (동-서) - // 1-5: 대각선 방향 쌍 (남동-북서) - // 2-6: 세로 방향 쌍 (남-북) - // 3-7: 대각선 방향 쌍 (남서-북동) + /// + /// 방향 쌍을 정의 (반대 방향끼리 쌍을 이룸) + /// 0-4: 가로 방향 쌍 (동-서) + /// 1-5: 대각선 방향 쌍 (남동-북서) + /// 2-6: 세로 방향 쌍 (남-북) + /// 3-7: 대각선 방향 쌍 (남서-북동) + /// private protected readonly int[,] DirectionPairs = { { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 } }; // 15*15 보드 사이즈 diff --git a/Assets/Script/Renju/RenjuDoubleFourDetector.cs b/Assets/Script/Renju/RenjuDoubleFourDetector.cs index 8bc8b65..9f38dce 100644 --- a/Assets/Script/Renju/RenjuDoubleFourDetector.cs +++ b/Assets/Script/Renju/RenjuDoubleFourDetector.cs @@ -30,12 +30,9 @@ public class RenjuDoubleFourDetector: ForbiddenDetectorBase /// private bool CheckDoubleFour(Enums.PlayerType[,] board, int row, int col) { - // 각각 두개의 라인에서 쌍사를 형성하는 경우 - if (FindDoubleLineFour(board, row, col)) return true; - - // true : 일직선으로 쌍사가 만들어지는 특수 패턴 // false : 모든 경우에도 쌍사가 만들어지지 않음 - return FindSingleLineDoubleFour(board, row, col); + return FindDoubleLineFour(board, row, col) || // 각각 두개의 라인에서 쌍사를 형성하는 경우 + FindSingleLineDoubleFour(board, row, col); // 일직선으로 쌍사가 만들어지는 특수 패턴 } private bool FindDoubleLineFour(Enums.PlayerType[,] board, int row, int col) diff --git a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs index 327eb39..02c0ee1 100644 --- a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs +++ b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs @@ -119,19 +119,9 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase /// private bool CheckForOpenThree(Enums.PlayerType[] linePattern, int centerIndex) { - // 연속된 열린 3 확인 - if (CheckConsecutiveOpenThree(linePattern, centerIndex)) - { - return true; - } - - // 한 칸 떨어진 열린 3 확인 - if (CheckGappedOpenThree(linePattern, centerIndex)) - { - return true; - } - - return false; + // 둘다 아니면 열린 3이 아님 + return CheckConsecutiveOpenThree(linePattern, centerIndex) || // 연속된 열린 3 확인 + CheckGappedOpenThree(linePattern, centerIndex); // 한 칸 떨어진 열린 3 확인 } /// diff --git a/Assets/Trash Can_JY/Renju.unity b/Assets/Trash Can_JY/Renju.unity index d70b9a6..1a49ad8 100644 --- a/Assets/Trash Can_JY/Renju.unity +++ b/Assets/Trash Can_JY/Renju.unity @@ -306,7 +306,7 @@ PrefabInstance: m_Modifications: - target: {fileID: 626368541760032086, guid: 65aac0e22fe25aa42b9cf7df776a854d, type: 3} propertyPath: m_Name - value: '[Canvas] Game UI' + value: Canvas objectReference: {fileID: 0} - target: {fileID: 6113787613246818512, guid: 65aac0e22fe25aa42b9cf7df776a854d, type: 3} propertyPath: m_Pivot.x @@ -21706,6 +21706,7 @@ GameObject: m_Component: - component: {fileID: 1260188604546925059} - component: {fileID: 5677811662396631252} + - component: {fileID: 5677811662396631253} m_Layer: 0 m_Name: GameManager m_TagString: Untagged @@ -33884,10 +33885,104 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 35a4c6d5d3a97b444b968e68ec8bb9f7, type: 3} m_Name: m_EditorClassIdentifier: - signinPanel: {fileID: 0} - signupPanel: {fileID: 0} - canvas: {fileID: 0} - profileSprites: [] + panelManagerPrefab: {fileID: 3475740041361426276, guid: 085ca07ca90c92545b2594bd13412701, type: 3} + audioManagerPrefab: {fileID: 2946408323859178723, guid: e829818dce39a5d4383e061111bed871, type: 3} +--- !u!82 &5677811662396631253 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3626119060319719757} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 0} + m_PlayOnAwake: 1 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 --- !u!61 &5684907091474785187 BoxCollider2D: m_ObjectHideFlags: 0 From 99b7f705ea4c8a0dfe266ae086afbbdc8f5d280b Mon Sep 17 00:00:00 2001 From: fiore Date: Thu, 20 Mar 2025 01:07:55 +0900 Subject: [PATCH 06/10] =?UTF-8?q?DO-31=20Fix=20:=20=EA=B1=B0=EC=A7=93=20?= =?UTF-8?q?=EA=B8=88=EC=88=98=20=ED=83=90=EC=A7=80=20=EB=B6=88=EA=B0=80=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 거짓금수가 나올 수 있는 금수는 쌍삼 뿐임 - 쌍삼이 감지된 경우 한 수를 더 내다 보고 금수로 막히는 경우 쌍삼아님 --- .../Renju/RenjuForbiddenMoveDetector.cs | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs index fce9c13..8fe5421 100644 --- a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs +++ b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs @@ -18,6 +18,7 @@ public class RenjuForbiddenMoveDetector : ForbiddenDetectorBase { var tempBoard = (Enums.PlayerType[,])board.Clone(); + var forbiddenCount = 0; List forbiddenMoves = new(); for (int row = 0; row < BoardSize; row++) { @@ -29,6 +30,7 @@ public class RenjuForbiddenMoveDetector : ForbiddenDetectorBase // 장목 검사 if (_overlineDetactor.IsOverline(tempBoard, row, col)) { + forbiddenCount++; Debug.Log("장목 금수 좌표 X축 : " + row + ", Y축 : " + col); forbiddenMoves.Add(new Vector2Int(row, col)); continue; @@ -37,20 +39,46 @@ public class RenjuForbiddenMoveDetector : ForbiddenDetectorBase // 4-4 검사 if (_doubleFourDetactor.IsDoubleFour(tempBoard, row, col)) { + forbiddenCount++; Debug.Log("사사 금수 좌표 X축 : " + row + ", Y축 : " + col); forbiddenMoves.Add(new Vector2Int(row, col)); continue; } + if(forbiddenCount >1) continue; + // 3-3 검사 if (_doubleThreeDetector.IsDoubleThree(tempBoard, row, col)) { - Debug.Log("삼삼 금수 좌표 X축 : " + row + ", Y축 : " + col); - forbiddenMoves.Add(new Vector2Int(row, col)); + if (CheckFakeForbiddenMove(tempBoard, row, col)) + { + Debug.Log("삼삼 금수 좌표 X축 : " + row + ", Y축 : " + col); + forbiddenMoves.Add(new Vector2Int(row, col)); + } + } } } return forbiddenMoves; } + + private bool CheckFakeForbiddenMove(Enums.PlayerType[,] board, int row, int col) + { + var tempBoard = (Enums.PlayerType[,])board.Clone(); + tempBoard[row, col] = Black; + + for (int newRow = 0; newRow < BoardSize; newRow++) + { + for (int newCol = 0; newCol < BoardSize; newCol++) + { + // ** 비어 있지 않으면 검사할 필요 없음 ** + if (!IsEmptyPosition(tempBoard, newRow, newCol)) continue; + + return _overlineDetactor.IsOverline(tempBoard, newRow, newCol) || + _doubleFourDetactor.IsDoubleFour(tempBoard, newRow, newCol); + } + } + return false; + } } \ No newline at end of file From d5fdd72ce816a3675b9556ff5e85d026a55a9936 Mon Sep 17 00:00:00 2001 From: fiore Date: Thu, 20 Mar 2025 15:09:06 +0900 Subject: [PATCH 07/10] =?UTF-8?q?DO-31=20Debug:=20=EA=B8=88=EC=88=98=20?= =?UTF-8?q?=EB=B0=98=ED=99=98=20=EB=AC=B8=EC=A0=9C=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Script/Renju/RenjuDoubleFourDetector.cs | 6 +- .../Renju/RenjuDoubleFourDetector.cs.meta | 14 ++- .../Script/Renju/RenjuDoubleThreeDetector.cs | 9 +- .../Renju/RenjuForbiddenMoveDetector.cs | 100 +++++++++++++----- .../Renju/RenjuForbiddenMoveDetector.cs.meta | 14 ++- 5 files changed, 108 insertions(+), 35 deletions(-) diff --git a/Assets/Script/Renju/RenjuDoubleFourDetector.cs b/Assets/Script/Renju/RenjuDoubleFourDetector.cs index 9f38dce..43a3ad3 100644 --- a/Assets/Script/Renju/RenjuDoubleFourDetector.cs +++ b/Assets/Script/Renju/RenjuDoubleFourDetector.cs @@ -133,7 +133,7 @@ public class RenjuDoubleFourDetector: ForbiddenDetectorBase } else { - linePattern[centerIndex + i] = Space; // 범위 밖은 빈칸으로 처리 + linePattern[centerIndex + i] = White; // 범위 밖은 백돌로 처리 } } @@ -149,7 +149,7 @@ public class RenjuDoubleFourDetector: ForbiddenDetectorBase } else { - linePattern[centerIndex - i] = Space; // 범위 밖은 빈칸으로 처리 + linePattern[centerIndex - i] = White; // 범위 밖은 백돌로 처리 } } @@ -178,7 +178,7 @@ public class RenjuDoubleFourDetector: ForbiddenDetectorBase } } - // 정확히 4개의 돌이 있고, 1개의 빈칸이 있으면 4로 판정 + // 4개의 돌이 있고, 1개의 빈칸이 있으면 4로 판정 // (현재 위치는 흑으로 이미 설정되어 있음) if (stoneCount == 4) { diff --git a/Assets/Script/Renju/RenjuDoubleFourDetector.cs.meta b/Assets/Script/Renju/RenjuDoubleFourDetector.cs.meta index abc7cef..54a3220 100644 --- a/Assets/Script/Renju/RenjuDoubleFourDetector.cs.meta +++ b/Assets/Script/Renju/RenjuDoubleFourDetector.cs.meta @@ -1,3 +1,11 @@ -fileFormatVersion: 2 -guid: 0daf1f2b8cbe4b19adc0e42db7a15991 -timeCreated: 1742270734 \ No newline at end of file +fileFormatVersion: 2 +guid: f997e95272e950240a6e9e2f8a99fdfa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs index 02c0ee1..5a7b5d1 100644 --- a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs +++ b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs @@ -18,13 +18,13 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase // 쌍삼 검사 bool isDoubleThree = CheckDoubleThree(board, row, col); - // 쌍삼으로 판정된 경우 4-3 상황인지 추가 검사 + // 쌍삼으로 판정된 경우 if (isDoubleThree) { // 4가 만들어지는지 확인 bool hasFour = CheckForFour(board, row, col); - // 4-3 상황이면 금수에서 제외 + // 4-3 상황 if (hasFour) { isDoubleThree = false; @@ -37,6 +37,8 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase return isDoubleThree; } + + /// /// 쌍삼(3-3) 여부를 검사합니다. /// @@ -56,6 +58,7 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase openThreeCount++; // 이미 열린 3이 2개 이상 발견되면 쌍삼으로 판정 + // TODO : 44를 만들 수 있는가?? if (openThreeCount >= 2) { return true; @@ -119,9 +122,11 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase /// private bool CheckForOpenThree(Enums.PlayerType[] linePattern, int centerIndex) { + // 둘다 아니면 열린 3이 아님 return CheckConsecutiveOpenThree(linePattern, centerIndex) || // 연속된 열린 3 확인 CheckGappedOpenThree(linePattern, centerIndex); // 한 칸 떨어진 열린 3 확인 + // TODO : 한칸 떨어진 열린 3, 여기서 장목이 되는지 체크해서 배제 해야함 } /// diff --git a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs index 8fe5421..995bc9b 100644 --- a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs +++ b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text; using UnityEngine; @@ -16,19 +17,19 @@ public class RenjuForbiddenMoveDetector : ForbiddenDetectorBase /// 금수 좌표를 담은 리스트 public List RenjuForbiddenMove(Enums.PlayerType[,] board) { - var tempBoard = (Enums.PlayerType[,])board.Clone(); var forbiddenCount = 0; List forbiddenMoves = new(); + List tempForbiddenMoves = new(); for (int row = 0; row < BoardSize; row++) { for (int col = 0; col < BoardSize; col++) { // ** 비어 있지 않으면 검사할 필요 없음 ** - if (!IsEmptyPosition(tempBoard, row, col)) continue; + if (!IsEmptyPosition(board, row, col)) continue; // 장목 검사 - if (_overlineDetactor.IsOverline(tempBoard, row, col)) + if (_overlineDetactor.IsOverline(board, row, col)) { forbiddenCount++; Debug.Log("장목 금수 좌표 X축 : " + row + ", Y축 : " + col); @@ -37,7 +38,7 @@ public class RenjuForbiddenMoveDetector : ForbiddenDetectorBase } // 4-4 검사 - if (_doubleFourDetactor.IsDoubleFour(tempBoard, row, col)) + if (_doubleFourDetactor.IsDoubleFour(board, row, col)) { forbiddenCount++; Debug.Log("사사 금수 좌표 X축 : " + row + ", Y축 : " + col); @@ -45,40 +46,91 @@ public class RenjuForbiddenMoveDetector : ForbiddenDetectorBase continue; } - if(forbiddenCount >1) continue; + if(forbiddenCount > 0) continue; // 3-3 검사 - if (_doubleThreeDetector.IsDoubleThree(tempBoard, row, col)) + if (_doubleThreeDetector.IsDoubleThree(board, row, col)) { - if (CheckFakeForbiddenMove(tempBoard, row, col)) - { - Debug.Log("삼삼 금수 좌표 X축 : " + row + ", Y축 : " + col); - forbiddenMoves.Add(new Vector2Int(row, col)); - } - + tempForbiddenMoves.Add(new Vector2Int(row, col)); + // if (!SimulateDoubleFour(tempBoard)) + // { + // Debug.Log("삼삼 금수 좌표 X축 : " + row + ", Y축 : " + col); + // forbiddenMoves.Add(new Vector2Int(row, col)); + // } } } } + foreach (var pos in tempForbiddenMoves) + { + board[pos.x, pos.y] = Black; + if (!SimulateDoubleFour(board)&& !SimulateOverline(board)) + { + Debug.Log("X: "+pos.x + "Y: "+ pos.y); + forbiddenMoves.Add(new Vector2Int(pos.x, pos.y)); + } + } + + + Debug.Log(DebugBoard(board)); return forbiddenMoves; } - private bool CheckFakeForbiddenMove(Enums.PlayerType[,] board, int row, int col) + + + private bool SimulateDoubleFour(Enums.PlayerType[,] board) { - var tempBoard = (Enums.PlayerType[,])board.Clone(); - tempBoard[row, col] = Black; - - for (int newRow = 0; newRow < BoardSize; newRow++) + for (int row = 0; row < BoardSize; row++) { - for (int newCol = 0; newCol < BoardSize; newCol++) + for (int col = 0; col < BoardSize; col++) { - // ** 비어 있지 않으면 검사할 필요 없음 ** - if (!IsEmptyPosition(tempBoard, newRow, newCol)) continue; - - return _overlineDetactor.IsOverline(tempBoard, newRow, newCol) || - _doubleFourDetactor.IsDoubleFour(tempBoard, newRow, newCol); + if (_doubleFourDetactor.IsDoubleFour(board, row, col)) + return true; } } return false; } -} \ No newline at end of file + + private bool SimulateOverline(Enums.PlayerType[,] board) + { + for (int row = 0; row < BoardSize; row++) + { + for (int col = 0; col < BoardSize; col++) + { + if (_overlineDetactor.IsOverline(board, row, col)) + { + return true; + } + } + } + return false; + } + + /// + /// 보드 상태를 시각적으로 출력하는 디버깅 함수 + /// + /// 현재 보드 상태 + /// 보드의 시각적 표현 문자열 + private string DebugBoard(Enums.PlayerType[,] board) + { + StringBuilder sb = new StringBuilder(); + + for (int row = 0; row < BoardSize; row++) + { + for (int col = 0; col < BoardSize; col++) + { + sb.Append(board[row, col] switch + { + Enums.PlayerType.None => "□", + Enums.PlayerType.PlayerA => "●", + Enums.PlayerType.PlayerB => "○", + _ => "?" + }); + } + sb.AppendLine(); // 줄바꿈 추가 + } + + return sb.ToString(); + } +} + diff --git a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs.meta b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs.meta index 511a9bd..05a239d 100644 --- a/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs.meta +++ b/Assets/Script/Renju/RenjuForbiddenMoveDetector.cs.meta @@ -1,3 +1,11 @@ -fileFormatVersion: 2 -guid: 8618553c3e244abdb040fb7378dd4b65 -timeCreated: 1741939566 \ No newline at end of file +fileFormatVersion: 2 +guid: 4440d621b56f2ce459d819497911892b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 9a590f18f6676899f30f167725b3f311b7acbd9d Mon Sep 17 00:00:00 2001 From: Parkillhwan Date: Thu, 20 Mar 2025 17:11:13 +0900 Subject: [PATCH 08/10] =?UTF-8?q?DO-16=20=EB=9E=AD=ED=82=B9=20=EB=B0=B1=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC,=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20=EB=B0=94?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Prefabs/Panels/LeaderboardPanel.prefab | 173 ++++++++---------- .../Prefabs/Panels/Main Panel.prefab | 2 +- .../Prefabs/Panels/Ranking Panel.prefab | 2 +- Assets/Resources/Prefabs/Ranking.prefab | 2 +- 4 files changed, 76 insertions(+), 103 deletions(-) diff --git a/Assets/Resources/Prefabs/Panels/LeaderboardPanel.prefab b/Assets/Resources/Prefabs/Panels/LeaderboardPanel.prefab index 50adf35..f23839d 100644 --- a/Assets/Resources/Prefabs/Panels/LeaderboardPanel.prefab +++ b/Assets/Resources/Prefabs/Panels/LeaderboardPanel.prefab @@ -12,8 +12,6 @@ GameObject: - component: {fileID: 2911450618660204948} - component: {fileID: 2729261171078307673} - component: {fileID: 4465141290128179683} - - component: {fileID: 2835505888941074797} - - component: {fileID: 5687316735128766768} m_Layer: 5 m_Name: Viewport m_TagString: Untagged @@ -37,7 +35,7 @@ RectTransform: m_Father: {fileID: 1188344226235047902} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} + m_AnchorMax: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 1} @@ -92,46 +90,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_ShowMaskGraphic: 1 ---- !u!114 &2835505888941074797 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1858212639388121281} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} - m_Name: - m_EditorClassIdentifier: - m_HorizontalFit: 1 - m_VerticalFit: 2 ---- !u!114 &5687316735128766768 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1858212639388121281} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Padding: - m_Left: 0 - m_Right: 0 - m_Top: 0 - m_Bottom: 0 - m_ChildAlignment: 0 - m_Spacing: 5 - m_ChildForceExpandWidth: 1 - m_ChildForceExpandHeight: 1 - m_ChildControlWidth: 0 - m_ChildControlHeight: 0 - m_ChildScaleWidth: 0 - m_ChildScaleHeight: 0 - m_ReverseArrangement: 0 --- !u!1 &2602607401298266001 GameObject: m_ObjectHideFlags: 0 @@ -168,7 +126,7 @@ RectTransform: m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} m_AnchoredPosition: {x: 40, y: -40} - m_SizeDelta: {x: 36, y: 40} + m_SizeDelta: {x: 73, y: 72} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &6169341149558268219 CanvasRenderer: @@ -198,7 +156,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 427761ad91f2d9d4e85af2f6a2894218, type: 3} + m_Sprite: {fileID: 21300000, guid: 2f19224efc36c9b49978cafd03ede1bb, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -252,7 +210,7 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 0} + - m_Target: {fileID: 1589736077307570888} m_TargetAssemblyTypeName: LeaderBoardController, Assembly-CSharp m_MethodName: OnBackButtonClicked m_Mode: 1 @@ -361,14 +319,14 @@ MonoBehaviour: m_Elasticity: 0.1 m_Inertia: 1 m_DecelerationRate: 0.135 - m_ScrollSensitivity: 1 + m_ScrollSensitivity: 100 m_Viewport: {fileID: 8740302936727227434} m_HorizontalScrollbar: {fileID: 0} m_VerticalScrollbar: {fileID: 3478506922544614059} m_HorizontalScrollbarVisibility: 2 m_VerticalScrollbarVisibility: 2 m_HorizontalScrollbarSpacing: -3 - m_VerticalScrollbarSpacing: -3 + m_VerticalScrollbarSpacing: -15 m_OnValueChanged: m_PersistentCalls: m_Calls: [] @@ -523,6 +481,7 @@ GameObject: m_Component: - component: {fileID: 227489081374553986} - component: {fileID: 6416582684501908282} + - component: {fileID: 2816695216852066709} m_Layer: 5 m_Name: Content m_TagString: Untagged @@ -544,10 +503,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 8740302936727227434} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 1060, y: 1493.8} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 0, y: -0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 1} --- !u!114 &6416582684501908282 MonoBehaviour: @@ -570,11 +529,25 @@ MonoBehaviour: m_Spacing: 50 m_ChildForceExpandWidth: 1 m_ChildForceExpandHeight: 1 - m_ChildControlWidth: 1 - m_ChildControlHeight: 1 + m_ChildControlWidth: 0 + m_ChildControlHeight: 0 m_ChildScaleWidth: 0 m_ChildScaleHeight: 0 m_ReverseArrangement: 0 +--- !u!114 &2816695216852066709 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3568653418969612126} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 1 + m_VerticalFit: 2 --- !u!1 &4202334049855500581 GameObject: m_ObjectHideFlags: 0 @@ -633,7 +606,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 0, b: 0, a: 1} + m_Color: {r: 1, g: 0.2847969, b: 0, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -659,9 +632,9 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 2084150948806744478} - - component: {fileID: 7465938882283913230} - - component: {fileID: 1080045383039686757} - component: {fileID: 3478506922544614059} + - component: {fileID: 6301460630123320729} + - component: {fileID: 1849839432792571899} m_Layer: 5 m_Name: Scrollbar Vertical m_TagString: Untagged @@ -687,46 +660,8 @@ RectTransform: m_AnchorMin: {x: 1, y: 0} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 20, y: -17} + m_SizeDelta: {x: 20, y: 0} m_Pivot: {x: 1, y: 1} ---- !u!222 &7465938882283913230 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5452094549188284008} - m_CullTransparentMesh: 1 ---- !u!114 &1080045383039686757 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5452094549188284008} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 0, b: 0, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 --- !u!114 &3478506922544614059 MonoBehaviour: m_ObjectHideFlags: 0 @@ -748,10 +683,10 @@ MonoBehaviour: m_SelectOnRight: {fileID: 0} m_Transition: 1 m_Colors: - m_NormalColor: {r: 1, g: 0.55039775, b: 0, a: 1} + m_NormalColor: {r: 1, g: 0.28627452, b: 0, a: 1} m_HighlightedColor: {r: 1, g: 0, b: 0, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.93710685, g: 0.33299702, b: 0.33299702, a: 1} + m_SelectedColor: {r: 0.8409424, g: 0.9685534, b: 0.57564956, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} m_ColorMultiplier: 1 m_FadeDuration: 0.1 @@ -776,6 +711,44 @@ MonoBehaviour: m_OnValueChanged: m_PersistentCalls: m_Calls: [] +--- !u!222 &6301460630123320729 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5452094549188284008} + m_CullTransparentMesh: 1 +--- !u!114 &1849839432792571899 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5452094549188284008} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.59607846} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 --- !u!1 &6747908716986530392 GameObject: m_ObjectHideFlags: 0 @@ -810,7 +783,7 @@ RectTransform: m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: -20, y: -20} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &7787380462476439032 GameObject: diff --git a/Assets/Resources/Prefabs/Panels/Main Panel.prefab b/Assets/Resources/Prefabs/Panels/Main Panel.prefab index 9a6246d..da3a302 100644 --- a/Assets/Resources/Prefabs/Panels/Main Panel.prefab +++ b/Assets/Resources/Prefabs/Panels/Main Panel.prefab @@ -1714,7 +1714,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: "\uBC15\uC77C\uD658" + m_text: name m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 85a19688db53c77469fc4406b01045da, type: 2} m_sharedMaterial: {fileID: -2477908578676791210, guid: 85a19688db53c77469fc4406b01045da, type: 2} diff --git a/Assets/Resources/Prefabs/Panels/Ranking Panel.prefab b/Assets/Resources/Prefabs/Panels/Ranking Panel.prefab index 06a872f..df9733e 100644 --- a/Assets/Resources/Prefabs/Panels/Ranking Panel.prefab +++ b/Assets/Resources/Prefabs/Panels/Ranking Panel.prefab @@ -545,7 +545,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0} m_AnchorMax: {x: 0.5, y: 1} - m_AnchoredPosition: {x: -392, y: -2.9951172} + m_AnchoredPosition: {x: -392, y: -0.6867676} m_SizeDelta: {x: 784, y: 0} m_Pivot: {x: 0, y: 1} --- !u!114 &5526954107552917871 diff --git a/Assets/Resources/Prefabs/Ranking.prefab b/Assets/Resources/Prefabs/Ranking.prefab index fc24199..38a4ab3 100644 --- a/Assets/Resources/Prefabs/Ranking.prefab +++ b/Assets/Resources/Prefabs/Ranking.prefab @@ -1185,7 +1185,7 @@ MonoBehaviour: m_Right: 0 m_Top: 30 m_Bottom: 35 - m_ChildAlignment: 0 + m_ChildAlignment: 3 m_Spacing: 0 m_ChildForceExpandWidth: 1 m_ChildForceExpandHeight: 1 From 1d4fdfab23d5c103ff200d54d1831ab0f68606d6 Mon Sep 17 00:00:00 2001 From: Parkillhwan Date: Thu, 20 Mar 2025 17:41:22 +0900 Subject: [PATCH 09/10] =?UTF-8?q?Revert=20"DO-16=20=EB=9E=AD=ED=82=B9=20?= =?UTF-8?q?=EB=B0=B1=20=EB=B2=84=ED=8A=BC,=20=EC=8A=A4=ED=81=AC=EB=A1=A4?= =?UTF-8?q?=20=EB=B0=94=20=EC=B6=94=EA=B0=80"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 9a590f18f6676899f30f167725b3f311b7acbd9d. --- .../Prefabs/Panels/LeaderboardPanel.prefab | 173 ++++++++++-------- .../Prefabs/Panels/Main Panel.prefab | 2 +- .../Prefabs/Panels/Ranking Panel.prefab | 2 +- Assets/Resources/Prefabs/Ranking.prefab | 2 +- 4 files changed, 103 insertions(+), 76 deletions(-) diff --git a/Assets/Resources/Prefabs/Panels/LeaderboardPanel.prefab b/Assets/Resources/Prefabs/Panels/LeaderboardPanel.prefab index f23839d..50adf35 100644 --- a/Assets/Resources/Prefabs/Panels/LeaderboardPanel.prefab +++ b/Assets/Resources/Prefabs/Panels/LeaderboardPanel.prefab @@ -12,6 +12,8 @@ GameObject: - component: {fileID: 2911450618660204948} - component: {fileID: 2729261171078307673} - component: {fileID: 4465141290128179683} + - component: {fileID: 2835505888941074797} + - component: {fileID: 5687316735128766768} m_Layer: 5 m_Name: Viewport m_TagString: Untagged @@ -35,7 +37,7 @@ RectTransform: m_Father: {fileID: 1188344226235047902} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0, y: 1} @@ -90,6 +92,46 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_ShowMaskGraphic: 1 +--- !u!114 &2835505888941074797 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1858212639388121281} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 1 + m_VerticalFit: 2 +--- !u!114 &5687316735128766768 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1858212639388121281} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 0 + m_Spacing: 5 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 0 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 + m_ReverseArrangement: 0 --- !u!1 &2602607401298266001 GameObject: m_ObjectHideFlags: 0 @@ -126,7 +168,7 @@ RectTransform: m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} m_AnchoredPosition: {x: 40, y: -40} - m_SizeDelta: {x: 73, y: 72} + m_SizeDelta: {x: 36, y: 40} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &6169341149558268219 CanvasRenderer: @@ -156,7 +198,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 2f19224efc36c9b49978cafd03ede1bb, type: 3} + m_Sprite: {fileID: 21300000, guid: 427761ad91f2d9d4e85af2f6a2894218, type: 3} m_Type: 0 m_PreserveAspect: 0 m_FillCenter: 1 @@ -210,7 +252,7 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 1589736077307570888} + - m_Target: {fileID: 0} m_TargetAssemblyTypeName: LeaderBoardController, Assembly-CSharp m_MethodName: OnBackButtonClicked m_Mode: 1 @@ -319,14 +361,14 @@ MonoBehaviour: m_Elasticity: 0.1 m_Inertia: 1 m_DecelerationRate: 0.135 - m_ScrollSensitivity: 100 + m_ScrollSensitivity: 1 m_Viewport: {fileID: 8740302936727227434} m_HorizontalScrollbar: {fileID: 0} m_VerticalScrollbar: {fileID: 3478506922544614059} m_HorizontalScrollbarVisibility: 2 m_VerticalScrollbarVisibility: 2 m_HorizontalScrollbarSpacing: -3 - m_VerticalScrollbarSpacing: -15 + m_VerticalScrollbarSpacing: -3 m_OnValueChanged: m_PersistentCalls: m_Calls: [] @@ -481,7 +523,6 @@ GameObject: m_Component: - component: {fileID: 227489081374553986} - component: {fileID: 6416582684501908282} - - component: {fileID: 2816695216852066709} m_Layer: 5 m_Name: Content m_TagString: Untagged @@ -503,10 +544,10 @@ RectTransform: m_Children: [] m_Father: {fileID: 8740302936727227434} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 0, y: -0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 1060, y: 1493.8} m_Pivot: {x: 0, y: 1} --- !u!114 &6416582684501908282 MonoBehaviour: @@ -529,25 +570,11 @@ MonoBehaviour: m_Spacing: 50 m_ChildForceExpandWidth: 1 m_ChildForceExpandHeight: 1 - m_ChildControlWidth: 0 - m_ChildControlHeight: 0 + m_ChildControlWidth: 1 + m_ChildControlHeight: 1 m_ChildScaleWidth: 0 m_ChildScaleHeight: 0 m_ReverseArrangement: 0 ---- !u!114 &2816695216852066709 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 3568653418969612126} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} - m_Name: - m_EditorClassIdentifier: - m_HorizontalFit: 1 - m_VerticalFit: 2 --- !u!1 &4202334049855500581 GameObject: m_ObjectHideFlags: 0 @@ -606,7 +633,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} - m_Color: {r: 1, g: 0.2847969, b: 0, a: 1} + m_Color: {r: 1, g: 0, b: 0, a: 1} m_RaycastTarget: 1 m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 @@ -632,9 +659,9 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 2084150948806744478} + - component: {fileID: 7465938882283913230} + - component: {fileID: 1080045383039686757} - component: {fileID: 3478506922544614059} - - component: {fileID: 6301460630123320729} - - component: {fileID: 1849839432792571899} m_Layer: 5 m_Name: Scrollbar Vertical m_TagString: Untagged @@ -660,8 +687,46 @@ RectTransform: m_AnchorMin: {x: 1, y: 0} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 20, y: 0} + m_SizeDelta: {x: 20, y: -17} m_Pivot: {x: 1, y: 1} +--- !u!222 &7465938882283913230 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5452094549188284008} + m_CullTransparentMesh: 1 +--- !u!114 &1080045383039686757 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5452094549188284008} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 --- !u!114 &3478506922544614059 MonoBehaviour: m_ObjectHideFlags: 0 @@ -683,10 +748,10 @@ MonoBehaviour: m_SelectOnRight: {fileID: 0} m_Transition: 1 m_Colors: - m_NormalColor: {r: 1, g: 0.28627452, b: 0, a: 1} + m_NormalColor: {r: 1, g: 0.55039775, b: 0, a: 1} m_HighlightedColor: {r: 1, g: 0, b: 0, a: 1} - m_PressedColor: {r: 0.93710685, g: 0.33299702, b: 0.33299702, a: 1} - m_SelectedColor: {r: 0.8409424, g: 0.9685534, b: 0.57564956, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} m_ColorMultiplier: 1 m_FadeDuration: 0.1 @@ -711,44 +776,6 @@ MonoBehaviour: m_OnValueChanged: m_PersistentCalls: m_Calls: [] ---- !u!222 &6301460630123320729 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5452094549188284008} - m_CullTransparentMesh: 1 ---- !u!114 &1849839432792571899 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5452094549188284008} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 0.59607846} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 --- !u!1 &6747908716986530392 GameObject: m_ObjectHideFlags: 0 @@ -783,7 +810,7 @@ RectTransform: m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_SizeDelta: {x: -20, y: -20} m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &7787380462476439032 GameObject: diff --git a/Assets/Resources/Prefabs/Panels/Main Panel.prefab b/Assets/Resources/Prefabs/Panels/Main Panel.prefab index da3a302..9a6246d 100644 --- a/Assets/Resources/Prefabs/Panels/Main Panel.prefab +++ b/Assets/Resources/Prefabs/Panels/Main Panel.prefab @@ -1714,7 +1714,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: name + m_text: "\uBC15\uC77C\uD658" m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 85a19688db53c77469fc4406b01045da, type: 2} m_sharedMaterial: {fileID: -2477908578676791210, guid: 85a19688db53c77469fc4406b01045da, type: 2} diff --git a/Assets/Resources/Prefabs/Panels/Ranking Panel.prefab b/Assets/Resources/Prefabs/Panels/Ranking Panel.prefab index df9733e..06a872f 100644 --- a/Assets/Resources/Prefabs/Panels/Ranking Panel.prefab +++ b/Assets/Resources/Prefabs/Panels/Ranking Panel.prefab @@ -545,7 +545,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0} m_AnchorMax: {x: 0.5, y: 1} - m_AnchoredPosition: {x: -392, y: -0.6867676} + m_AnchoredPosition: {x: -392, y: -2.9951172} m_SizeDelta: {x: 784, y: 0} m_Pivot: {x: 0, y: 1} --- !u!114 &5526954107552917871 diff --git a/Assets/Resources/Prefabs/Ranking.prefab b/Assets/Resources/Prefabs/Ranking.prefab index 38a4ab3..fc24199 100644 --- a/Assets/Resources/Prefabs/Ranking.prefab +++ b/Assets/Resources/Prefabs/Ranking.prefab @@ -1185,7 +1185,7 @@ MonoBehaviour: m_Right: 0 m_Top: 30 m_Bottom: 35 - m_ChildAlignment: 3 + m_ChildAlignment: 0 m_Spacing: 0 m_ChildForceExpandWidth: 1 m_ChildForceExpandHeight: 1 From 53f6978f8ba4bb15529336527bf5949ecff288fd Mon Sep 17 00:00:00 2001 From: fiore Date: Fri, 21 Mar 2025 09:35:00 +0900 Subject: [PATCH 10/10] =?UTF-8?q?DO-31=20fix=20:=20=EC=8C=8D=EC=82=BC=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=82=AC=ED=95=AD=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Script/Renju/RenjuDoubleThreeDetector.cs | 563 +++++++++++++----- Assets/Trash Can_JY/Renju.unity | 4 + 2 files changed, 411 insertions(+), 156 deletions(-) diff --git a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs index 5a7b5d1..1befe0d 100644 --- a/Assets/Script/Renju/RenjuDoubleThreeDetector.cs +++ b/Assets/Script/Renju/RenjuDoubleThreeDetector.cs @@ -1,8 +1,25 @@ using System.Collections.Generic; using UnityEngine; -public class RenjuDoubleThreeDetector: ForbiddenDetectorBase +/// +/// 렌주 쌍삼(3-3) 금수 판정을 위한 개선된 클래스 +/// 렌주 국제 규칙 9.3에 따라 쌍삼의 예외 상황까지 정확히 판별 +/// +public class RenjuDoubleThreeDetector : ForbiddenDetectorBase { + // 열린 3 패턴 정보를 저장하는 구조체 + private struct OpenThreeInfo + { + public int direction; // 방향 인덱스 + public List emptyPositions; // 빈 좌표들 (4를 만들 수 있는 위치) + + public OpenThreeInfo(int dir) + { + direction = dir; + emptyPositions = new List(); + } + } + /// /// 쌍삼(3-3) 여부를 검사합니다. /// @@ -15,36 +32,26 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase // 임시로 돌 배치 board[row, col] = Black; - // 쌍삼 검사 - bool isDoubleThree = CheckDoubleThree(board, row, col); - - // 쌍삼으로 판정된 경우 - if (isDoubleThree) - { - // 4가 만들어지는지 확인 - bool hasFour = CheckForFour(board, row, col); - - // 4-3 상황 - if (hasFour) - { - isDoubleThree = false; - } - } + // 쌍삼 기본 검사 (열린 3이 2개 이상인지) + List openThrees = FindAllOpenThrees(board, row, col); // 원래 상태로 되돌림 board[row, col] = Space; - return isDoubleThree; + // 열린 3이 2개 미만이면 쌍삼이 아님 + if (openThrees.Count < 2) + return false; + + // 렌주 규칙 9.3에 따른 예외 케이스 확인 + return !CheckDoubleThreeExceptions(board, row, col, openThrees); } - - /// - /// 쌍삼(3-3) 여부를 검사합니다. + /// 모든 방향에서 열린 3을 찾아 반환합니다. /// - private bool CheckDoubleThree(Enums.PlayerType[,] board, int row, int col) + private List FindAllOpenThrees(Enums.PlayerType[,] board, int row, int col) { - int openThreeCount = 0; + List openThrees = new List(); // 4개의 방향 쌍에 대해 검사 (대각선 및 직선 포함) for (int i = 0; i < 4; i++) @@ -52,29 +59,42 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase int dir1 = DirectionPairs[i, 0]; int dir2 = DirectionPairs[i, 1]; - // 해당 방향에서 열린 3의 개수 계산 - if (CheckOpenThreeInDirection(board, row, col, dir1, dir2)) + // 열린 3 정보 획득 + OpenThreeInfo threeInfo = new OpenThreeInfo(i); + if (FindOpenThreeInDirection(board, row, col, dir1, dir2, ref threeInfo)) { - openThreeCount++; - - // 이미 열린 3이 2개 이상 발견되면 쌍삼으로 판정 - // TODO : 44를 만들 수 있는가?? - if (openThreeCount >= 2) - { - return true; - } + openThrees.Add(threeInfo); } } + return openThrees; + } + + /// + /// 특정 방향에서 열린 3을 찾고 관련 정보를 채웁니다. + /// + private bool FindOpenThreeInDirection(Enums.PlayerType[,] board, int row, int col, int dir1, int dir2, ref OpenThreeInfo threeInfo) + { + // 라인 패턴 추출 + Enums.PlayerType[] linePattern = ExtractLinePattern(board, row, col, dir1, dir2); + int centerIndex = 5; // 중앙 인덱스 (현재 위치) + + // 연속된 열린 3 또는 한 칸 떨어진 열린 3 확인 + if (FindConsecutiveOpenThree(linePattern, centerIndex, ref threeInfo, row, col, dir1, dir2) || + FindGappedOpenThree(linePattern, centerIndex, ref threeInfo, row, col, dir1, dir2)) + { + // 열린 3이 발견됨 + return true; + } + return false; } /// - /// 특정 방향에서 열린 3이 형성되는지 확인합니다. + /// 라인 패턴을 추출합니다. /// - private bool CheckOpenThreeInDirection(Enums.PlayerType[,] board, int row, int col, int dir1, int dir2) + private Enums.PlayerType[] ExtractLinePattern(Enums.PlayerType[,] board, int row, int col, int dir1, int dir2) { - // 각 방향으로 최대 5칸까지의 범위를 검사 (현재 위치 포함 총 11칸) Enums.PlayerType[] linePattern = new Enums.PlayerType[11]; int centerIndex = 5; // 중앙 인덱스 (현재 위치) @@ -93,7 +113,7 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase } else { - linePattern[centerIndex + i] = White; // 범위 밖은 막힌 것으로 처리 + linePattern[centerIndex + i] = White; // 범위 밖은 벽으로 처리하여 일관성 유지 } } @@ -109,33 +129,19 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase } else { - linePattern[centerIndex - i] = White; // 범위 밖은 막힌 것으로 처리 + linePattern[centerIndex - i] = White; // 범위 밖은 벽으로 처리하여 일관성 유지 } } - // 열린 3 패턴 확인 - return CheckForOpenThree(linePattern, centerIndex); + return linePattern; } /// - /// 라인 패턴에서 열린 3 패턴을 확인합니다. + /// 연속된 열린 3 패턴을 찾고 관련 정보를 채웁니다. /// - private bool CheckForOpenThree(Enums.PlayerType[] linePattern, int centerIndex) + private bool FindConsecutiveOpenThree(Enums.PlayerType[] linePattern, int centerIndex, ref OpenThreeInfo threeInfo, int row, int col, int dir1, int dir2) { - - // 둘다 아니면 열린 3이 아님 - return CheckConsecutiveOpenThree(linePattern, centerIndex) || // 연속된 열린 3 확인 - CheckGappedOpenThree(linePattern, centerIndex); // 한 칸 떨어진 열린 3 확인 - // TODO : 한칸 떨어진 열린 3, 여기서 장목이 되는지 체크해서 배제 해야함 - } - - /// - /// 연속된 열린 3 패턴을 확인합니다. - /// - private bool CheckConsecutiveOpenThree(Enums.PlayerType[] linePattern, int centerIndex) - { - // 연속된 3개의 돌 패턴 - // 시작 인덱스를 조정하여 센터가 패턴 내에 있는지 확인 + // 연속된 3개의 돌 패턴 (●●●) for (int start = centerIndex - 2; start <= centerIndex; start++) { // 범위 체크 @@ -170,6 +176,27 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase if (isExtendedLeftOpen && isExtendedRightOpen) { + // 4를 만들 수 있는 위치 저장 + if (isLeftOpen) + { + int leftRow = row + Directions[dir2, 0] * (centerIndex - (start - 1)); + int leftCol = col + Directions[dir2, 1] * (centerIndex - (start - 1)); + if (IsInBounds(leftRow, leftCol)) + { + threeInfo.emptyPositions.Add(new Vector2Int(leftCol, leftRow)); + } + } + + if (isRightOpen) + { + int rightRow = row + Directions[dir1, 0] * ((start + 3) - centerIndex); + int rightCol = col + Directions[dir1, 1] * ((start + 3) - centerIndex); + if (IsInBounds(rightRow, rightCol)) + { + threeInfo.emptyPositions.Add(new Vector2Int(rightCol, rightRow)); + } + } + return true; } } @@ -180,15 +207,11 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase } /// - /// 한 칸 떨어진 열린 3 패턴을 확인합니다. + /// 한 칸 떨어진 열린 3 패턴을 찾고 관련 정보를 채웁니다. /// - private bool CheckGappedOpenThree(Enums.PlayerType[] linePattern, int centerIndex) + private bool FindGappedOpenThree(Enums.PlayerType[] linePattern, int centerIndex, ref OpenThreeInfo threeInfo, int row, int col, int dir1, int dir2) { - // 한 칸 떨어진 패턴 확인 - // 패턴 1: ●●○● (centerIndex가 어느 위치든 가능) - // 패턴 2: ●○●● (centerIndex가 어느 위치든 가능) - - // 윈도우 크기 4로 슬라이딩하면서 검사 + // 한 칸 떨어진 패턴 확인 (●●○● 또는 ●○●●) for (int start = Mathf.Max(0, centerIndex - 3); start <= Mathf.Min(linePattern.Length - 4, centerIndex); start++) { // 패턴 내에 돌과 빈칸 개수 확인 @@ -218,10 +241,46 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase // 3개의 돌과 1개의 빈칸으로 구성된 패턴 if (stoneCount == 3 && gapCount == 1) { - // 빈칸에 돌을 놓았을 때 열린 4가 되는지 확인 - if (CheckIfCreatesOpenFour(linePattern, gapPosition)) + // 양쪽이 모두 열려있는지 확인 + bool isLeftOpen = (start - 1 >= 0) && (linePattern[start - 1] == Space); + bool isRightOpen = (start + 4 < linePattern.Length) && (linePattern[start + 4] == Space); + + // 한쪽이라도 열려있으면 잠재적 열린 3 + if (isLeftOpen || isRightOpen) { - return true; + // 빈칸에 돌을 놓았을 때 열린 4가 되는지 확인 + if (CheckIfCreatesOpenFour(linePattern, gapPosition)) + { + // 4를 만들 수 있는 위치 저장 (빈칸 위치) + int gapRow = row; + int gapCol = col; + + // 빈칸의 보드 좌표 계산 + int offset = gapPosition - centerIndex; + if (offset > 0) + { + gapRow += Directions[dir1, 0] * offset; + gapCol += Directions[dir1, 1] * offset; + } + else if (offset < 0) + { + gapRow += Directions[dir2, 0] * (-offset); + gapCol += Directions[dir2, 1] * (-offset); + } + + if (IsInBounds(gapRow, gapCol)) + { + threeInfo.emptyPositions.Add(new Vector2Int(gapCol, gapRow)); + } + + // 장목이 되는지 확인 (장목이 되면 열린 3이 아님) + if (CheckIfCreatesOverline(linePattern, gapPosition)) + { + return false; + } + + return true; + } } } } @@ -229,6 +288,30 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase return false; } + /// + /// 특정 방향으로 추가로 열려있는지 확인합니다. + /// + private bool IsExtendedOpen(Enums.PlayerType[] linePattern, int startPos, int direction) + { + // 한 칸 더 확장해서 확인 + int nextPos = startPos + direction; + if (nextPos >= 0 && nextPos < linePattern.Length) + { + // 다음 칸이 상대 돌이나 벽이면 확장 불가 + if (linePattern[nextPos] == White) + { + return false; + } + } + else + { + // 범위를 벗어나면 확장 불가 + return false; + } + + return true; + } + /// /// 빈칸에 돌을 놓았을 때 열린 4가 되는지 확인합니다. /// @@ -265,9 +348,9 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase bool isLeftOpen = (start - 1 >= 0) && (testPattern[start - 1] == Space); bool isRightOpen = (start + 4 < testPattern.Length) && (testPattern[start + 4] == Space); - if (isLeftOpen && isRightOpen) + if (isLeftOpen || isRightOpen) { - return true; // 열린 4가 됨 + return true; // 열린 4나 반열린 4가 됨 } } } @@ -276,42 +359,140 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase } /// - /// 특정 방향으로 추가로 열려있는지 확인합니다. + /// 빈칸에 돌을 놓았을 때 장목(6목 이상)이 되는지 확인합니다. /// - private bool IsExtendedOpen(Enums.PlayerType[] linePattern, int startPos, int direction) + private bool CheckIfCreatesOverline(Enums.PlayerType[] linePattern, int position) { - // 한 칸 더 확장해서 확인 - int nextPos = startPos + direction; - if (nextPos >= 0 && nextPos < linePattern.Length) + // 시뮬레이션: 빈칸에 돌을 놓아봄 + Enums.PlayerType[] testPattern = new Enums.PlayerType[linePattern.Length]; + System.Array.Copy(linePattern, testPattern, linePattern.Length); + testPattern[position] = Black; + + // 놓은 위치 주변의 최대 연속 돌 수 계산 + int maxLength = 1; // 놓은 돌 포함 + + // 오른쪽 방향 연속 돌 세기 + for (int i = position + 1; i < testPattern.Length && testPattern[i] == Black; i++) { - // 다음 칸이 상대 돌이나 벽이면 확장 불가 - if (linePattern[nextPos] == White) - { - return false; - } - } - else - { - // 범위를 벗어나면 확장 불가 - return false; + maxLength++; } - return true; + // 왼쪽 방향 연속 돌 세기 + for (int i = position - 1; i >= 0 && testPattern[i] == Black; i--) + { + maxLength++; + } + + // 6목 이상이면 장목 + return maxLength >= 6; } /// - /// 4가 만들어지는지 확인합니다. + /// 렌주 규칙 9.3에 따른 쌍삼 예외 케이스를 확인합니다. /// - private bool CheckForFour(Enums.PlayerType[,] board, int row, int col) + private bool CheckDoubleThreeExceptions(Enums.PlayerType[,] board, int row, int col, List openThrees) { - // 4개의 방향 쌍에 대해 검사 - for (int i = 0; i < 4; i++) - { - int dir1 = DirectionPairs[i, 0]; - int dir2 = DirectionPairs[i, 1]; + // 예외 케이스 1: 하나의 삼만 열린 사가 될 수 있는 경우 (9.3 a항) + bool canFormOpenFourWithoutDoubleFour = CheckExceptionCanFormOneFour(board, row, col, openThrees); - // 해당 방향에서 4가 형성되는지 확인 - if (CheckFourInDirection(board, row, col, dir1, dir2)) + // 예외 케이스 2: 9.3 b항 (복잡한 연쇄 체크) + bool isMeetExceptionB = CheckExceptionB(board, row, col, openThrees); + + // 어느 하나라도 예외 조건을 만족하면 쌍삼이 아님 + return canFormOpenFourWithoutDoubleFour || isMeetExceptionB; + } + + /// + /// 예외 케이스 1: 하나의 삼만 열린 사가 될 수 있고 쌍사가 형성되지 않는 경우 (9.3 a항) + /// + private bool CheckExceptionCanFormOneFour(Enums.PlayerType[,] board, int row, int col, List openThrees) + { + int canFormFourCount = 0; + + // 각 열린 3에 대해, 4를 만들 수 있는지 확인 + foreach (var threeInfo in openThrees) + { + foreach (var emptyPos in threeInfo.emptyPositions) + { + // 빈 위치에 돌을 놓았을 때 열린 4가 되는지 확인 + board[emptyPos.y, emptyPos.x] = Black; + + // 쌍사가 형성되는지 확인 + bool formsDoubleFour = CheckDoubleFour(board, emptyPos.y, emptyPos.x); + + // 원래 상태로 복원 + board[emptyPos.y, emptyPos.x] = Space; + + // 쌍사 없이 4를 만들 수 있으면 카운트 증가 + if (!formsDoubleFour) + { + canFormFourCount++; + // 디버깅 + // Debug.Log($"Can form four at ({emptyPos.x}, {emptyPos.y}) without double four"); + } + } + } + + // 하나의 삼만 쌍사 없이 4로 만들 수 있는 경우 + return canFormFourCount == 1; + } + + /// + /// 예외 케이스 2: 9.3 b항의 복잡한 연쇄 체크 + /// + private bool CheckExceptionB(Enums.PlayerType[,] board, int row, int col, List openThrees) + { + // 이 부분은 매우 복잡한 렌주 규칙 9.3 b항을 구현해야 합니다. + // 기본적인 구현만 제공하며, 필요에 따라 확장 가능합니다. + + // 각 열린 3에 대해, 4를 만들 때 다른 쌍삼이 형성되는지 확인 + foreach (var threeInfo in openThrees) + { + bool canFormFourWithoutChainDoubleThree = false; + + foreach (var emptyPos in threeInfo.emptyPositions) + { + // 빈 위치에 돌을 놓았을 때 + board[emptyPos.y, emptyPos.x] = Black; + + // 다른 쌍삼이 형성되는지 확인 (연쇄 체크) + bool formsOtherDoubleThree = false; + + // 다른 모든 빈 위치에 대해 쌍삼 체크 + for (int r = 0; r < BoardSize; r++) + { + for (int c = 0; c < BoardSize; c++) + { + if (board[r, c] == Space) + { + // 임시로 돌 배치하여 쌍삼 체크 + board[r, c] = Black; + bool isDoubleThree = CheckSimpleDoubleThree(board, r, c); + board[r, c] = Space; + + if (isDoubleThree) + { + formsOtherDoubleThree = true; + break; + } + } + } + if (formsOtherDoubleThree) break; + } + + // 원래 상태로 복원 + board[emptyPos.y, emptyPos.x] = Space; + + // 연쇄 쌍삼이 형성되지 않으면 예외 조건 만족 + if (!formsOtherDoubleThree) + { + canFormFourWithoutChainDoubleThree = true; + break; + } + } + + // 하나의 삼이라도 연쇄 쌍삼 없이 4를 만들 수 있으면 예외 조건 만족 + if (canFormFourWithoutChainDoubleThree) { return true; } @@ -320,81 +501,152 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase return false; } + /// + /// 단순 쌍삼 체크 (연쇄 검사용, 재귀 호출 방지) + /// + private bool CheckSimpleDoubleThree(Enums.PlayerType[,] board, int row, int col) + { + int openThreeCount = 0; + + // 4개의 방향 쌍에 대해 검사 + for (int i = 0; i < 4; i++) + { + int dir1 = DirectionPairs[i, 0]; + int dir2 = DirectionPairs[i, 1]; + + // 간단한 열린 3 체크 + if (CheckSimpleOpenThree(board, row, col, dir1, dir2)) + { + openThreeCount++; + if (openThreeCount >= 2) + { + return true; + } + } + } + + return false; + } + + /// + /// 단순 열린 3 체크 (연쇄 검사용) + /// + private bool CheckSimpleOpenThree(Enums.PlayerType[,] board, int row, int col, int dir1, int dir2) + { + Enums.PlayerType[] linePattern = ExtractLinePattern(board, row, col, dir1, dir2); + int centerIndex = 5; + + // 연속된 열린 3 패턴 체크 + for (int start = centerIndex - 2; start <= centerIndex; start++) + { + if (start < 0 || start + 2 >= linePattern.Length) + { + continue; + } + + bool isConsecutiveThree = true; + for (int i = 0; i < 3; i++) + { + if (linePattern[start + i] != Black) + { + isConsecutiveThree = false; + break; + } + } + + if (isConsecutiveThree) + { + bool isLeftOpen = (start - 1 >= 0) && (linePattern[start - 1] == Space); + bool isRightOpen = (start + 3 < linePattern.Length) && (linePattern[start + 3] == Space); + + if (isLeftOpen && isRightOpen) + { + return true; + } + } + } + + // 한 칸 떨어진 열린 3 패턴 체크 (간단 구현) + for (int start = centerIndex - 3; start <= centerIndex; start++) + { + if (start < 0 || start + 3 >= linePattern.Length) + { + continue; + } + + int stoneCount = 0; + int gapCount = 0; + + for (int i = 0; i < 4; i++) + { + if (linePattern[start + i] == Black) + { + stoneCount++; + } + else if (linePattern[start + i] == Space) + { + gapCount++; + } + else + { + stoneCount = 0; + break; + } + } + + if (stoneCount == 3 && gapCount == 1) + { + return true; + } + } + + return false; + } + + /// + /// 쌍사 여부를 확인합니다 (예외 처리용) + /// + private bool CheckDoubleFour(Enums.PlayerType[,] board, int row, int col) + { + int fourCount = 0; + + // 4개의 방향 쌍에 대해 검사 + for (int i = 0; i < 4; i++) + { + int dir1 = DirectionPairs[i, 0]; + int dir2 = DirectionPairs[i, 1]; + + if (CheckFourInDirection(board, row, col, dir1, dir2)) + { + fourCount++; + if (fourCount >= 2) + { + return true; + } + } + } + + return false; + } + /// /// 특정 방향에서 4가 형성되는지 확인합니다. - /// 떨어져 있는 돌도 고려합니다 (한 칸 또는 두 칸 떨어진 패턴 포함). /// private bool CheckFourInDirection(Enums.PlayerType[,] board, int row, int col, int dir1, int dir2) { - // 각 방향으로 최대 5칸까지의 범위를 검사 (현재 위치 포함 총 11칸) Enums.PlayerType[] linePattern = ExtractLinePattern(board, row, col, dir1, dir2); - int centerIndex = 5; // 중앙 인덱스 (현재 위치) + int centerIndex = 5; - // 모든 가능한 패턴 확인 - return CheckFourOneGap(linePattern, centerIndex); - } - - /// - /// 라인 패턴을 추출합니다. (중복 코드를 방지하기 위한 헬퍼 메서드) - /// - private Enums.PlayerType[] ExtractLinePattern(Enums.PlayerType[,] board, int row, int col, int dir1, int dir2) - { - Enums.PlayerType[] linePattern = new Enums.PlayerType[11]; - int centerIndex = 5; // 중앙 인덱스 (현재 위치) - - // 현재 위치 설정 - linePattern[centerIndex] = Black; - - // dir1 방향으로 패턴 채우기 - for (int i = 1; i <= 5; i++) - { - int newRow = row + Directions[dir1, 0] * i; - int newCol = col + Directions[dir1, 1] * i; - - if (IsInBounds(newRow, newCol)) - { - linePattern[centerIndex + i] = board[newRow, newCol]; - } - else - { - linePattern[centerIndex + i] = Space; // 범위 밖은 빈칸으로 처리 - } - } - - // dir2 방향으로 패턴 채우기 - for (int i = 1; i <= 5; i++) - { - int newRow = row + Directions[dir2, 0] * i; - int newCol = col + Directions[dir2, 1] * i; - - if (IsInBounds(newRow, newCol)) - { - linePattern[centerIndex - i] = board[newRow, newCol]; - } - else - { - linePattern[centerIndex - i] = Space; // 범위 밖은 빈칸으로 처리 - } - } - - return linePattern; - } - - /// - /// 한 칸 떨어진 4 패턴을 확인합니다. - /// - private bool CheckFourOneGap(Enums.PlayerType[] linePattern, int centerIndex) - { - // 윈도우 슬라이딩으로 연속된 5칸을 검사 (한 칸 떨어진 패턴을 위해) - for (int start = 0; start <= 5; start++) + // 윈도우 슬라이딩으로 연속된 4를 검사 + for (int start = 0; start <= 7; start++) { // 현재 위치가 이 윈도우에 포함되는지 확인 - bool currentPositionInWindow = (start <= centerIndex && centerIndex < start + 5); + bool currentPositionInWindow = (start <= centerIndex && centerIndex < start + 4); if (!currentPositionInWindow) continue; // 윈도우 내의 돌 개수 세기 int stoneCount = 0; - for (int i = 0; i < 5; i++) + for (int i = 0; i < 4; i++) { if (linePattern[start + i] == Black) { @@ -402,8 +654,7 @@ public class RenjuDoubleThreeDetector: ForbiddenDetectorBase } } - // 정확히 4개의 돌이 있고, 1개의 빈칸이 있으면 4로 판정 - // (현재 위치는 흑으로 이미 설정되어 있음) + // 4개의 돌이 있으면 4로 판정 if (stoneCount == 4) { return true; diff --git a/Assets/Trash Can_JY/Renju.unity b/Assets/Trash Can_JY/Renju.unity index 1a49ad8..b1afb5d 100644 --- a/Assets/Trash Can_JY/Renju.unity +++ b/Assets/Trash Can_JY/Renju.unity @@ -308,6 +308,10 @@ PrefabInstance: propertyPath: m_Name value: Canvas objectReference: {fileID: 0} + - target: {fileID: 1250546304786973426, guid: 65aac0e22fe25aa42b9cf7df776a854d, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} - target: {fileID: 6113787613246818512, guid: 65aac0e22fe25aa42b9cf7df776a854d, type: 3} propertyPath: m_Pivot.x value: 0