Example #1
0
    /// <summary>
    /// Recursive alpha beta pruning minimax search strategy.
    /// </summary>
    /// <param name="gbs">The Game Board State.</param>
    /// <param name="searchLevels">The number of levels to search (depth)</param>
    /// <param name="currentPlayer">The current player's turn.</param>
    /// <param name="BestMove">The best move found during the search</param>
    /// <param name="alpha">Starting alpha value.</param>
    /// <param name="beta">Starting beta value.</param>
    /// <returns></returns>
    public static AIMinMaxResult AIMinMaxSearch(this IGameBoardState gbs, int searchLevels, Player.PlayerNumber currentPlayer, bool QuiescenceSearch = false, double alpha = -1.0, double beta = 1.0)
    {
        Move BestMove = null;

        double checkWinner = gbs.CheckWinner();

        //cutoff for search (recursive base cases)
        if (checkWinner == -1.0)
        {
            return(new AIMinMaxResult(BestMove, -1.0, 1));
        }

        if (checkWinner == 1.0)
        {
            return(new AIMinMaxResult(BestMove, 1.0, 1));
        }

        if (searchLevels == 0)
        {
            return(new AIMinMaxResult(BestMove, gbs.CalculateUtility(), 1));
        }

        AIMinMaxResult result         = null;
        long           statesSearched = 0;
        //iterate by looking at all possible moves for each piece
        List <IPieceState> pieces = gbs.GetAlivePieces().Where(s => s.GetPlayer() == currentPlayer).Select(s => s).ToList();

        foreach (IPieceState piece in pieces.Shuffle())
        {
            List <Move> moves;
            if (QuiescenceSearch)
            {
                moves = MoveGenerator.GetCaptureMoves(gbs, piece);
            }
            else
            {
                moves = MoveGenerator.GetMoves(gbs, piece);
            }

            MovesSearched += moves.Count;

            //perform each move on a cloned board and search clone recursively, swapping players each turn
            foreach (Move move in moves.Shuffle())
            {
                IGameBoardState clone = gbs.Clone();
                clone.Move(move.piece, move.space);

                if (currentPlayer == Player.PlayerNumber.Player1)
                {
                    result          = clone.AIMinMaxSearch(searchLevels - 1, Player.PlayerNumber.Player2, true, alpha, beta);
                    statesSearched += result.TotalStatesSearched;
                    if (statesSearched > StatesSearched)
                    {
                        StatesSearched = statesSearched;
                    }
                    if (result.AlphaBeta > alpha)
                    {
                        alpha    = result.AlphaBeta;
                        BestMove = move;
                    }

                    //beta cut off
                    if (beta <= alpha)
                    {
                        break;
                    }
                }
                else /* (currentPlayer == Player.PlayerNumber.Player2) */
                {
                    result          = clone.AIMinMaxSearch(searchLevels - 1, Player.PlayerNumber.Player1, true, alpha, beta);
                    statesSearched += result.TotalStatesSearched;
                    if (statesSearched > StatesSearched)
                    {
                        StatesSearched = statesSearched;
                    }
                    if (result.AlphaBeta < beta)
                    {
                        beta     = result.AlphaBeta;
                        BestMove = move;
                    }

                    //alpha cut off
                    if (beta <= alpha)
                    {
                        break;
                    }
                }

                if (jobStatus == AIMinMaxJobStatus.StopRequested && LevelsSearched > 0)
                {
                    searchLevels = 1;
                }
            }

            if (jobStatus == AIMinMaxJobStatus.StopRequested && LevelsSearched > 0)
            {
                searchLevels = 1;
            }
        }

        //no moves found, treat as a base case
        if (BestMove == null)
        {
            return(new AIMinMaxResult(BestMove, gbs.CalculateUtility(), 1));
        }

        //Create a result and return it
        return(new AIMinMaxResult(BestMove, result.AlphaBeta, statesSearched));
    }