Beispiel #1
0
        /// <summary>
        /// Recursively carries out a full width alpha beta search untill the bottom is reached.
        /// From then a Quiescent search is carried out to avoid horrison effects.
        /// </summary>
        /// <param name="alpha">This is the best score that can be forced by some means. Anything worth less than this is of no use, because there is a strategy that is known to result in a score of alpha.</param>
        /// <param name="beta">Beta is the worst thing that the opponent has to endure. If the search finds something that returns a score of beta or better, it's too good, so the side to move is not going to get a chance to use this strategy.</param>
        /// <param name="remainingDepth">Remaining depth to search before bottom is reached.</param>
        /// <param name="allowNullMove">Is a null move allowed at this search depth.</param>
        /// <param name="allowTranspotitionTable">Is it allowed to use the transpotition table to probe for scores.</param>
        /// <returns>The score of a board.</returns>
        private int AlphaBetaSearch(int alpha, int beta, int remainingDepth, bool allowNullMove, bool allowTranspotitionTable)
        {
            if (m_searchRollback)
            {
                return(beta);
            }

            //At interval check if time is up and rollback if so.
            if (m_nodesVisited == m_nextRollbackCheck)
            {
                if (AbortingSearch())
                {
                    m_alphaBetaTable.Close();
                    m_quiescentTable.Close();
                    m_searchRollback = true;
                    return(beta);
                }

                m_nextRollbackCheck += ROLLBACK_INTERVAL_COUNT;
            }
            ++m_nodesVisited;

            int           score         = 0;
            Move          pvMove        = null;
            AlphaBetaFlag alphaBetaFlag = AlphaBetaFlag.AlphaScore;

            if (m_board.State.NonHitAndPawnMovesPlayed >= 100)
            {
                return(0);
            }

            if (m_board.BoardHistoryFrequency() >= 3)
            {
                return(0);
            }

            //don't allow transposition table before both players has passed the above repetetion draw checks.
            if (allowTranspotitionTable && (m_searchDepth - remainingDepth) > 0)
            {
                if (m_alphaBetaTable.ProbeScore(m_board.BoardHash(false), alpha, beta, remainingDepth, ref score))
                {
                    if (Math.Abs(score) != Math.Abs(m_evaluator.MateValue)) //don't probe a mate value as this actuall might be a mate far down in the tree, and we want to find the mate at lowest depth.
                    {
                        return(score);
                    }
                }
            }

            if (remainingDepth == 0)
            {
                score = QuiescentSearch(alpha, beta);

                if (allowTranspotitionTable)
                {
                    m_alphaBetaTable.RecordHash(m_board.BoardHash(false), AlphaBetaFlag.ExactScore, remainingDepth, score, pvMove);
                }

                return(score);
            }

            if (allowNullMove)
            {
                //Carry out a null move which is a move where nothing is actually moved. This makes the opponent move
                //twice in a row. The idea is then to search to a reduced depth and if nothing good come out of this
                //(for the opponent) the move is considered garbage and we cut it off.
                NullMove nullMove = new NullMove(m_board, m_evaluator);
                if (nullMove.Execute())
                {
                    int remDepth = (remainingDepth > NULL_REDUCTION) ? remainingDepth - 1 - NULL_REDUCTION : 0;
                    score = -AlphaBetaSearch(-beta, -beta + 1, remDepth, false, false);
                    nullMove.UnExecute();

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

            MoveOrganizer currentMoves = new MoveOrganizer(m_alphaBetaTable.ProbePvMove(m_board.BoardHash(false)));

            m_board.GeneratePseudoLegalMoves(currentMoves);
            currentMoves.Sort(m_captureMoveCompare);

            bool validMoveFound = false;

            foreach (Move move in currentMoves)
            {
                if (move.Execute(m_board))
                {
                    validMoveFound = true;

                    if (pvMove == null)
                    {
                        score = -AlphaBetaSearch(-beta, -alpha, remainingDepth - 1, true, allowTranspotitionTable);
                    }
                    else
                    {
                        score = -AlphaBetaSearch(-alpha - 1, -alpha, remainingDepth - 1, true, false);
                        if ((score > alpha) && (score < beta))
                        {
                            score = -AlphaBetaSearch(-beta, -alpha, remainingDepth - 1, true, allowTranspotitionTable);
                        }
                    }
                    move.UnExecute(m_board);

                    if (score >= beta)
                    {
                        if (allowTranspotitionTable)
                        {
                            m_alphaBetaTable.RecordHash(m_board.BoardHash(false), AlphaBetaFlag.BetaScore, remainingDepth, beta, pvMove);
                        }

                        return(beta);
                    }

                    if (score > alpha)
                    {
                        alpha         = score;
                        pvMove        = move;
                        alphaBetaFlag = AlphaBetaFlag.ExactScore;
                    }
                }
            }

            if (!validMoveFound)
            {
                if (m_board.ColorToPlayIsCheck())
                {
                    alpha = m_evaluator.MateValue; //Checkmate
                }
                else
                {
                    alpha = 0; //Stalemate
                }
            }

            if (allowTranspotitionTable)
            {
                m_alphaBetaTable.RecordHash(m_board.BoardHash(false), alphaBetaFlag, remainingDepth, alpha, pvMove);
            }

            return(alpha);
        }