Пример #1
0
        private async Task <double?> PrincipalVariationSearchAsync(GameBoard gameBoard, int depth, double alpha, double beta, int color, OrderType orderType, CancellationToken token)
        {
            double alphaOriginal = alpha;

            ulong key = gameBoard.ZobristKey;

            if (TranspositionTable.TryLookup(key, out TranspositionTableEntry tEntry) && tEntry.Depth >= depth)
            {
                if (tEntry.Type == TranspositionTableEntryType.Exact)
                {
                    return(tEntry.Value);
                }
                else if (tEntry.Type == TranspositionTableEntryType.LowerBound)
                {
                    alpha = Math.Max(alpha, tEntry.Value);
                }
                else if (tEntry.Type == TranspositionTableEntryType.UpperBound)
                {
                    beta = Math.Min(beta, tEntry.Value);
                }

                if (alpha >= beta)
                {
                    return(tEntry.Value);
                }
            }

            if (depth == 0 || gameBoard.GameIsOver)
            {
                return(await QuiescenceSearchAsync(gameBoard, QuiescentSearchMaxDepth, alpha, beta, color, token));
            }

            double?bestValue = null;
            Move   bestMove  = tEntry?.BestMove;

            List <Move> moves = GetPreSortedValidMoves(gameBoard, bestMove);

            bool firstMove = true;

            foreach (Move move in moves.GetEnumerableByOrderType(orderType))
            {
                bool updateAlpha = false;

                if (token.IsCancellationRequested)
                {
                    return(null);
                }

                double?value = null;

                gameBoard.TrustedPlay(move);

                if (firstMove)
                {
                    // Full window search
                    value = -1 * await PrincipalVariationSearchAsync(gameBoard, depth - 1, -beta, -alpha, -color, orderType, token);

                    updateAlpha = true;
                    firstMove   = false;
                }
                else
                {
                    // Null window search
                    value = -1 * await PrincipalVariationSearchAsync(gameBoard, depth - 1, -alpha - double.Epsilon, -alpha, -color, orderType, token);

                    if (value.HasValue && value > alpha && value < beta)
                    {
                        // Research with full window
                        value = -1 * await PrincipalVariationSearchAsync(gameBoard, depth - 1, -beta, -alpha, -color, orderType, token);

                        updateAlpha = true;
                    }
                }

                gameBoard.UndoLastMove();

                if (!value.HasValue)
                {
                    return(null);
                }

                if (updateAlpha)
                {
                    alpha = Math.Max(alpha, value.Value);
                }

                if (!bestValue.HasValue || value >= bestValue)
                {
                    bestValue = value;
                    bestMove  = move;
                }

                if (bestValue >= beta)
                {
                    break;
                }
            }

            if (bestValue.HasValue)
            {
                tEntry = new TranspositionTableEntry();

                if (bestValue <= alphaOriginal)
                {
                    tEntry.Type = TranspositionTableEntryType.UpperBound;
                }
                else
                {
                    tEntry.Type     = bestValue >= beta ? TranspositionTableEntryType.LowerBound : TranspositionTableEntryType.Exact;
                    tEntry.BestMove = bestMove;
                }

                tEntry.Value = bestValue.Value;
                tEntry.Depth = depth;

                TranspositionTable.Store(key, tEntry);
            }

            return(bestValue);
        }
Пример #2
0
        private async Task <EvaluatedMoveCollection> EvaluateMovesToDepthAsync(GameBoard gameBoard, int depth, IEnumerable <EvaluatedMove> movesToEvaluate, CancellationToken token)
        {
            double alpha = double.NegativeInfinity;
            double beta  = double.PositiveInfinity;

            int color = gameBoard.CurrentTurnColor == PlayerColor.White ? 1 : -1;

            double alphaOriginal = alpha;

            double?bestValue = null;

            EvaluatedMoveCollection evaluatedMoves = new EvaluatedMoveCollection();

            bool firstMove = true;

            foreach (EvaluatedMove moveToEvaluate in movesToEvaluate)
            {
                bool updateAlpha = false;

                if (token.IsCancellationRequested)
                {
                    // Cancel
                    return(new EvaluatedMoveCollection(movesToEvaluate, false));
                }

                gameBoard.TrustedPlay(moveToEvaluate.Move);

                double?value = null;

                if (firstMove)
                {
                    // Full window search
                    value = -1 * await PrincipalVariationSearchAsync(gameBoard, depth - 1, -beta, -alpha, -color, OrderType.Default, token);

                    updateAlpha = true;
                    firstMove   = false;
                }
                else
                {
                    // Null window search
                    value = -1 * await PrincipalVariationSearchAsync(gameBoard, depth - 1, -alpha - double.Epsilon, -alpha, -color, OrderType.Default, token);

                    if (value.HasValue && value > alpha && value < beta)
                    {
                        // Research with full window
                        value = -1 * await PrincipalVariationSearchAsync(gameBoard, depth - 1, -beta, -alpha, -color, OrderType.Default, token);

                        updateAlpha = true;
                    }
                }

                gameBoard.UndoLastMove();

                if (!value.HasValue)
                {
                    // Cancel occurred during evaluation
                    return(new EvaluatedMoveCollection(movesToEvaluate, false));
                }

                EvaluatedMove evaluatedMove = new EvaluatedMove(moveToEvaluate.Move, value.Value, depth);
                evaluatedMoves.Add(evaluatedMove);

                if (updateAlpha)
                {
                    alpha = Math.Max(alpha, value.Value);
                }

                if (!bestValue.HasValue || value >= bestValue)
                {
                    bestValue = value;
                }

                if (bestValue >= beta)
                {
                    // A winning move has been found, since beta is always infinity in this function
                    break;
                }
            }

            ulong key = gameBoard.ZobristKey;

            TranspositionTableEntry tEntry = new TranspositionTableEntry();

            if (bestValue <= alphaOriginal)
            {
                // Losing move since alphaOriginal os negative infinity in this function
                tEntry.Type = TranspositionTableEntryType.UpperBound;
            }
            else
            {
                // Move is a lower bound winning move if bestValue >= beta (always infinity in this function), otherwise it's exact
                tEntry.Type     = bestValue >= beta ? TranspositionTableEntryType.LowerBound : TranspositionTableEntryType.Exact;
                tEntry.BestMove = evaluatedMoves.BestMove.Move;
            }

            tEntry.Value = bestValue.Value;
            tEntry.Depth = depth;

            TranspositionTable.Store(key, tEntry);

            return(evaluatedMoves);
        }