DO-4 [Style] 공유되는 변수 정리

This commit is contained in:
Sehyeon 2025-03-19 15:02:35 +09:00
parent b382e82059
commit 3eb595b143
5 changed files with 100 additions and 26 deletions

View File

@ -0,0 +1,12 @@
// AI에서만 사용하는 상수 모음
public class AIConstants
{
// 방향 상수
public static readonly int[][] Directions = new int[][]
{
new int[] {1, 0}, // 수직
new int[] {0, 1}, // 수평
new int[] {1, 1}, // 대각선 ↘ ↖
new int[] {1, -1} // 대각선 ↙ ↗
};
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: de0993e48b9548668a73768a38c11b6d
timeCreated: 1742362879

View File

@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public static class AIEvaluator
{
// 패턴 가중치 상수
public static class PatternScore
public struct PatternScore
{
// AI 패턴 점수
public const float FIVE_IN_A_ROW = 100000f;
@ -31,14 +32,7 @@ public static class AIEvaluator
public const float EDGE_WEIGHT = 0.8f;
}
// 방향 상수 -> public으로 빼기
private static readonly int[][] Directions = new int[][]
{
new int[] {1, 0}, // 수직
new int[] {0, 1}, // 수평
new int[] {1, 1}, // 대각선 ↘ ↖
new int[] {1, -1} // 대각선 ↙ ↗
};
private static readonly int[][] Directions = AIConstants.Directions;
// 보드 전체 상태 평가
public static float EvaluateBoard(Enums.PlayerType[,] board, Enums.PlayerType aiPlayer)
@ -102,7 +96,7 @@ public static class AIEvaluator
// 위치 가중치 적용
patternScore *= positionWeight;
// 최종 점수 적용 (플레이어는 음수)
// 최종 점수 (플레이어는 음수)
score += playerScore * patternScore;
}
}
@ -310,19 +304,24 @@ public static class AIEvaluator
return fourThreeCount;
}
// 이동 평가 함수 (EvaluateMove 대체)
// 이동 평가 함수
public static float EvaluateMove(Enums.PlayerType[,] board, int row, int col, Enums.PlayerType AIPlayer)
{
float score = 0;
Enums.PlayerType opponentPlayer = (AIPlayer == Enums.PlayerType.PlayerA) ?
Enums.PlayerType.PlayerB : Enums.PlayerType.PlayerA;
// 복합 패턴 감지를 위한 위치 저장 리스트
List<(int[] dir, int count, int openEnds)> aiPatterns = new List<(int[], int, int)>();
List<(int[] dir, int count, int openEnds)> opponentPatterns = new List<(int[], int, int)>();
// AI 관점에서 평가
board[row, col] = AIPlayer;
foreach (var dir in Directions)
{
var (count, openEnds) = MiniMaxAIController.CountStones(board, row, col, dir, AIPlayer, false);
aiPatterns.Add((dir, count, openEnds));
if (count >= 4)
{
@ -347,12 +346,16 @@ public static class AIEvaluator
}
}
// AI 복합 패턴 점수 계산 (새로 추가)
score += EvaluateComplexMovePatterns(aiPatterns, true);
// 상대 관점에서 평가 (방어 가치)
board[row, col] = opponentPlayer;
foreach (var dir in Directions)
{
var (count, openEnds) = MiniMaxAIController.CountStones(board, row, col, dir, opponentPlayer, false);
opponentPatterns.Add((dir, count, openEnds));
// 상대 패턴 차단에 대한 가치 (약간 낮은 가중치)
if (count >= 4)
@ -378,6 +381,8 @@ public static class AIEvaluator
}
}
score += EvaluateComplexMovePatterns(opponentPatterns, false);
// 원래 상태로 복원
board[row, col] = Enums.PlayerType.None;
@ -391,4 +396,57 @@ public static class AIEvaluator
return score * centerBonus;
}
// 복합 패턴 평가를 위한 새로운 함수
private static float EvaluateComplexMovePatterns(List<(int[] dir, int count, int openEnds)> patterns, bool isAI)
{
float score = 0;
// 열린 3 패턴 및 4 패턴 찾기
var openThrees = patterns.Where(p => p.count == 3 && p.openEnds == 2).ToList();
var fours = patterns.Where(p => p.count == 4 && p.openEnds >= 1).ToList();
// 3-3 패턴 감지
if (openThrees.Count >= 2)
{
for (int i = 0; i < openThrees.Count; i++)
{
for (int j = i + 1; j < openThrees.Count; j++)
{
if (!AreParallelDirections(openThrees[i].dir, openThrees[j].dir))
{
float threeThreeScore = PatternScore.DOUBLE_THREE / 4; // 복합 패턴 가중치
score += isAI ? threeThreeScore : threeThreeScore;
break;
}
}
}
}
// 4-4 패턴 감지
if (fours.Count >= 2)
{
for (int i = 0; i < fours.Count; i++)
{
for (int j = i + 1; j < fours.Count; j++)
{
if (!AreParallelDirections(fours[i].dir, fours[j].dir))
{
float fourFourScore = PatternScore.DOUBLE_FOUR / 4;
score += isAI ? fourFourScore : fourFourScore;
break;
}
}
}
}
// 4-3 패턴 감지
if (fours.Count > 0 && openThrees.Count > 0)
{
float fourThreeScore = PatternScore.FOUR_THREE / 4;
score += isAI ? fourThreeScore : fourThreeScore;
}
return score;
}
}

