예제 #1
0
        private int PrincipalVariationSearch(Board board, Colour colour, byte depth, ushort ply, int alpha, int beta, uint[] parentPrincipalVariation)
        {
            ++PositionCount;

            if (depth == 0)
            {
                return(positionEvaluator.Evaluate(board) * (colour == Colour.White ? 1 : -1));
            }

            var transpositionKey = board.Key;

            var existingTransposition = transpositionTable.Find(transpositionKey);

            uint previousBestMove = 0;

            if (existingTransposition.Key != 0)
            {
                if (existingTransposition.Depth > 1 && existingTransposition.Depth > depth)
                {
                    return(existingTransposition.Evaluation);
                }

                if (existingTransposition.BestMove != 0)
                {
                    previousBestMove = existingTransposition.BestMove;
                }
            }

            var bestScore = int.MinValue;
            var bestMove  = 0u;

            var principalVariation = new uint[64];

            var moveCount = 1;

            foreach (var move in GetNextMove(moveGenerator, ply, board, colour, previousBestMove))
            {
                board.MakeMove(move);

                var evaluatedScore = 0;

                var oppositeColour = colour.Opposite();

                var nextDepth = (byte)(depth - 1);
                var nextPly   = (ushort)(ply + 1);

                // https://www.chessprogramming.org/Principal_Variation_Search
                if (moveCount == 1)
                {
                    // Always do a full search on the first/PV move
                    evaluatedScore = -PrincipalVariationSearch(board, oppositeColour, nextDepth, nextPly, -beta, -alpha, principalVariation);
                }
                else
                {
                    // Late Move Reduction http://mediocrechess.blogspot.com/2007/03/other-late-move-reduction-lmr.html
                    if (ply > 3 && moveCount > 3 && move.GetCapturePieceType() == PieceType.None && move.GetNumCheckers() == 0 && nextDepth > 0)
                    {
                        --nextDepth;
                    }

                    // Search with aspiration window
                    evaluatedScore = -PrincipalVariationSearch(board, oppositeColour, nextDepth, nextPly, -alpha - 1, -alpha, principalVariation);

                    if (alpha < evaluatedScore && evaluatedScore < beta)
                    {
                        // Re-search
                        evaluatedScore = -PrincipalVariationSearch(board, oppositeColour, nextDepth, nextPly, -beta, -evaluatedScore, principalVariation);
                    }
                }

                board.UnMakeMove(move);

                if (alpha < evaluatedScore)
                {
                    // alpha = Math.Max(bestScore, evaluatedScore); // alpha acts like max in MiniMax
                    alpha = evaluatedScore;

                    bestMove  = move;
                    bestScore = evaluatedScore;

                    UpdatePrincipalVariation(principalVariation, parentPrincipalVariation, ply, move);
                }

                if (alpha > beta)
                {
                    // Fail-hard beta-cutoff
                    break;
                }

                ++moveCount;

                if (ply == 1)
                {
                    var info = new Info(PositionCount, stopWatch.ElapsedMilliseconds, depth, transpositionTable);

                    Info?.Invoke(this, new InfoEventArgs(info));
                }
            }

            transpositionTable.Set(transpositionKey, depth, colour, bestScore, bestMove);

            if (alpha == int.MinValue)
            {
                alpha = PieceValues.CheckmateValue + ply;
            }

            if (alpha == int.MaxValue)
            {
                alpha = -(PieceValues.CheckmateValue + ply);
            }

            return(alpha);
        }
예제 #2
0
 private int Evaluate() => positionEvaluator.Evaluate(board);