using FourInARow; namespace MinMaxAB; public class MinMaxABFourInARowBoard { protected static int EvaluateScoreDiff(int player, int computer) { if ((player == 0 && computer == 0) || (computer > 0 && player > 0)) return 0; if (computer > 0) { return computer switch { 1 => 1, 2 => 8, 3 => 64, _ => 0 }; } if (player > 0) { return player switch { 1 => -1, 2 => -8, 3 => -64, _ => 0 }; ; } return 0; } private readonly int[][] directions = [ [ 0, 1 ], [ 1, 0 ], [ 1, 1 ], [ -1, 1 ] ]; // public int CountSequences(GameBoard board) // { // int score = 0; // 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; // } // БЫСТРЕЕ ПРИ ВЫСОКОЙ ЧАСТОТЕ ПРОЦА public int CountSequences(GameBoard board) { int score = 0; for (int col = 0; col < board.dimensions.Columns; col++) { for (int row = 0; row < board.dimensions.Rows - 3; row++) { int c = 0; int p = 0; for (int k = 0; k < 4; k++) { if (board.cells[col][row + k] == Player.Computer) c++; else if (board.cells[col][row + k] != Player.None) p++; } score += EvaluateScoreDiff(p, c); } } for (int col = 0; col < board.dimensions.Columns - 3; col++) { for (int row = 0; row < board.dimensions.Rows; row++) { int c = 0; int p = 0; for (int k = 0; k < 4; k++) { if (board.cells[col + k][row] == Player.Computer) c++; else if (board.cells[col + k][row] != Player.None) p++; } score += EvaluateScoreDiff(p, c); } } for (int col = 0; col < board.dimensions.Columns - 3; col++) { for (int row = 0; row < board.dimensions.Rows - 3; row++) { int c = 0; int p = 0; for (int k = 0; k < 4; k++) { if (board.cells[col + k][row + k] == Player.Computer) c++; else if (board.cells[col + k][row + k] != Player.None) p++; } score += EvaluateScoreDiff(p, c); } } for (int col = 3; col < board.dimensions.Columns; col++) { for (int row = 0; row < board.dimensions.Rows - 3; row++) { int c = 0; int p = 0; for (int k = 0; k < 4; k++) { if (board.cells[col - k][row + k] == Player.Computer) c++; else if (board.cells[col - k][row + k] != Player.None) p++; } score += EvaluateScoreDiff(p, c); } } 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, new() { MaxDegreeOfParallelism = 1 }, i => 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.OrderByDescending(m => m.Score).ThenBy(m => int.Abs(m.Column - (board.dimensions.Columns / 2))).First().Column; } }