// History and stats update bonus, based on depth
int stat_bonus(Depth d) {
- return std::min((9 * d + 270) * d - 311 , 2145);
+ return std::min((8 * d + 240) * d - 276 , 1907);
}
// Add a small random component to draw evaluations to avoid 3-fold blindness
multiPV = std::min(multiPV, rootMoves.size());
- complexityAverage.set(202, 1);
+ complexityAverage.set(174, 1);
trend = SCORE_ZERO;
optimism[ us] = Value(39);
int failedHighCnt = 0;
while (true)
{
- Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - searchAgainCounter);
+ // Adjust the effective depth searched, but ensuring at least one effective increment for every
+ // four searchAgain steps (see issue #2717).
+ Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - 3 * (searchAgainCounter + 1) / 4);
bestValue = Stockfish::search<Root>(rootPos, ss, alpha, beta, adjustedDepth, false);
// Bring the best move to the front. It is critical that sorting
double reduction = (1.56 + mainThread->previousTimeReduction) / (2.20 * timeReduction);
double bestMoveInstability = 1 + 1.7 * totBestMoveChanges / Threads.size();
int complexity = mainThread->complexityAverage.value();
- double complexPosition = std::clamp(1.0 + (complexity - 326) / 1618.1, 0.5, 1.5);
+ double complexPosition = std::min(1.0 + (complexity - 277) / 1819.1, 1.5);
double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition;
// At non-PV nodes we check for an early TT cutoff
if ( !PvNode
&& ss->ttHit
- && tte->depth() > depth - ((int)thisThread->id() & 0x1)
+ && tte->depth() > depth - ((int)thisThread->id() & 0x1) - (tte->bound() == BOUND_EXACT)
&& ttValue != VALUE_NONE // Possible in case of TT access race
&& (tte->bound() & (ttValue >= beta ? BOUND_LOWER : BOUND_UPPER)))
{
// Never assume anything about values stored in TT
ss->staticEval = eval = tte->eval();
if (eval == VALUE_NONE)
- ss->staticEval = eval = evaluate(pos);
+ ss->staticEval = eval = evaluate(pos, &complexity);
+ else // Fall back to (semi)classical complexity for TT hits, the NNUE complexity is lost
+ complexity = abs(ss->staticEval - pos.psq_eg_stm());
// Randomize draw evaluation
if (eval == VALUE_DRAW)
}
else
{
- ss->staticEval = eval = evaluate(pos);
+ ss->staticEval = eval = evaluate(pos, &complexity);
// Save static evaluation into transposition table
if (!excludedMove)
tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval);
}
+ thisThread->complexityAverage.update(complexity);
+
// Use static evaluation difference to improve quiet move ordering (~3 Elo)
if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture)
{
improvement = (ss-2)->staticEval != VALUE_NONE ? ss->staticEval - (ss-2)->staticEval
: (ss-4)->staticEval != VALUE_NONE ? ss->staticEval - (ss-4)->staticEval
: 175;
-
improving = improvement > 0;
- complexity = abs(ss->staticEval - (us == WHITE ? eg_value(pos.psq_score()) : -eg_value(pos.psq_score())));
-
- thisThread->complexityAverage.update(complexity);
// Step 7. Razoring.
// If eval is really low check with qsearch if it can exceed alpha, if it can't,
&& (ss-1)->statScore < 14695
&& eval >= beta
&& eval >= ss->staticEval
- && ss->staticEval >= beta - 15 * depth - improvement / 15 + 198 + complexity / 28
+ && ss->staticEval >= beta - 15 * depth - improvement / 15 + 201 + complexity / 24
&& !excludedMove
&& pos.non_pawn_material(us)
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
assert(eval - beta >= 0);
// Null move dynamic reduction based on depth, eval and complexity of position
- Depth R = std::min(int(eval - beta) / 147, 5) + depth / 3 + 4 - (complexity > 753);
+ Depth R = std::min(int(eval - beta) / 147, 5) + depth / 3 + 4 - (complexity > 650);
ss->currentMove = MOVE_NULL;
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
assert(probCutBeta < VALUE_INFINITE);
MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, depth - 3, &captureHistory);
- bool ttPv = ss->ttPv;
- ss->ttPv = false;
while ((move = mp.next_move()) != MOVE_NONE)
if (move != excludedMove && pos.legal(move))
if (value >= probCutBeta)
{
// Save ProbCut data into transposition table
- tte->save(posKey, value_to_tt(value, ss->ply), ttPv, BOUND_LOWER, depth - 3, move, ss->staticEval);
+ tte->save(posKey, value_to_tt(value, ss->ply), ss->ttPv, BOUND_LOWER, depth - 3, move, ss->staticEval);
return value;
}
}
- ss->ttPv = ttPv;
}
// Step 11. If the position is not in TT, decrease depth by 3.
&& history < -3875 * (depth - 1))
continue;
- history += thisThread->mainHistory[us][from_to(move)];
+ history += 2 * thisThread->mainHistory[us][from_to(move)];
// Futility pruning: parent node (~9 Elo)
if ( !ss->inCheck
r--;
// Increase reduction for cut nodes (~3 Elo)
- if (cutNode && move != ss->killers[0])
+ if (cutNode)
r += 2;
// Increase reduction if ttMove is a capture (~3 Elo)
if ((ss+1)->cutoffCnt > 3 && !PvNode)
r++;
- ss->statScore = thisThread->mainHistory[us][from_to(move)]
+ ss->statScore = 2 * thisThread->mainHistory[us][from_to(move)]
+ (*contHist[0])[movedPiece][to_sq(move)]
+ (*contHist[1])[movedPiece][to_sq(move)]
+ (*contHist[3])[movedPiece][to_sq(move)]
// Decrease/increase reduction for moves with a good/bad history (~30 Elo)
r -= ss->statScore / 15914;
- // In general we want to cap the LMR depth search at newDepth. But if reductions
- // are really negative and movecount is low, we allow this move to be searched
- // deeper than the first move (this may lead to hidden double extensions).
- int deeper = r >= -1 ? 0
- : moveCount <= 4 ? 2
- : PvNode || cutNode ? 1
- : 0;
-
- Depth d = std::clamp(newDepth - r, 1, newDepth + deeper);
+ // In general we want to cap the LMR depth search at newDepth, but when
+ // reduction is negative, we allow this move a limited search extension
+ // beyond the first move depth. This may lead to hidden double extensions.
+ Depth d = std::clamp(newDepth - r, 1, newDepth + 1);
value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, true);