DO-4 [Refactor] 시간 단축 - Move Ordering 적용

This commit is contained in:
Sehyeon 2025-03-17 16:17:25 +09:00
parent 9f94a8d0a5
commit 23f114897a

View File

@ -6,7 +6,7 @@ using UnityEngine;
public static class MiniMaxAIController public static class MiniMaxAIController
{ {
// To-Do List // To-Do List
// 탐색 시간 개선 // 탐색 시간 개선: 캐싱(_stoneInfoCache), 좋은 수부터 탐색(Move Ordering)
// AI 난이도 개선 // AI 난이도 개선
private const int SEARCH_DEPTH = 3; // 탐색 깊이 제한 (3 = 빠른 응답, 4 = 좀 더 강한 AI 그러나 느린) private const int SEARCH_DEPTH = 3; // 탐색 깊이 제한 (3 = 빠른 응답, 4 = 좀 더 강한 AI 그러나 느린)
@ -52,7 +52,7 @@ public static class MiniMaxAIController
float bestScore = float.MinValue; float bestScore = float.MinValue;
(int row, int col)? bestMove = null; (int row, int col)? bestMove = null;
(int row, int col)? secondBestMove = null; (int row, int col)? secondBestMove = null;
List<(int row, int col)> validMoves = GetValidMoves(board); List<(int row, int col, float score)> validMoves = GetValidMoves(board);
// 보드에 놓을 수 있는 자리가 있는지 확인 // 보드에 놓을 수 있는 자리가 있는지 확인
if (validMoves.Count == 0) if (validMoves.Count == 0)
@ -68,7 +68,7 @@ public static class MiniMaxAIController
return bestMove; return bestMove;
} }
foreach (var (row, col) in validMoves) foreach (var (row, col, _) in validMoves)
{ {
board[row, col] = _AIPlayerType; board[row, col] = _AIPlayerType;
float score = DoMinimax(board, SEARCH_DEPTH, false, -1000, 1000, row, col); float score = DoMinimax(board, SEARCH_DEPTH, false, -1000, 1000, row, col);
@ -105,26 +105,26 @@ public static class MiniMaxAIController
if (depth == 0) return EvaluateBoard(board); if (depth == 0) return EvaluateBoard(board);
float bestScore = isMaximizing ? float.MinValue : float.MaxValue; float bestScore = isMaximizing ? float.MinValue : float.MaxValue;
List<(int row, int col)> validMoves = GetValidMoves(board); // 현재 놓을 수 있는 자리 리스트 List<(int row, int col, float score)> validMoves = GetValidMoves(board); // 현재 놓을 수 있는 자리 리스트
foreach (var (row, col) in validMoves) foreach (var (row, col, _) in validMoves)
{ {
board[row, col] = isMaximizing ? Enums.PlayerType.PlayerB : Enums.PlayerType.PlayerA; board[row, col] = isMaximizing ? Enums.PlayerType.PlayerB : Enums.PlayerType.PlayerA;
ClearCache(); // 돌 ClearCache(); // 돌
float score = DoMinimax(board, depth - 1, !isMaximizing, alpha, beta, row, col); float minimaxScore = DoMinimax(board, depth - 1, !isMaximizing, alpha, beta, row, col);
board[row, col] = Enums.PlayerType.None; board[row, col] = Enums.PlayerType.None;
ClearCache(); ClearCache();
if (isMaximizing) if (isMaximizing)
{ {
bestScore = Math.Max(bestScore, score); bestScore = Math.Max(bestScore, minimaxScore);
alpha = Math.Max(alpha, bestScore); alpha = Math.Max(alpha, bestScore);
} }
else else
{ {
bestScore = Math.Min(bestScore, score); bestScore = Math.Min(bestScore, minimaxScore);
beta = Math.Min(beta, bestScore); beta = Math.Min(beta, bestScore);
} }
@ -134,9 +134,9 @@ public static class MiniMaxAIController
} }
// 이동 가능 + 주변에 돌 있는 위치 탐색 // 이동 가능 + 주변에 돌 있는 위치 탐색
private static List<(int row, int col)> GetValidMoves(Enums.PlayerType[,] board) private static List<(int row, int col, float score)> GetValidMoves(Enums.PlayerType[,] board)
{ {
List<(int, int)> validMoves = new List<(int, int)>(); List<(int, int, float)> validMoves = new List<(int, int, float)>();
int size = board.GetLength(0); int size = board.GetLength(0);
for (int row = 0; row < size; row++) for (int row = 0; row < size; row++)
@ -145,10 +145,13 @@ public static class MiniMaxAIController
{ {
if (board[row, col] == Enums.PlayerType.None && HasNearbyStones(board, row, col)) if (board[row, col] == Enums.PlayerType.None && HasNearbyStones(board, row, col))
{ {
validMoves.Add((row, col)); float score = EvaluateBoard(board);
validMoves.Add((row, col, score));
} }
} }
} }
validMoves.Sort((a, b) => b.Item3.CompareTo(a.Item3));
return validMoves; return validMoves;
} }
@ -224,6 +227,7 @@ public static class MiniMaxAIController
// 캐시 초기화, 새로운 돌이 놓일 시 실행 // 캐시 초기화, 새로운 돌이 놓일 시 실행
private static void ClearCache() private static void ClearCache()
{ {
// 전체 초기화가 아닌 부분 초기화하기? (현재 변경된 위치 N에서 반경 5칸만 초기화)
_stoneInfoCache.Clear(); _stoneInfoCache.Clear();
} }