コード例 #1
0
        private int QuiesceneSearch(int alpha, int beta)
        {
            searchInfo.Nodes++;
            searchInfo.QNodes++;

            int currentEval = Evaluation.Evaluate(board);

            if (currentEval >= beta)
            {
                searchInfo.BetaCutoffs++;
                return(beta);
            }
            if (currentEval > alpha)
            {
                alpha = currentEval;
            }

            generator.Setup();
            var moves = generator.GetMoves(true);

            foreach (var move in moves.OrderByDescending(m => MoveImportance(m, -1, null)))
            {
                board.SubmitMove(move);
                var eval = -QuiesceneSearch(-beta, -alpha);
                board.UndoMove();

                if (eval >= beta)
                {
                    searchInfo.BetaCutoffs++;
                    return(beta);
                }

                if (eval > alpha)
                {
                    alpha = eval;
                }
            }

            return(alpha);
        }
コード例 #2
0
        private int DeepEval(int depth, int alpha, int beta, bool nullMoveAllowed, Move[] pv, IDictionary <Move, int> orderedTopLevelMoves = null)
        {
            searchInfo.Nodes++;

            if (transpositions.ContainsKey(board.positionKey))
            {
                searchInfo.Transpositions++;
                var score = LookupEvaluation(alpha, beta);

                if (score != LookupFailed)
                {
                    return(score);
                }
            }

            generator.Setup();
            var moves = generator.GetMoves(false);

            if (!moves.Any())
            {
                //When in Check: Checkmate:
                if (generator.InCheck)
                {
                    //Compute checkmate score:
                    var currentDepth = board.states.Count; //TODO add ply variable to board
                    return(-CHECKMATE + currentDepth);
                }
                else //Stalemate
                {
                    return(DRAW);
                }
            }
            else if (board.states.Any(s => s.positionKey == board.positionKey))
            {
                //Repetition
                return(DRAW);
            }

            //TODO Add 50 moves rule

            if (depth == 0)
            {
                return(QuiesceneSearch(alpha, beta));
            }

            if (depth == 1)
            {
                //Futility pruning
                var currentEval = Evaluation.Evaluate(board);
                if (currentEval + Evaluation.BishopValue < alpha)
                {
                    searchInfo.FutilityPrunes++;
                    //Prune this node, i.e. go directly to QuiesceneSearch
                    return(QuiesceneSearch(alpha, beta));
                }
            }

            if (nullMoveAllowed && !generator.InCheck && depth >= 1 + R)
            {
                searchInfo.NullMoves++;
                //Null move pruning
                var npv = new Move[depth]; //irellevant here
                board.SubmitNullMove();
                int eval = -DeepEval(depth - 1 - R, -beta, -beta + 1, false, npv);
                board.UndoNullMove();
                if (eval >= beta)
                {
                    searchInfo.NullMovesSuccess++;
                    return(eval);
                }
            }

            TranspositionEntryType ttType = TranspositionEntryType.UpperBound;
            int movenumber = 1;

            bool searchPV = true;

            foreach (var move in moves.OrderByDescending(m => MoveImportance(m, depth, orderedTopLevelMoves)))
            {
                if (depth == searchInfo.Depth) //Upper level
                {
                    Console.WriteLine($"info currmove {move.ToAlgebraicNotation()} currmovenumber {movenumber++} depth {depth}");
                }

                var npv = new Move[depth - 1];
                board.SubmitMove(move);

                int eval;
                if (searchPV)
                {
                    eval = -DeepEval(depth - 1, -beta, -alpha, true, npv);
                }
                else
                {
                    searchInfo.Scouts++;
                    //Scout zw search
                    eval = -ZWSerach(depth - 1, -alpha);
                    if (eval > alpha)
                    {
                        eval = -DeepEval(depth - 1, -beta, -alpha, true, npv); // re-search
                    }
                    else
                    {
                        searchInfo.ScoutRemovals++;
                    }
                }

                board.UndoMove();

                if (depth == searchInfo.Depth)
                {
                    searchInfo.TopLevelMoveOrder.Add(move, eval);
                }

                if (eval >= beta)
                {
                    searchInfo.BetaCutoffs++;
                    //transposition is an upper bound
                    StoreEvaluation(eval, TranspositionEntryType.LowerBound);
                    if (move.CapturedPiece == Piece.NONE)
                    {
                        KillerMoves[board.Ply][2] = KillerMoves[board.Ply][1];
                        KillerMoves[board.Ply][1] = KillerMoves[board.Ply][0];
                        KillerMoves[board.Ply][0] = move;
                    }
                    return(beta);
                }
                else if (eval > alpha)
                {
                    alpha    = eval;
                    searchPV = false;
                    pv[0]    = move;
                    Array.Copy(npv, 0, pv, 1, npv.Length);
                    ttType = TranspositionEntryType.Exact;
                }
            }

            StoreEvaluation(alpha, ttType);

            return(alpha);
        }
