using FourInARow; namespace MinMaxAB; public class MinMaxABFourInARowBoard { protected static int EvaluateScoreDiff(int player, int computer) { if (player == 0 && computer == 0) return 0; if (computer > 0) { return computer switch { 1 => 1, 2 => 10, 3 => 100, _ => 0 }; } if (player > 0) { return player switch { 1 => -1, 2 => -10, 3 => -100, _ => 0 }; ; } return 0; } public int CountSequences(GameBoard board) { int score = 0; int[,] directions = new int[,] { { 0, 1 }, { 1, 0 }, { 1, 1 }, { -1, 1 } }; for (int row = 0; row < board.dimensions.Rows; row++) { for (int col = 0; col < board.dimensions.Columns; col++) { for (int dir = 0; dir < 4; dir++) { int rowDir = directions[dir, 0]; int colDir = directions[dir, 1]; int endRow = row + (3 * rowDir); int endCol = col + (3 * colDir); if (endRow >= 0 && endRow < board.dimensions.Rows && endCol >= 0 && endCol < board.dimensions.Columns) { int aiCount = 0; int humanCount = 0; for (int k = 0; k < 4; k++) { int currentRow = row + (k * rowDir); int currentCol = col + (k * colDir); if (board.cells[currentCol][currentRow] == Player.Computer) aiCount++; else if (board.cells[currentCol][currentRow] != Player.None) humanCount++; } score += EvaluateScoreDiff(humanCount, aiCount); } } } } return score; } private int EvaluateMinMax(GameBoard board, int depth, bool maxPlayer = false, int alpha = int.MinValue, int beta = int.MaxValue) { var currentWinner = board.GetWinner(); if (currentWinner == Player.Computer) return (depth + 1) * 100_000; else if (currentWinner == Player.Human) return -(depth + 1) * 100_000; if (!board.HasEmptyColumns()) return 0; if (depth == 0) return CountSequences(board); int best = maxPlayer ? int.MinValue : int.MaxValue; for (int i = 0; i < board.dimensions.Columns; i++) { if (!board.PlaceCoin(maxPlayer ? Player.Computer : Player.Human, i)) continue; int x = EvaluateMinMax(board, depth - 1, !maxPlayer, alpha, beta); best = maxPlayer ? int.Max(best, x) : int.Min(best, x); board.RemoveFromTop(i); if (maxPlayer) alpha = int.Max(alpha, best); else beta = int.Min(beta, best); if (beta <= alpha) i++; } return best; } public int GetBestMove(GameBoard board, int depth) { List<(int Column, int Score)> moves = []; Parallel.For(0, board.dimensions.Columns, i => { var newBoard = board.Clone(); if (!newBoard.PlaceCoin(Player.Computer, i)) return; moves.Add((i, EvaluateMinMax(newBoard, depth))); }); return moves.MaxBy(m => m.Score).Column; } }