Пример #1
0
    private Move computeBestMove(Side side, Chessboard chessboard, int presentCumulativeScore)
    {
        currentDepth++;

        // First, get the set of available moves
        List <Move> moves = new List <Move>();
        Move        bestMoveForIteration = new Move(null, null);

        bool isPlayingSide = chessboard.CurrentMovingSide() == side;

        foreach (AbstractPiece piece in chessboard.getActivePieces())
        {
            if (piece.side == chessboard.CurrentMovingSide())
            {
                foreach (Position movePosition in piece.GetSafeMovesForCurrentPosition().GetPositions())
                {
                    Move newMove = MoveEvaluator.EvaluateMove(new Move(piece, movePosition), isPlayingSide);
                    moves = InsertionSortMove(moves, newMove);
                }
            }
        }

        if (moves.Count > 0)
        {
            bestMoveForIteration = moves.ToArray()[0];
            if (currentDepth < maxAllowableDepth)
            {
                foreach (Move move in moves)
                {
                    Chessboard copyChessboard = Chessboard.MakeCopyOfChessboard(chessboard);
                    copyChessboard.MoveTo(copyChessboard.GetPieceAtPosition(move.getPiece().GetCurrentPosition()), move.getPosition());
                    copyChessboard.ChangeMovingSide();
                    int followUpScore = computeBestMove(side, copyChessboard, presentCumulativeScore + move.getScore()).getScore();

                    if (move.getScore() + followUpScore > bestMoveForIteration.getScore())
                    {
                        bestMoveForIteration = move;
                    }
                }
            }
        }

        currentDepth--;

        return(bestMoveForIteration);
    }
Пример #2
0
        private int Search(int depth, int ply, int alpha, int beta, PVList pvList, bool nullMoveReduction)
        {
            if (ct.IsCancellationRequested)
            {
                return(0);
            }

            searchStats.Nodes++;

            if (gameState.IsDraw())
            {
                int score = evaluator.GetDrawScore(engine.EngineColor);
                if (score > alpha)
                {
                    pvList.Replace(new PVList());
                }
                return(score);
            }

            if (gameState.IsCheck() && depth < ArtemisEngine.MAX_DEPTH)
            {
                //check extension
                depth += 1;
            }

            int   originalAlpha = alpha;
            ulong hash          = gameState.GetIrrevState().ZobristHash;
            TTHit ttHit         = transpositionTable.TryGetValue(hash, depth, alpha, beta, pvList);

            if (ttHit.HitType == HitType.Hit)
            {
                searchStats.TTHits++;
                return(ttHit.Score);
            }
            TranspositionNode ttNode = ttHit.TTNode;

            if (depth <= 0 || ply == ArtemisEngine.MAX_DEPTH)
            {
                int score = quietSearch.Search(alpha, beta);
                if (score > alpha)
                {
                    pvList.Replace(new PVList());
                }
                return(score);
            }


            Move   bestMove = null;
            bool   cutoff   = false;
            PVList newPV    = new PVList();
            bool   PVNode   = alpha != beta - 1;

            if (!PVNode && ttHit.HitType != HitType.AvoidNullMove &&
                !nullMoveReduction && engine.GameStage != GameStage.Endgame && !gameState.IsCheck())
            {
                //null move pruning
                gameState.MakeNullMove();
                int nextDepth = depth - 1 - config.NullMoveDepthReduction;
                int score     = -Search(nextDepth, ply + 1, -beta, -beta + 1, newPV, true);
                gameState.UnmakeNullMove();
                if (score >= beta)
                {
                    searchStats.NullMoveCutoffs++;
                    searchStats.AlphaBetaCutoffs++;
                    TranspositionNode newNode = new TranspositionNode(NodeType.CutNode, score, nextDepth + 1, null, null);
                    SaveNode(hash, ttNode, newNode);
                    //alpha-beta cutoff
                    return(beta);
                }
            }

            List <Move> moves  = gameState.GetMoves();
            Move        pvMove = null;

            if (PVNode)
            {
                if (currentPVNode != null)
                {
                    pvMove        = currentPVNode.Move;
                    currentPVNode = currentPVNode.Next;
                }
                else
                {
                    PVNode = false;
                }
            }
            Move hashMove = null;

            if (ttNode != null)
            {
                hashMove = ttNode.BestMove;
            }
            Move[] killers = killerMoves.GetKillerMoves(ply);
            moves = moves.OrderByDescending(m => moveEvaluator.EvaluateMove(m, pvMove, hashMove, killers).Score).ToList();

            int  originalLen          = moves.Count;
            int  moveCount            = 0;
            bool lmrCandidatePosition = depth >= 3 && !PVNode && !gameState.IsCheck();

            for (int i = 0; i < moves.Count && !cutoff; i++)
            {
                Move move = moves[i];
                gameState.MakeMove(move);
                if (move.IsLegal())
                {
                    int  nextDepth    = depth - 1;
                    bool lmrReduction = false;
                    if (lmrCandidatePosition && moveCount >= 4 && move.IsQuiet() && !gameState.IsCheck())
                    {
                        lmrReduction = true;
                        nextDepth--;
                        searchStats.LMRReductions++;
                    }

                    int score;
                    if (moveCount == 0 || searchDepth == 1)
                    {
                        score = -Search(nextDepth, ply + 1, -beta, -alpha, newPV, false);
                    }
                    else
                    {
                        ulong moveHash = gameState.GetIrrevState().ZobristHash;
                        if (!config.Multithreading || i >= originalLen || searchedNodes.TryAdd(moveHash, true))
                        {
                            score = -Search(nextDepth, ply + 1, -alpha - 1, -alpha, newPV, false);
                            searchedNodes.TryRemove(moveHash, out _);

                            if (score > alpha)
                            {
                                if (lmrReduction)
                                {
                                    nextDepth++;
                                }
                                score = -Search(nextDepth, ply + 1, -beta, -alpha, newPV, false);
                            }
                        }
                        else
                        {
                            moves.Add(move);
                            gameState.UnmakeMove(move);
                            continue;
                        }
                    }

                    if (score >= beta)
                    {
                        //alpha-beta cutoff
                        searchStats.AlphaBetaCutoffs++;
                        alpha    = beta;
                        bestMove = move;
                        cutoff   = true;
                        killerMoves.AddMove(move, ply);
                    }
                    else if (score > alpha)
                    {
                        alpha    = score;
                        bestMove = move;
                    }

                    moveCount++;
                }
                gameState.UnmakeMove(move);
            }

            if (moveCount == 0)
            {
                //player has no legal moves
                if (gameState.IsCheck())
                {
                    return(-PositionEvaluator.CHECKMATE_SCORE - depth);
                }
                else
                {
                    return(0);
                }
            }

            NodeType nodeType = GetNodeType(originalAlpha, beta, alpha);
            PVList   nodePV   = null;

            if (nodeType == NodeType.PVNode)
            {
                searchStats.PVNodes++;
                PVNode node = new PVNode(bestMove);
                newPV.AddFirst(node);
                nodePV = newPV;
                pvList.Replace(newPV);
            }
            TranspositionNode updatedNode = new TranspositionNode(nodeType, alpha, depth, bestMove, nodePV);

            SaveNode(hash, ttNode, updatedNode);

            return(alpha);
        }