View File

@ -8,19 +8,14 @@ public static class MiniMaxAIController
private const int SEARCH_DEPTH = 3; // 탐색 깊이 제한 (3 = 빠른 응답, 4 = 좀 더 강한 AI 그러나 느린)
private const int WIN_COUNT = 5;
private static int[][] _directions = new int[][]
{
new int[] {1, 0}, // 수직
new int[] {0, 1}, // 수평
new int[] {1, 1}, // 대각선 ↘ ↖
new int[] {1, -1} // 대각선 ↙ ↗
};
private static int[][] _directions = AIConstants.Directions;
private static int _playerLevel = 1; // 급수 설정
private static float _mistakeMove;
private static Enums.PlayerType _AIPlayerType = Enums.PlayerType.PlayerB;
private static System.Random _random = new System.Random();
private static System.Random _random = new System.Random(); // 랜덤 실수용 Random 함수
// 중복 계산을 방지하기 위한 캐싱 데이터. 위치 기반 (그리드 기반 해시맵)
private static Dictionary<(int row, int col), Dictionary<(int dirX, int dirY), (int count, int openEnds)>>
@ -36,7 +31,7 @@ public static class MiniMaxAIController
public static void SetLevel(int level)
{
_playerLevel = level;
// 레벨에 따른 실수률? 설정
_mistakeMove = GetMistakeProbability(_playerLevel);
}
@ -158,7 +153,10 @@ public static class MiniMaxAIController
// score가 높은 순으로 정렬 -> 더 좋은 수 먼저 계산하도록 함
validMoves.Sort((a, b) => b.Item3.CompareTo(a.Item3));
return validMoves;
// 상위 10-15개만 고려. 일단 15개
return validMoves.Take(15).ToList();
// return validMoves;
}
private static bool HasNearbyStones(Enums.PlayerType[,] board, int row, int col, int distance = 3)
@ -274,11 +272,13 @@ public static class MiniMaxAIController
#endregion
// 최근에 둔 돌 위치 기반으로 게임 승리를 판별하는 함수
public static bool CheckGameWin(Enums.PlayerType player, Enums.PlayerType[,] board, int row, int col)
// !!!!!!MinimaxAIController 밖의 cs파일은 호출 시 맨 마지막을 false로 지정해야 합니다.!!!!!!
public static bool CheckGameWin(Enums.PlayerType player, Enums.PlayerType[,] board,
int row, int col, bool isSavedCache = true)
{
foreach (var dir in _directions)
{
var (count, _) = CountStones(board, row, col, dir, player);
var (count, _) = CountStones(board, row, col, dir, player, isSavedCache);
// 자기 자신 포함하여 5개 이상일 시 true 반환
if (count + 1 >= WIN_COUNT)

View File

@ -261,7 +261,7 @@ public class GameLogic : MonoBehaviour
ReplayManager.Instance.RecordStonePlaced(Enums.StoneType.Black, row, col); //기보 데이터 저장
break;
case Enums.PlayerType.PlayerB:
/*
// AI 테스트 시작
OmokAI.Instance.StartBestMoveSearch(_board, (bestMove) =>
{
@ -277,14 +277,15 @@ public class GameLogic : MonoBehaviour
}
});
// AI 테스트 끝
*/
/*
stoneController.SetStoneType(Enums.StoneType.White, row, col);
stoneController.SetStoneState(Enums.StoneState.LastPositioned, row, col);
_board[row, col] = Enums.PlayerType.PlayerB;
LastNSelectedSetting(row, col);
ReplayManager.Instance.RecordStonePlaced(Enums.StoneType.White, row, col);
*/
break;
}
}