bestThread = Threads.get_best_thread();
bestPreviousScore = bestThread->rootMoves[0].score;
+ bestPreviousAverageScore = bestThread->rootMoves[0].averageScore;
// Send again PV info if we have a new best thread
if (bestThread != this)
// The latter is needed for statScore and killer initialization.
Stack stack[MAX_PLY+10], *ss = stack+7;
Move pv[MAX_PLY+1];
- Value bestValue, alpha, beta, delta;
+ Value alpha, beta, delta;
Move lastBestMove = MOVE_NONE;
Depth lastBestMoveDepth = 0;
MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr);
nodesLastExplosive = nodes;
nodesLastNormal = nodes;
- state = EXPLOSION_NONE;
- trend = SCORE_ZERO;
+ state = EXPLOSION_NONE;
+ trend = SCORE_ZERO;
+ optimism[ us] = Value(25);
+ optimism[~us] = -optimism[us];
int searchAgainCounter = 0;
// Reset aspiration window starting size
if (rootDepth >= 4)
{
- Value prev = rootMoves[pvIdx].previousScore;
+ Value prev = rootMoves[pvIdx].averageScore;
delta = Value(17) + int(prev) * prev / 16384;
alpha = std::max(prev - delta,-VALUE_INFINITE);
beta = std::min(prev + delta, VALUE_INFINITE);
- // Adjust trend based on root move's previousScore (dynamic contempt)
- int tr = 113 * prev / (abs(prev) + 147);
-
+ // Adjust trend and optimism based on root move's previousScore
+ int tr = sigmoid(prev, 0, 0, 147, 113, 1);
trend = (us == WHITE ? make_score(tr, tr / 2)
: -make_score(tr, tr / 2));
+
+ int opt = sigmoid(prev, 0, 25, 147, 14464, 256);
+ optimism[ us] = Value(opt);
+ optimism[~us] = -optimism[us];
}
// Start with a small aspiration window and, in the case of a fail
if (skill.enabled() && skill.time_to_pick(rootDepth))
skill.pick_best(multiPV);
+ // Use part of the gained time from a previous stable move for the current move
+ for (Thread* th : Threads)
+ {
+ totBestMoveChanges += th->bestMoveChanges;
+ th->bestMoveChanges = 0;
+ }
+
// Do we have time for the next iteration? Can we stop searching now?
if ( Limits.use_time_management()
&& !Threads.stop
&& !mainThread->stopOnPonderhit)
{
- double fallingEval = (318 + 6 * (mainThread->bestPreviousScore - bestValue)
+ double fallingEval = (142 + 6 * (mainThread->bestPreviousScore - bestValue)
+ + 6 * (mainThread->bestPreviousAverageScore - bestValue)
+ 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 825.0;
fallingEval = std::clamp(fallingEval, 0.5, 1.5);
// If the bestMove is stable over several iterations, reduce time accordingly
timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.92 : 0.95;
double reduction = (1.47 + mainThread->previousTimeReduction) / (2.32 * timeReduction);
-
- // Use part of the gained time from a previous stable move for the current move
- for (Thread* th : Threads)
- {
- totBestMoveChanges += th->bestMoveChanges;
- th->bestMoveChanges = 0;
- }
double bestMoveInstability = 1.073 + std::max(1.0, 2.25 - 9.9 / rootDepth)
* totBestMoveChanges / Threads.size();
double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability;
// Use static evaluation difference to improve quiet move ordering
if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture)
{
- int bonus = std::clamp(-depth * 4 * int((ss-1)->staticEval + ss->staticEval), -1000, 1000);
+ int bonus = std::clamp(-16 * int((ss-1)->staticEval + ss->staticEval), -2000, 2000);
thisThread->mainHistory[~us][from_to((ss-1)->currentMove)] << bonus;
}
// Step 7. Futility pruning: child node (~50 Elo).
// The depth condition is important for mate finding.
- if ( !PvNode
+ if ( !ss->ttPv
&& depth < 9
&& eval - futility_margin(depth, improving) >= beta
&& eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins.
}
else
{
+ int history = (*contHist[0])[movedPiece][to_sq(move)]
+ + (*contHist[1])[movedPiece][to_sq(move)]
+ + (*contHist[3])[movedPiece][to_sq(move)];
+
// Continuation history based pruning (~20 Elo)
- if (lmrDepth < 5
- && (*contHist[0])[movedPiece][to_sq(move)]
- + (*contHist[1])[movedPiece][to_sq(move)]
- + (*contHist[3])[movedPiece][to_sq(move)] < -3000 * depth + 3000)
+ if ( lmrDepth < 5
+ && history < -3000 * depth + 3000)
continue;
+ history += thisThread->mainHistory[us][from_to(move)];
+
+ lmrDepth = std::max(0, lmrDepth - (beta - alpha < thisThread->rootDelta / 4));
+
// Futility pruning: parent node (~5 Elo)
if ( !ss->inCheck
&& lmrDepth < 8
- && ss->staticEval + 172 + 145 * lmrDepth <= alpha)
+ && ss->staticEval + 142 + 139 * lmrDepth + history / 64 <= alpha)
continue;
// Prune moves with negative SEE (~20 Elo)
{
Depth r = reduction(improving, depth, moveCount, rangeReduction > 2);
- // Decrease reduction if on the PV (~2 Elo)
+ // Decrease reduction at some PvNodes (~2 Elo)
if ( PvNode
- && bestMoveCount <= 3)
+ && bestMoveCount <= 3
+ && beta - alpha >= thisThread->rootDelta / 4)
r--;
- // Increases reduction for PvNodes that have small window
- if (PvNode && beta - alpha < thisThread->rootDelta / 4)
- r++;
-
// Decrease reduction if position is or has been on the PV
// and node is not likely to fail low. (~3 Elo)
if ( ss->ttPv
&& !likelyFailLow)
r -= 2;
- // Increase reduction at root and non-PV nodes when the best move does not change frequently
- if ( (rootNode || !PvNode)
- && thisThread->bestMoveChanges <= 2)
+ // Increase reduction at non-PV nodes
+ if (!PvNode)
r++;
// Decrease reduction if opponent's move count is high (~1 Elo)
RootMove& rm = *std::find(thisThread->rootMoves.begin(),
thisThread->rootMoves.end(), move);
+ rm.averageScore = rm.averageScore != -VALUE_INFINITE ? (2 * value + rm.averageScore) / 3 : value;
+
// PV move or new best move?
if (moveCount == 1 || value > alpha)
{
thisThread->mainHistory[us][from_to(move)] << bonus;
update_continuation_histories(ss, pos.moved_piece(move), to_sq(move), bonus);
- // Penalty for reversed move in case of moved piece not being a pawn
- if (type_of(pos.moved_piece(move)) != PAWN)
- thisThread->mainHistory[us][from_to(reverse_move(move))] << -bonus;
-
// Update countermove history
if (is_ok((ss-1)->currentMove))
{