Example #1
0
        /// <summary>
        /// Returns the dynamic value of the position as determined by a recursive
        /// search that terminates upon reaching a quiescent position.
        /// </summary>
        /// <param name="position">The position to search on.</param>
        /// <param name="ply">The number of plies from the root position.</param>
        /// <param name="alpha">The lower bound on the value of the best move.</param>
        /// <param name="beta">The upper bound on the value of the best move.</param>
        /// <returns>The value of the termination position given optimal play.</returns>
        private Int32 Quiescence(Position position, Int32 ply, Int32 alpha, Int32 beta)
        {
            _totalNodes++;
            _quiescenceNodes++;

            // Evaluate the position statically. Check for upper bound cutoff and lower
            // bound improvement.
            Int32 value = Evaluate(position);

            if (value >= beta)
            {
                return(value);
            }
            if (value > alpha)
            {
                alpha = value;
            }

            // Perform hash probe.
            _hashProbes++;
            Int32 hashMove = Move.Invalid;

            if (_table.TryProbe(position.ZobristKey, out HashEntry hashEntry))
            {
                Int32 hashType  = hashEntry.Type;
                Int32 hashValue = hashEntry.GetValue(ply);
                if (hashType == HashEntry.Exact ||
                    (hashType == HashEntry.Beta && hashValue >= beta) ||
                    (hashType == HashEntry.Alpha && hashValue <= alpha))
                {
                    _hashCutoffs++;
                    return(hashValue);
                }
                if (Move.IsCapture(hashEntry.Move))
                {
                    hashMove = hashEntry.Move;
                }
            }

            // Initialize variables and generate the pseudo-legal moves to be
            // considered. Perform basic move ordering and sort the moves.
            Int32 colour = position.SideToMove;

            Int32[] moves      = _generatedMoves[ply];
            Int32   movesCount = position.PseudoQuiescenceMoves(moves);

            if (movesCount == 0)
            {
                return(alpha);
            }
            for (Int32 i = 0; i < movesCount; i++)
            {
                _moveValues[i] = MoveOrderingValue(moves[i]);
            }

            // Perform hash move ordering.
            _hashMoveChecks++;
            if (hashMove != Move.Invalid)
            {
                for (Int32 i = 0; i < movesCount; i++)
                {
                    if (moves[i] == hashMove)
                    {
                        _moveValues[i] = HashMoveValue;
                        _hashMoveMatches++;
                        break;
                    }
                }
            }

            Sort(moves, _moveValues, movesCount);
            Int32 bestType = HashEntry.Alpha;
            Int32 bestMove = moves[0];

            // Go through the move list.
            for (Int32 i = 0; i < movesCount; i++)
            {
                _movesSearched++;
                Int32 move = moves[i];

                // Consider the move only if it doesn't lose material.
                if (EvaluateStaticExchange(position, move) >= 0)
                {
                    // Make the move.
                    position.Make(move);

                    // Search the move if it is legal. This is equivalent to not leaving the
                    // king in check.
                    if (!position.InCheck(colour))
                    {
                        value = -Quiescence(position, ply + 1, -beta, -alpha);

                        // Check for upper bound cutoff and lower bound improvement.
                        if (value >= beta)
                        {
                            position.Unmake(move);
                            _table.Store(new HashEntry(position, 0, ply, move, value, HashEntry.Beta));
                            return(value);
                        }
                        if (value > alpha)
                        {
                            alpha    = value;
                            bestMove = move;
                            bestType = HashEntry.Exact;
                        }
                    }

                    // Unmake the move.
                    position.Unmake(move);
                }
            }
            _table.Store(new HashEntry(position, 0, ply, bestMove, alpha, bestType));
            return(alpha);
        }