コード例 #3
0
        //ZW search with multicut
        private int ZWSerach(int depth, int beta, bool cut = true, bool nullMoveAllowed = true)
        {
            searchInfo.Nodes++;
            generator.Setup();
            var moves = generator.GetMoves(false);

            if (transpositions.ContainsKey(board.positionKey))
            {
                searchInfo.Transpositions++;
                var score = LookupEvaluation(beta - 1, beta);

                if (score != LookupFailed)
                {
                    return(score);
                }
            }

            if (!moves.Any())
            {
                //When in Check: Checkmate:
                if (generator.InCheck)
                {
                    return(beta - 1);
                }
                else //Stalemate
                {
                    if (0 >= beta)
                    {
                        return(beta);
                    }
                    else
                    {
                        return(beta - 1);
                    }
                }
            }
            else if (board.states.Any(s => s.positionKey == board.positionKey))
            {
                //Repetition
                if (0 >= beta)
                {
                    return(beta);
                }
                else
                {
                    return(beta - 1);
                }
            }

            if (depth <= 0)
            {
                return(QuiesceneSearch(beta - 1, beta));
            }


            if (depth == 1)
            {
                //Futility pruning
                var currentEval = Evaluation.Evaluate(board);
                if (currentEval + Evaluation.BishopValue < beta - 1)
                {
                    searchInfo.FutilityPrunes++;
                    //Prune this node, i.e. go directly to QuiesceneSearch
                    return(QuiesceneSearch(beta - 1, beta));
                }
            }

            if (nullMoveAllowed && !generator.InCheck && depth >= 1 + R)
            {
                searchInfo.NullMoves++;
                //Null move pruning
                board.SubmitNullMove();
                int eval = -ZWSerach(depth - 1 - R, 1 - beta, cut, false);
                board.UndoNullMove();
                if (eval >= beta)
                {
                    searchInfo.NullMovesSuccess++;
                    return(beta);
                }
            }

            var orderedMoves = moves.OrderByDescending(m => MoveImportance(m, depth, null)).ToList();
            var moveIndex    = 0;

            if (depth >= MC_R && cut)
            {
                int c = 0;
                for (int m = 0; m < MC_M && moveIndex < orderedMoves.Count; m++)
                {
                    board.SubmitMove(orderedMoves[moveIndex]);
                    int eval = -ZWSerach(depth - 1 - MC_R, 1 - beta, !cut, true);
                    board.UndoMove();
                    moveIndex++;
                    if (eval >= beta)
                    {
                        c++;
                        if (c == MC_C)
                        {
                            searchInfo.MCPrunes++;
                            return(beta); // mc-prune
                        }
                    }
                }
            }

            for (moveIndex = 0; moveIndex < orderedMoves.Count; moveIndex++)
            {
                board.SubmitMove(orderedMoves[moveIndex]);
                int eval = -ZWSerach(depth - 1, 1 - beta, !cut, true);
                board.UndoMove();

                if (eval >= beta)
                {
                    return(beta);
                }
            }

            return(beta - 1);
        }