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)
&& !Threads.stop
&& !mainThread->stopOnPonderhit)
{
- double fallingEval = (318 + 6 * (mainThread->bestPreviousScore - bestValue)
- + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 825.0;
+ double fallingEval = (142 + 12 * (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
Depth extension, newDepth;
Value bestValue, value, ttValue, eval, maxValue, probCutBeta;
bool givesCheck, improving, didLMR, priorCapture;
- bool captureOrPromotion, doFullDepthSearch, moveCountPruning,
- ttCapture, singularQuietLMR;
+ bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture;
Piece movedPiece;
int moveCount, captureCount, quietCount, bestMoveCount, improvement;
ss->ply);
value = bestValue;
- singularQuietLMR = moveCountPruning = false;
+ moveCountPruning = false;
// Indicate PvNodes that will probably fail low if the node was searched
// at a depth equal or greater than the current depth, and the result of this search was a fail low.
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
// a reduced search 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 ( !rootNode
- && depth >= 7
+ && depth >= 6 + 2 * (PvNode && tte->is_pv())
&& move == ttMove
&& !excludedMove // Avoid recursive singular search
/* && ttValue != VALUE_NONE Already implicit in the next condition */
if (value < singularBeta)
{
extension = 1;
- singularQuietLMR = !ttCapture;
// Avoid search explosion by limiting the number of double extensions
if ( !PvNode
// Step 15. Make the move
pos.do_move(move, st, givesCheck);
+ bool doDeeperSearch = false;
+
// Step 16. Late moves reduction / extension (LMR, ~200 Elo)
// We use various heuristics for the sons of a node after the first son has
// been searched. In general we would like to reduce them, but there are many
&& !likelyFailLow)
r -= 2;
- // Increase reduction at non-PV nodes when the best move does not change frequently
- if ( !PvNode
- && thisThread->bestMoveChanges <= 2)
+ // Increase reduction at non-PV nodes (~3 Elo)
+ if (!PvNode)
r++;
// Decrease reduction if opponent's move count is high (~1 Elo)
if ((ss-1)->moveCount > 13)
r--;
- // Decrease reduction if ttMove has been singularly extended (~1 Elo)
- if (singularQuietLMR)
- r--;
-
// Increase reduction for cut nodes (~3 Elo)
if (cutNode && move != ss->killers[0])
r += 2;
// If the son is reduced and fails high it will be re-searched at full depth
doFullDepthSearch = value > alpha && d < newDepth;
+ doDeeperSearch = value > alpha + 88;
didLMR = true;
}
else
// Step 17. Full depth search when LMR is skipped or fails high
if (doFullDepthSearch)
{
- value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode);
+ value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth + doDeeperSearch, !cutNode);
// If the move passed LMR update its stats
if (didLMR && !captureOrPromotion)
// Bonus for prior countermove that caused the fail low
else if ( (depth >= 3 || PvNode)
&& !priorCapture)
- update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + (PvNode || cutNode)));
+ {
+ //Assign extra bonus if current node is PvNode or cutNode
+ //or fail low was really bad
+ bool extraBonus = PvNode
+ || cutNode
+ || bestValue < alpha - 94 * depth;
+
+ update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus));
+ }
if (PvNode)
bestValue = std::min(bestValue, maxValue);