Move ttMove, move, excludedMove, bestMove;
Depth extension, newDepth;
Value bestValue, value, ttValue, eval, maxValue;
- bool ttHit, inCheck, givesCheck, singularExtensionNode, improving;
+ bool ttHit, inCheck, givesCheck, improving;
bool captureOrPromotion, doFullDepthSearch, moveCountPruning, skipQuiets, ttCapture, pvExact;
Piece movedPiece;
int moveCount, captureCount, quietCount;
if (skipEarlyPruning || !pos.non_pawn_material(pos.side_to_move()))
goto moves_loop;
- // Step 7. Razoring (skipped when in check)
+ // Step 7. Razoring (skipped when in check, ~2 Elo)
if ( !PvNode
&& depth < 3 * ONE_PLY
&& eval <= alpha - RazorMargin[depth / ONE_PLY])
return v;
}
- // Step 8. Futility pruning: child node (skipped when in check)
+ // Step 8. Futility pruning: child node (skipped when in check, ~30 Elo)
if ( !rootNode
&& depth < 7 * ONE_PLY
&& eval - futility_margin(depth, improving) >= beta
&& eval < VALUE_KNOWN_WIN) // Do not return unproven wins
return eval;
- // Step 9. Null move search with verification search
+ // Step 9. Null move search with verification search (~40 Elo)
if ( !PvNode
&& eval >= beta
&& ss->staticEval >= beta - 36 * depth / ONE_PLY + 225
}
}
- // Step 10. ProbCut (skipped when in check)
+ // Step 10. ProbCut (skipped when in check, ~10 Elo)
// If we have a good enough capture and a reduced search returns a value
// much above beta, we can (almost) safely prune the previous move.
if ( !PvNode
}
}
- // Step 11. Internal iterative deepening (skipped when in check)
+ // Step 11. Internal iterative deepening (skipped when in check, ~2 Elo)
if ( depth >= 6 * ONE_PLY
&& !ttMove
&& (PvNode || ss->staticEval + 128 >= beta))
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory, contHist, countermove, ss->killers);
value = bestValue; // Workaround a bogus 'uninitialized' warning under gcc
- singularExtensionNode = !rootNode
- && depth >= 8 * ONE_PLY
- && ttMove != MOVE_NONE
- && ttValue != VALUE_NONE
- && !excludedMove // Recursive singular search is not allowed
- && (tte->bound() & BOUND_LOWER)
- && tte->depth() >= depth - 3 * ONE_PLY;
skipQuiets = false;
ttCapture = false;
pvExact = PvNode && ttHit && tte->bound() == BOUND_EXACT;
moveCountPruning = depth < 16 * ONE_PLY
&& moveCount >= FutilityMoveCounts[improving][depth / ONE_PLY];
- // Step 13. Extensions
+ // Step 13. Extensions (~70 Elo)
- // Singular extension search. If all moves but one fail low on a search
- // of (alpha-s, beta-s), and just one fails high on (alpha, beta), then
- // that move is singular and should be extended. To verify this we do a
- // reduced search on on all the other moves but the ttMove and if the
+ // Singular extension search (~60 Elo). If all moves but one fail low on a
+ // search of (alpha-s, beta-s), and just one fails high on (alpha, beta),
+ // then that move is singular and should be extended. To verify this we do
+ // a reduced search on on all the other moves but the ttMove and if the
// result is lower than ttValue minus a margin then we will extend the ttMove.
- if ( singularExtensionNode
+ if ( depth >= 8 * ONE_PLY
&& move == ttMove
+ && !rootNode
+ && !excludedMove // Recursive singular search is not allowed
+ && ttValue != VALUE_NONE
+ && (tte->bound() & BOUND_LOWER)
+ && tte->depth() >= depth - 3 * ONE_PLY
&& pos.legal(move))
{
Value rBeta = std::max(ttValue - 2 * depth / ONE_PLY, -VALUE_MATE);
if (value < rBeta)
extension = ONE_PLY;
}
- else if ( givesCheck // Check extension
+ else if ( givesCheck // Check extension (~2 Elo)
&& !moveCountPruning
&& pos.see_ge(move))
extension = ONE_PLY;
// Calculate new depth for this move
newDepth = depth - ONE_PLY + extension;
- // Step 14. Pruning at shallow depth
+ // Step 14. Pruning at shallow depth (~170 Elo)
if ( !rootNode
&& pos.non_pawn_material(pos.side_to_move())
&& bestValue > VALUE_MATED_IN_MAX_PLY)
&& !givesCheck
&& (!pos.advanced_pawn_push(move) || pos.non_pawn_material() >= Value(5000)))
{
- // Move count based pruning
+ // Move count based pruning (~30 Elo)
if (moveCountPruning)
{
skipQuiets = true;
// Reduced depth of the next LMR search
int lmrDepth = std::max(newDepth - reduction<PvNode>(improving, depth, moveCount), DEPTH_ZERO) / ONE_PLY;
- // Countermoves based pruning
+ // Countermoves based pruning (~20 Elo)
if ( lmrDepth < 3
&& (*contHist[0])[movedPiece][to_sq(move)] < CounterMovePruneThreshold
&& (*contHist[1])[movedPiece][to_sq(move)] < CounterMovePruneThreshold)
continue;
- // Futility pruning: parent node
+ // Futility pruning: parent node (~2 Elo)
if ( lmrDepth < 7
&& !inCheck
&& ss->staticEval + 256 + 200 * lmrDepth <= alpha)
continue;
- // Prune moves with negative SEE
+ // Prune moves with negative SEE (~10 Elo)
if ( lmrDepth < 8
&& !pos.see_ge(move, Value(-35 * lmrDepth * lmrDepth)))
continue;
}
- else if ( depth < 7 * ONE_PLY
+ else if ( depth < 7 * ONE_PLY // (~20 Elo)
&& !extension
&& !pos.see_ge(move, -Value(CapturePruneMargin[depth / ONE_PLY])))
continue;
else
{
assert(value >= beta); // Fail high
+ ss->statScore = std::max(ss->statScore, 0);
break;
}
}