template <NodeType NT>
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning);
- template <NodeType NT, bool InCheck>
+ template <NodeType NT>
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth = DEPTH_ZERO);
Value value_to_tt(Value v, int ply);
template <NodeType NT>
Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode, bool skipEarlyPruning) {
+ // Use quiescence search when needed
+ if (depth < ONE_PLY)
+ return qsearch<NT>(pos, ss, alpha, beta);
+
const bool PvNode = NT == PV;
const bool rootNode = PvNode && ss->ply == 0;
if (inCheck)
{
ss->staticEval = eval = VALUE_NONE;
- improving = true;
+ improving = false;
goto moves_loop;
}
else if (ttHit)
{
if ( depth == ONE_PLY
&& eval + RazorMargin1 <= alpha)
- return qsearch<NonPV, false>(pos, ss, alpha, alpha+1);
+ return qsearch<NonPV>(pos, ss, alpha, alpha+1);
else if (eval + RazorMargin2 <= alpha)
{
Value ralpha = alpha - RazorMargin2;
- Value v = qsearch<NonPV, false>(pos, ss, ralpha, ralpha+1);
+
+ Value v = qsearch<NonPV>(pos, ss, ralpha, ralpha+1);
if (v <= ralpha)
return v;
ss->contHistory = thisThread->contHistory[NO_PIECE][0].get();
pos.do_null_move(st);
- Value nullValue = depth-R < ONE_PLY ? -qsearch<NonPV, false>(pos, ss+1, -beta, -beta+1)
- : - search<NonPV>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode, true);
+
+ Value nullValue = -search<NonPV>(pos, ss+1, -beta, -beta+1, depth-R, !cutNode, true);
+
pos.undo_null_move();
if (nullValue >= beta)
thisThread->nmp_ply = ss->ply + 3 * (depth-R) / 4;
thisThread->nmp_odd = ss->ply % 2;
- Value v = depth-R < ONE_PLY ? qsearch<NonPV, false>(pos, ss, beta-1, beta)
- : search<NonPV>(pos, ss, beta-1, beta, depth-R, false, true);
+ Value v = search<NonPV>(pos, ss, beta-1, beta, depth-R, false, true);
thisThread->nmp_odd = thisThread->nmp_ply = 0;
{
assert(is_ok((ss-1)->currentMove));
- Value rbeta = std::min(beta + 200, VALUE_INFINITE);
+ Value rbeta = std::min(beta + 216 - 48 * improving, VALUE_INFINITE);
MovePicker mp(pos, ttMove, rbeta - ss->staticEval, &thisThread->captureHistory);
int probCutCount = 0;
while ( (move = mp.next_move()) != MOVE_NONE
- && probCutCount < depth / ONE_PLY - 3)
+ && probCutCount < 3)
if (pos.legal(move))
{
probCutCount++;
pos.do_move(move, st);
- // Perform a preliminary search at depth 1 to verify that the move holds.
- // We will only do this search if the depth is not 5, thus avoiding two
- // searches at depth 1 in a row.
- if (depth != 5 * ONE_PLY)
- value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, ONE_PLY, !cutNode, true);
+ // Perform a preliminary qsearch to verify that the move holds
+ value = -qsearch<NonPV>(pos, ss+1, -rbeta, -rbeta+1);
- // If the first search was skipped or was performed and held, perform
- // the regular search.
- if (depth == 5 * ONE_PLY || value >= rbeta)
+ // If the qsearch held perform the regular search
+ if (value >= rbeta)
value = -search<NonPV>(pos, ss+1, -rbeta, -rbeta+1, depth - 4 * ONE_PLY, !cutNode, false);
pos.undo_move(move);
// Step 17. Full depth search when LMR is skipped or fails high
if (doFullDepthSearch)
- value = newDepth < ONE_PLY ?
- givesCheck ? -qsearch<NonPV, true>(pos, ss+1, -(alpha+1), -alpha)
- : -qsearch<NonPV, false>(pos, ss+1, -(alpha+1), -alpha)
- : - search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode, false);
+ value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode, false);
// For PV nodes only, do a full PV search on the first move or after a fail
// high (in the latter case search only if value < beta), otherwise let the
(ss+1)->pv = pv;
(ss+1)->pv[0] = MOVE_NONE;
- value = newDepth < ONE_PLY ?
- givesCheck ? -qsearch<PV, true>(pos, ss+1, -beta, -alpha)
- : -qsearch<PV, false>(pos, ss+1, -beta, -alpha)
- : - search<PV>(pos, ss+1, -beta, -alpha, newDepth, false, false);
+ value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth, false, false);
}
// Step 18. Undo move
// qsearch() is the quiescence search function, which is called by the main
// search function with depth zero, or recursively with depth less than ONE_PLY.
-
- template <NodeType NT, bool InCheck>
+ template <NodeType NT>
Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
const bool PvNode = NT == PV;
+ const bool inCheck = bool(pos.checkers());
assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE);
assert(PvNode || (alpha == beta - 1));
assert(depth <= DEPTH_ZERO);
assert(depth / ONE_PLY * ONE_PLY == depth);
- assert(InCheck == bool(pos.checkers()));
Move pv[MAX_PLY+1];
StateInfo st;
// Check for an immediate draw or maximum ply reached
if ( pos.is_draw(ss->ply)
|| ss->ply >= MAX_PLY)
- return (ss->ply >= MAX_PLY && !InCheck) ? evaluate(pos) : VALUE_DRAW;
+ return (ss->ply >= MAX_PLY && !inCheck) ? evaluate(pos) : VALUE_DRAW;
assert(0 <= ss->ply && ss->ply < MAX_PLY);
// Decide whether or not to include checks: this fixes also the type of
// TT entry depth that we are going to use. Note that in qsearch we use
// only two types of depth in TT: DEPTH_QS_CHECKS or DEPTH_QS_NO_CHECKS.
- ttDepth = InCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
+ ttDepth = inCheck || depth >= DEPTH_QS_CHECKS ? DEPTH_QS_CHECKS
: DEPTH_QS_NO_CHECKS;
// Transposition table lookup
posKey = pos.key();
return ttValue;
// Evaluate the position statically
- if (InCheck)
+ if (inCheck)
{
ss->staticEval = VALUE_NONE;
bestValue = futilityBase = -VALUE_INFINITE;
moveCount++;
// Futility pruning
- if ( !InCheck
+ if ( !inCheck
&& !givesCheck
&& futilityBase > -VALUE_KNOWN_WIN
&& !pos.advanced_pawn_push(move))
}
// Detect non-capture evasions that are candidates to be pruned
- evasionPrunable = InCheck
+ evasionPrunable = inCheck
&& (depth != DEPTH_ZERO || moveCount > 2)
&& bestValue > VALUE_MATED_IN_MAX_PLY
&& !pos.capture(move);
// Don't search moves with negative SEE values
- if ( (!InCheck || evasionPrunable)
+ if ( (!inCheck || evasionPrunable)
&& !pos.see_ge(move))
continue;
// Make and search the move
pos.do_move(move, st, givesCheck);
- value = givesCheck ? -qsearch<NT, true>(pos, ss+1, -beta, -alpha, depth - ONE_PLY)
- : -qsearch<NT, false>(pos, ss+1, -beta, -alpha, depth - ONE_PLY);
+ value = -qsearch<NT>(pos, ss+1, -beta, -alpha, depth - ONE_PLY);
pos.undo_move(move);
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
// All legal moves have been searched. A special case: If we're in check
// and no legal moves were found, it is checkmate.
- if (InCheck && bestValue == -VALUE_INFINITE)
+ if (inCheck && bestValue == -VALUE_INFINITE)
return mated_in(ss->ply); // Plies to mate from the root
tte->save(posKey, value_to_tt(bestValue, ss->ply),
return;
// When using nodes, ensure checking rate is not lower than 0.1% of nodes
- callsCnt = Limits.nodes ? std::min(4096, int(Limits.nodes / 1024)) : 4096;
+ callsCnt = Limits.nodes ? std::min(1024, int(Limits.nodes / 1024)) : 1024;
static TimePoint lastInfoTime = now();