// Futility margin
Value futility_margin(Depth d, bool noTtCutNode, bool improving) {
- return Value((126 - 42 * noTtCutNode) * (d - improving));
+ return Value((125 - 43 * noTtCutNode) * (d - improving));
}
// Reductions lookup table initialized at startup
Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) {
int reductionScale = Reductions[d] * Reductions[mn];
- return (reductionScale + 1560 - int(delta) * 945 / int(rootDelta)) / 1024
- + (!i && reductionScale > 791);
+ return (reductionScale + 1487 - int(delta) * 976 / int(rootDelta)) / 1024
+ + (!i && reductionScale > 808);
}
constexpr int futility_move_count(bool improving, Depth depth) {
}
// History and stats update bonus, based on depth
-int stat_bonus(Depth d) { return std::min(334 * d - 531, 1538); }
+int stat_bonus(Depth d) { return std::min(357 * d - 483, 1511); }
// Add a small random component to draw evaluations to avoid 3-fold blindness
Value value_draw(const Thread* thisThread) {
// If eval is really low check with qsearch if it can exceed alpha, if it can't,
// return a fail low.
// Adjust razor margin according to cutoffCnt. (~1 Elo)
- if (eval < alpha - 492 - (257 - 200 * ((ss + 1)->cutoffCnt > 3)) * depth * depth)
+ if (eval < alpha - 474 - (270 - 174 * ((ss + 1)->cutoffCnt > 3)) * depth * depth)
{
value = qsearch<NonPV>(pos, ss, alpha - 1, alpha);
if (value < alpha)
+ {
+ if (!priorCapture && prevSq != SQ_NONE)
+ {
+ int bonus = (depth > 6) + (PvNode || cutNode) + (value < alpha - 658)
+ + ((ss - 1)->moveCount > 11);
+ update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
+ stat_bonus(depth) * bonus);
+ thisThread->mainHistory[~us][from_to((ss - 1)->currentMove)]
+ << stat_bonus(depth) * bonus * 57 / 100;
+ }
return value;
+ }
}
// Step 8. Futility pruning: child node (~40 Elo)
- (ss - 1)->statScore / 321
>= beta
&& eval >= beta && eval < 29462 // smaller than TB wins
- && !(!ttCapture && ttMove))
+ && (!ttMove || ttCapture))
return eval;
// Step 9. Null move search with verification search (~35 Elo)
}
}
- // Step 10. If the position doesn't have a ttMove, decrease depth by 2,
- // or by 4 if the TT entry for the current position was hit and
+ // Step 10. Internal iterative reductions (~9 Elo)
+ // For PV nodes without a ttMove, we decrease depth by 2,
+ // or by 4 if the current position is present in the TT and
// the stored depth is greater than or equal to the current depth.
- // Use qsearch if depth is equal or below zero (~9 Elo)
+ // Use qsearch if depth <= 0.
if (PvNode && !ttMove)
depth -= 2 + 2 * (ss->ttHit && tte->depth() >= depth);
if (depth <= 0)
return qsearch<PV>(pos, ss, alpha, beta);
+ // For cutNodes without a ttMove, we decrease depth by 2
+ // if current depth >= 8.
if (cutNode && depth >= 8 && !ttMove)
depth -= 2;
{
assert(probCutBeta < VALUE_INFINITE);
- MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory);
+ MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory,
+ thisThread->pawnHistory);
while ((move = mp.next_move()) != MOVE_NONE)
if (move != excludedMove && pos.legal(move))
prevSq != SQ_NONE ? thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] : MOVE_NONE;
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &captureHistory, contHist,
- countermove, ss->killers);
+ thisThread->pawnHistory, countermove, ss->killers);
value = bestValue;
moveCountPruning = singularQuietLMR = false;
{
Piece capturedPiece = pos.piece_on(to_sq(move));
int futilityEval =
- ss->staticEval + 188 + 206 * lmrDepth + PieceValue[capturedPiece]
+ ss->staticEval + 239 + 291 * lmrDepth + PieceValue[capturedPiece]
+ captureHistory[movedPiece][to_sq(move)][type_of(capturedPiece)] / 7;
if (futilityEval < alpha)
continue;
{
int history = (*contHist[0])[movedPiece][to_sq(move)]
+ (*contHist[1])[movedPiece][to_sq(move)]
- + (*contHist[3])[movedPiece][to_sq(move)];
+ + (*contHist[3])[movedPiece][to_sq(move)]
+ + thisThread->pawnHistory[pawn_structure(pos)][movedPiece][to_sq(move)];
// Continuation history based pruning (~2 Elo)
- if (lmrDepth < 6 && history < -3232 * depth)
+ if (lmrDepth < 6 && history < -3645 * depth)
continue;
history += 2 * thisThread->mainHistory[us][from_to(move)];
- lmrDepth += history / 5793;
- lmrDepth = std::max(lmrDepth, -2);
+ lmrDepth += history / 7836;
+ lmrDepth = std::max(lmrDepth, -1);
// Futility pruning: parent node (~13 Elo)
- if (!ss->inCheck && lmrDepth < 13 && ss->staticEval + 115 + 122 * lmrDepth <= alpha)
+ if (!ss->inCheck && lmrDepth < 13 && ss->staticEval + 77 + 124 * lmrDepth <= alpha)
continue;
lmrDepth = std::max(lmrDepth, 0);
// Prune moves with negative SEE (~4 Elo)
- if (!pos.see_ge(move, Value(-27 * lmrDepth * lmrDepth)))
+ if (!pos.see_ge(move, Value(-26 * lmrDepth * lmrDepth)))
continue;
}
}
if (PvNode)
r--;
- // Decrease reduction if ttMove has been singularly extended (~1 Elo)
+ // Decrease reduction if a quiet ttMove has been singularly extended (~1 Elo)
if (singularQuietLMR)
r--;
// Step 18. Full-depth search when LMR is skipped
else if (!PvNode || moveCount > 1)
{
- // Increase reduction for cut nodes and not ttMove (~1 Elo)
+ // Increase reduction for cut nodes without ttMove (~1 Elo)
if (!ttMove && cutNode)
r += 2;
// Bonus for prior countermove that caused the fail low
else if (!priorCapture && prevSq != SQ_NONE)
{
- int bonus = (depth > 6) + (PvNode || cutNode) + (bestValue < alpha - 653)
- + ((ss - 1)->moveCount > 11);
+ int bonus = (depth > 6) + (PvNode || cutNode) + (bestValue < alpha - 657)
+ + ((ss - 1)->moveCount > 10);
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
stat_bonus(depth) * bonus);
thisThread->mainHistory[~us][from_to((ss - 1)->currentMove)]
- << stat_bonus(depth) * bonus / 2;
+ << stat_bonus(depth) * bonus * 61 / 100;
}
if (PvNode)
// will be generated.
Square prevSq = is_ok((ss - 1)->currentMove) ? to_sq((ss - 1)->currentMove) : SQ_NONE;
MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory,
- contHist, prevSq);
+ contHist, thisThread->pawnHistory, prevSq);
int quietCheckEvasions = 0;
// Increase stats for the best move in case it was a quiet move
update_quiet_stats(pos, ss, bestMove, bestMoveBonus);
+ thisThread->pawnHistory[pawn_structure(pos)][moved_piece][to_sq(bestMove)]
+ << quietMoveBonus;
// Decrease stats for all non-best quiet moves
for (int i = 0; i < quietCount; ++i)
{
+ thisThread->pawnHistory[pawn_structure(pos)][pos.moved_piece(quietsSearched[i])]
+ [to_sq(quietsSearched[i])]
+ << -bestMoveBonus;
thisThread->mainHistory[us][from_to(quietsSearched[i])] << -bestMoveBonus;
update_continuation_histories(ss, pos.moved_piece(quietsSearched[i]),
to_sq(quietsSearched[i]), -bestMoveBonus);
// Updates histories of the move pairs formed
-// by moves at ply -1, -2, -4, and -6 with current move.
+// by moves at ply -1, -2, -3, -4, and -6 with current move.
void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) {
for (int i : {1, 2, 3, 4, 6})