Exemplo n.º 1
0
        public int Search(int alpha, int beta, int depth)
        {
            Metrics.Nodes++;
            PvLength[Ply] = Ply;
            var inCheck = MyBoard.InCheck(MyBoard.SideToMove);
            int ext     = inCheck ? 1 : 0;

            if (MyGameState.GameBoard.History.IsPositionDrawn(MyBoard.HashKey))
            {
                return(CurrentDrawScore);
            }

            if (Ply >= MAX_DEPTH)
            {
                TakeBack();
                return(Evaluator.Evaluate(MyBoard, -10000, 10000));
            }

            if ((Metrics.Nodes & 65535) == 65535)
            {
                Interrupt();
                if (MyGameState.TimeUp)
                {
                    return(alpha);
                }
            }

            Move bestMove = null;

            if (depth + ext <= 0)
            {
                return(Quiesce(alpha, beta));
            }

            //first let's look for a transposition
            var entry = TranspositionTable.Instance.Read(MyBoard.HashKey);

            if (entry != null)
            {
                //we have a hit from the TTable
                if (entry.Depth >= depth)
                {
                    if (entry.Type == (byte)EntryType.CUT && entry.Score >= beta)
                    {
                        return(beta);
                    }
                    else if (entry.Type == (byte)EntryType.ALL && entry.Score <= alpha)
                    {
                        return(alpha);
                    }
                    else if (entry.Type == (byte)EntryType.PV)
                    {
                        return(entry.Score);
                    }
                }
            }

            int mateThreat   = 0;
            var myPieceCount = MyBoard.PieceCount(MyBoard.SideToMove);

            //next try a Null Move
            if (Ply > 0 &&
                depth > 1 &&
                alpha == beta - 1 &&
                !inCheck &&
                !MyBoard.History[Ply - 1].IsNullMove &&
                myPieceCount > 0 &&
                (myPieceCount > 2 || depth < 7))
            {
                Metrics.NullMoveTries++;
                MakeNullMove();
                var nullReductionDepth = depth > 6 ? 4 : 3;
                int nmScore;
                if (depth - nullReductionDepth - 1 > 0)
                {
                    nmScore = -Search(-beta, 1 - beta, depth - nullReductionDepth - 1);
                }
                else
                {
                    nmScore = -Quiesce(-beta, 1 - beta);
                }
                UnmakeNullMove();

                if (MyGameState.TimeUp)
                {
                    return(alpha);
                }

                if (nmScore >= beta)
                {
                    Metrics.NullMoveFailHigh++;
                    TranspositionTable.Instance.Store(MyBoard.HashKey, null, depth, nmScore, EntryType.CUT);
                    return(nmScore);
                }
            }

            var moves = MoveGenerator
                        .GenerateMoves(MyBoard)
                        .OrderByDescending((m) => OrderMove(m, entry));
            Move lastMove = null;
            int  lmr = 0, nonCaptureMoves = 0, movesSearched = 0;

            foreach (var m in moves)
            {
                bool fprune = false;
                int  score;
                if (!Make(m))
                {
                    continue;
                }

                var justGaveCheck = MyBoard.InCheck(MyBoard.SideToMove);
                var capture       = ((m.Bits & (byte)MoveBits.Capture) != 0);
                if (!capture && (entry == null || entry.MoveValue != m.Value)) // don't count the hash move as a non-capture
                {
                    ++nonCaptureMoves;                                         // while it might not be a capture, the point
                }
                // here is to start counting after generated captures
                var passedpawnpush = (m.Bits & (byte)MoveBits.Pawn) > 0 && (Evaluator.PassedPawnMask[MyBoard.SideToMove ^ 1, m.To] & MyBoard.Pawns[MyBoard.SideToMove]) == 0;
                //LATE MOVE REDUCTIONS
                if (ext == 0 &&          //no extension
                    !inCheck &&          //i am not in check at this node
                    !justGaveCheck &&    //the move we just made does not check the opponent
                    mateThreat == 0 &&   //no mate threat detected
                    !passedpawnpush &&   //do not reduce/prune passed pawn pushes
                    nonCaptureMoves > 0) //start reducing after the winning captures
                {
                    if (depth > 2)
                    {
                        lmr = movesSearched > 2 ? 2 : 1; // start reducing depth if we aren't finding anything useful
                    }
                    //FUTILITY PRUNING
                    else if (depth < 3 && alpha > -9900 && beta < 9900)
                    {
                        if (depth == 2 && -Evaluator.EvaluateMaterial(MyBoard) + Evaluator.PieceValues[(int)Piece.Rook] <= alpha)
                        {
                            Metrics.EFPrune++;
                            fprune = true;
                        }

                        else if (depth == 1 && -Evaluator.EvaluateMaterial(MyBoard) + Evaluator.PieceValues[(int)Piece.Knight] <= alpha)
                        {
                            Metrics.FPrune++;
                            fprune = true;
                        }
                    }
                }
                if (!fprune)
                {
                    //if we don't yet have a move, then search full window (PV Node)
                    if (bestMove == null)
                    {
                        score = -Search(-beta, -alpha, depth - 1 - lmr + ext);
                    }
                    else //otherwise, use a zero window
                    {
                        //zero window search
                        score = -Search(-alpha - 1, -alpha, depth - 1 - lmr + ext);

                        if (score > alpha)
                        {
                            //this move might be better than our current best move
                            //we have to research with full window

                            score = -Search(-beta, -alpha, depth - 1 - lmr + ext);

                            if (score > alpha && lmr > 0)
                            {
                                //let's research again without the lmr
                                Metrics.LMRResearch++;
                                score = -Search(-beta, -alpha, depth - 1);
                            }
                        }
                    }
                }
                else
                {
                    score = -Quiesce(-beta, -alpha);
                }

                TakeBack();
                ++movesSearched;
                if (MyGameState.TimeUp)
                {
                    return(alpha);
                }

                if (score >= beta)
                {
                    SearchFailHigh(m, score, depth, entry);
                    if (lastMove == null)
                    {
                        Metrics.FirstMoveFailHigh++;
                    }
                    return(score);
                }

                if (score > alpha)
                {
                    alpha    = score;
                    bestMove = m;
                    // PV Node
                    //update the PV
                    UpdatePv(bestMove);
                    //Add to hashtable
                    TranspositionTable.Instance.Store(
                        MyBoard.HashKey, bestMove, depth, alpha, TranspositionTableEntry.EntryType.PV);
                }

                lastMove = m;
            }

            //check for mate
            if (lastMove == null)
            {
                //we can't make a move. check for mate or stalemate.
                if (inCheck)
                {
                    return(-10000 + Ply);
                }
                else
                {
                    return(CurrentDrawScore);
                }
            }


            if (bestMove == null)
            {
                //ALL NODE
                TranspositionTable.Instance.Store(
                    MyBoard.HashKey, null, depth, alpha,
                    TranspositionTableEntry.EntryType.ALL);
            }

            return(alpha);
        }