/// <summary> /// Initial minimax starting method. This method kicks off the algoritm and finds the best move for the current player. /// If two or more moves have the same value, the best move is choosen randomly from the moves /// </summary> /// <param name="board">The board.</param> /// <returns>Best move for the current player</returns> public static CheckersMove MinimaxStart(CheckerBoard board) { int alpha = int.MinValue; int beta = int.MaxValue; thinking = true; List <CheckersMove> possibleMoves = board.GetMovesForPlayer(); List <int> values = new List <int>(); Logger.Info(string.Format("Max is {0}", board.CurrentPlayerTurn)); if (possibleMoves.IsNullOrEmpty()) { return(null); } foreach (CheckersMove move in possibleMoves) { CheckersMove moveToMake = move; CheckerBoard boardToMakeMoveOn = board; do { Logger.Debug("Board Before"); Logger.Debug(boardToMakeMoveOn.ToString()); boardToMakeMoveOn = (CheckerBoard)boardToMakeMoveOn.GetMinimaxClone(); boardToMakeMoveOn.MakeMoveOnBoard((CheckersMove)moveToMake.GetMinimaxClone()); moveToMake = moveToMake.NextMove; Logger.Debug("Board After"); Logger.Debug(boardToMakeMoveOn.ToString()); }while (moveToMake != null); values.Add(Minimax(boardToMakeMoveOn, Settings.AIDepth - 1, alpha, beta, false, board.CurrentPlayerTurn)); } int maxHeuristics = int.MinValue; foreach (int value in values) { if (value >= maxHeuristics) { maxHeuristics = value; } } //filter the list of moves based on max value List <CheckersMove> bestMoves = new List <CheckersMove>(); for (int i = 0; i < values.Count; i++) { if (values[i] == maxHeuristics) { bestMoves.Add(possibleMoves[i]); } } counter = 0; thinking = false; Logger.Info("Node Values: " + string.Join(",", values.Select(x => x.ToString()).ToArray())); return(bestMoves[Rng.Next(bestMoves.Count)]); }
/// <summary> /// Runs the minimax algoritm with alpha beta pruning /// </summary> /// <param name="board">The board.</param> /// <param name="depth">The depth.</param> /// <param name="alpha">The alpha.</param> /// <param name="beta">The beta.</param> /// <param name="isMax">if set to <c>true</c> [is maximum].</param> /// <param name="rootPlayer">The root player.</param> /// <returns>Minimax value for this board state</returns> private static int Minimax(CheckerBoard board, int depth, int alpha, int beta, bool isMax, PlayerColor rootPlayer) { List <CheckersMove> possibleMoves = board.GetMovesForPlayer(); if (depth == 0 || possibleMoves.Count == 0) { return(Score(board, rootPlayer)); } int value = 0; if (isMax) { value = int.MinValue; foreach (CheckersMove move in possibleMoves) { CheckersMove moveToMake = move; CheckerBoard boardToMakeMoveOn = board; do { boardToMakeMoveOn = (CheckerBoard)boardToMakeMoveOn.GetMinimaxClone(); boardToMakeMoveOn.MakeMoveOnBoard((CheckersMove)moveToMake.GetMinimaxClone()); moveToMake = moveToMake.NextMove; }while (moveToMake != null); int result = Minimax(boardToMakeMoveOn, depth - 1, alpha, beta, false, rootPlayer); value = Math.Max(result, value); alpha = Math.Max(alpha, value); if (alpha >= beta) { Logger.Debug("Branch was pruned"); break; } } } else { value = int.MaxValue; foreach (CheckersMove move in possibleMoves) { CheckersMove moveToMake = move; CheckerBoard boardToMakeMoveOn = board; do { boardToMakeMoveOn = (CheckerBoard)boardToMakeMoveOn.GetMinimaxClone(); boardToMakeMoveOn.MakeMoveOnBoard((CheckersMove)moveToMake.GetMinimaxClone()); moveToMake = moveToMake.NextMove; }while (moveToMake != null); int result = Minimax(boardToMakeMoveOn, depth - 1, alpha, beta, true, rootPlayer); value = Math.Min(result, value); beta = Math.Min(alpha, value); if (alpha >= beta) { Logger.Debug("Branch was pruned"); break; } } } return(value); }