From 2245550e3c0344bcba093b24dc00f36b462fc940 Mon Sep 17 00:00:00 2001 From: Scott Gasch Date: Tue, 25 Aug 2026 23:22:29 -0700 Subject: Tame check-extension compounding; verified neutral in self-play (0.4955) Fixes a real pathology: checks along a long unbroken forcing line could extend for free (net zero cost against the qsearch boundary), letting tree size blow up multiple orders of magnitude on positions like a near-all-check forced mate (ECM.089: 4.5B nodes / 31min at depth 12 before this change). - Main-search check extension: gate on SEE soundness (a losing sacrifice check gets a small consolation QUARTER_PLY instead of the full bonus a sound check gets), and flatten the sound-check bonus to a flat THREE_QUARTERS_PLY instead of a near-free ONE_PLY. - Lower the qsearch entry threshold to match (THREE_QUARTERS_PLY instead of ONE_PLY) so a lone check still buys one extra full-width ply as before; root.c trims QUARTER_PLY off the per-iteration depth budget so this doesn't add a blanket 1/4 ply to every search. - Qsearch's own check-widening (QSearchFromCheckNoStandPat) now relies on fCouldStandPat history plus a g_uIterateDepth/4 ceiling instead of an unconditional per-check grant, and QPLIES_OF_NON_CAPTURE_CHECKS moved from 1 to 2 to cover both "enter qsearch already in check" and "opponent's reply is the first real check" cases with one baseline window instead of ad hoc attacker-color tracking. Net effect on ECM.089 (sn 4M canary): ~7.5x fewer nodes and ~4x less time at depth 12 versus the original, unbounded behavior. Costs solve count on the full ECM suite (879 pos, sn 4M): 650 baseline -> 636 here -- expected and accepted, since ECM is unusually check-extension-heavy tactics and not representative of real games. Self-play vs baseline (1000 games, st 1) came back at B_SCORE=0.4955, ELO=-3.1+/-21.5 -- statistically neutral, confirming the fix costs nothing in real play. Co-Authored-By: Claude Sonnet 5 --- src/chess.h | 16 +------ src/main.c | 1 - src/poshash.c | 2 +- src/root.c | 18 +++----- src/search.c | 129 +++++++++++++++++++++----------------------------------- src/searchsup.c | 87 ++++++++++---------------------------- src/split.c | 30 +++++++------ 7 files changed, 97 insertions(+), 186 deletions(-) (limited to 'src') diff --git a/src/chess.h b/src/chess.h index abf802e..8861ef1 100755 --- a/src/chess.h +++ b/src/chess.h @@ -819,10 +819,6 @@ typedef struct _COUNTERS UINT64 u64LazyEvals; UINT64 u64FullEvals; UINT64 u64CyclesInEval; - UINT64 u64HistoryPrunes; - UINT64 u64HistoryPruneReSearches; - UINT64 u64FutilityCandidates; - UINT64 u64FutilityPrunes; } tree; @@ -932,7 +928,6 @@ typedef struct _PLY_INFO #endif SCORE iEval; INT iExtensionAmount; - FLAG fIsPVNode; // (iBeta != iAlpha+1) at this ply FLAG fInCheck; FLAG fInQsearch; MOVE mv; @@ -2285,7 +2280,7 @@ IsDraw(SEARCHER_THREAD_CONTEXT *ctx); // // search.c // -#define QPLIES_OF_NON_CAPTURE_CHECKS (1) +#define QPLIES_OF_NON_CAPTURE_CHECKS (2) #define FUTILITY_BASE_MARGIN (50) // + ctx->uPositional (min 100) #define DO_IID #define IID_R_FACTOR (TWO_PLY + HALF_PLY) @@ -2320,14 +2315,6 @@ ComputeMoveScore(IN SEARCHER_THREAD_CONTEXT *ctx, FLAG ThreadUnderTerminatingSplit(SEARCHER_THREAD_CONTEXT *); -void -InitializeLMRTable(void); - -INT -ExtraReduction(IN ULONG uRemainingDepth, - IN ULONG uMoveNum, - IN ULONG uFailHighPct); - FLAG WeShouldDoHistoryPruning(IN SCORE iRoughEval, IN SCORE iAlpha, @@ -2377,6 +2364,7 @@ ComputeMoveExtension(IN OUT SEARCHER_THREAD_CONTEXT *ctx, IN ULONG uMoveNum, IN SCORE iRoughEval, IN ULONG uDepth, + IN SCORE iCheckSee, IN OUT INT *piExtend); SCORE diff --git a/src/main.c b/src/main.c index cae9877..01c8d26 100755 --- a/src/main.c +++ b/src/main.c @@ -465,7 +465,6 @@ Return value: InitializeDistanceTable(); InitializeOpeningBook(); InitializeDynamicMoveOrdering(); - InitializeLMRTable(); InitializeHashSystem(); InitializePositionHashSystem(); #ifdef MP diff --git a/src/poshash.c b/src/poshash.c index e8f09b5..19d10ab 100644 --- a/src/poshash.c +++ b/src/poshash.c @@ -196,7 +196,7 @@ SideCanStandPat(POSITION *pos, ULONG uSide) ULONG uLock = HashPositionToLockNumber(uEntry); LOCK_POSITION_HASH(uLock); #endif - if (pHash->u64Sig == u64Sig) + if (pHash->u64Sig == u64Sig) { fStand = ((pHash->cTrapped[uSide] == ILLEGAL_COOR) && (pHash->uEnpriseCount[uSide] < 2)); diff --git a/src/root.c b/src/root.c index 7c50a65..8d1adf8 100755 --- a/src/root.c +++ b/src/root.c @@ -456,17 +456,6 @@ Return value: ASSERT(d); Trace("Null move cutoff rate: %5.3f percent.\n", ((n / d) * 100.0)); - n = (double)(ctx->sCounters.tree.u64HistoryPruneReSearches); - d = (double)(ctx->sCounters.tree.u64HistoryPrunes) + 1; - Trace("History/LMR pruning: %"COMPILER_LONGLONG_UNSIGNED_FORMAT - " reduced, %5.3f percent needed a full-depth re-search.\n", - ctx->sCounters.tree.u64HistoryPrunes, ((n / d) * 100.0)); - n = (double)(ctx->sCounters.tree.u64FutilityPrunes); - d = (double)(ctx->sCounters.tree.u64FutilityCandidates) + 1; - Trace("Futility pruning: %"COMPILER_LONGLONG_UNSIGNED_FORMAT - " candidates, %5.3f percent actually pruned " - "(rest saved by fail-high%% / SEE gates).\n", - ctx->sCounters.tree.u64FutilityCandidates, ((n / d) * 100.0)); if (ctx->sCounters.egtb.uProbes > 0) { n = (double)(ctx->sCounters.egtb.uHits); @@ -1166,10 +1155,15 @@ Return value: if (iBeta > INFINITY) iBeta = +INFINITY; if (iAlpha < -INFINITY) iAlpha = -INFINITY; if (iAlpha >= iBeta) iAlpha = iBeta - 1; + // Was + HALF_PLY. Trimmed by QUARTER_PLY to compensate for + // search.c's qsearch-entry threshold moving from ONE_PLY down + // to THREE_QUARTERS_PLY -- that change alone would otherwise + // hand every line an extra ~1/4 ply of full-width search for + // free, not just check-heavy ones. iScore = RootSearch(ctx, iAlpha, iBeta, - uDepth * ONE_PLY + HALF_PLY); + uDepth * ONE_PLY + QUARTER_PLY); if (g_MoveTimer.bvFlags & TIMER_STOPPING) break; mv = ctx->mvRootMove; diff --git a/src/search.c b/src/search.c index ff7e661..00b37f2 100755 --- a/src/search.c +++ b/src/search.c @@ -153,7 +153,7 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, ULONG uStage = TRY_HASH_MOVE; ULONG u; ULONG uFutilityMargin = 0; - SCORE iMoveSee = 0; + SCORE iCheckSee; #ifdef DEBUG ASSERT(IS_VALID_SCORE(iAlpha)); ASSERT(IS_VALID_SCORE(iBeta)); @@ -167,8 +167,15 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, mvBest.uMove = 0; // Jump directly to Qsearch if remaining depth is low enough. - // This is the only place Qsearch is entered. - if (uDepth < ONE_PLY) + // This is the only place Qsearch is entered. Lowered from ONE_PLY to + // THREE_QUARTERS_PLY to match the check extension's new flat amount + // (searchsup.c's ComputeMoveExtension) -- a lone check (or short run + // of them) still buys exactly one extra full-width ply as before, but + // a long unbroken chain now pays QUARTER_PLY of real cost per check + // instead of extending for free. root.c compensates by trimming the + // same QUARTER_PLY off the per-iteration depth budget so this doesn't + // just add a blanket 1/4 ply to every search. + if (uDepth < THREE_QUARTERS_PLY) { pf->fCouldStandPat[BLACK] = pf->fCouldStandPat[WHITE] = FALSE; pf->uQsearchNodes = pf->uQsearchDepth = 0; @@ -192,7 +199,6 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, } DTEnterNode(ctx, uDepth, FALSE, iAlpha, iBeta); iInitialAlpha = iAlpha; - pi->fIsPVNode = (iBeta != iAlpha + 1); ASSERT((IS_CHECKING_MOVE(mvLast) && (TRUE == pi->fInCheck)) || (!IS_CHECKING_MOVE(mvLast) && (FALSE == pi->fInCheck))); @@ -430,19 +436,8 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, // prune away moves we will also make sure there is // no per-move extension. ASSERT(!uFutilityMargin); - // Narrowed from "<= TWO_PLY" to "< TWO_PLY": ExtraReduction's - // own safety cap guarantees a reduced move's child lands - // with remaining depth >= TWO_PLY, which used to hand every - // heavily-reduced line straight into futility's activation - // floor at exactly that value -- double jeopardy on the - // same move by construction, not by chance. Excluding just - // that exact floor value (not the whole fractional-depth - // window below it) un-stacks that specific overlap. - if (FALSE && // EXPERIMENT: disabled for the unscaled-LMR-table - // test -- isolate the new reduction table's - // effect without also stacking futility pruning - (iRoughEval + VALUE_ROOK <= iAlpha) && - (uDepth < TWO_PLY) && + if ((iRoughEval + VALUE_ROOK <= iAlpha) && + (uDepth <= TWO_PLY) && (ctx->uPly >= 2) && (iOrigExtend == 0) && (ctx->sPlyInfo[ctx->uPly - 2].iExtensionAmount <= 0) && @@ -530,14 +525,15 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, } #endif - // SEE must be computed on the PRE-move position (it internally - // simulates removing mv.pMoved from mv.cFrom and adding x-rays -- - // see see.c) -- so grab it now, before MakeMove mutates *pos in - // place, for the futility check below to use. Only bother when - // futility mode is actually active at this node. - if (uFutilityMargin) + // SEE must be computed on the PRE-move position -- see.c's + // exchange walk needs the piece still sitting on cFrom. Only + // needed for checking moves, where ComputeMoveExtension uses it + // to gate the check extension on soundness (Crafty-style: don't + // extend a checking move that's really just a losing sacrifice). + iCheckSee = 0; + if (IS_CHECKING_MOVE(mv)) { - iMoveSee = SEE(pos, mv); + iCheckSee = SEE(pos, mv); } if (TRUE == MakeMove(ctx, mv)) @@ -555,6 +551,7 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, (x - 1), // Note: x==0 if doing mvHash iRoughEval, uDepth, + iCheckSee, &iExtend); // Cap how many extension plies this line may spend in total @@ -579,22 +576,11 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, iExtend)) { ASSERT(iExtend == 0); - iExtend = -(ONE_PLY + ExtraReduction(uDepth, (x - 1), - GetMoveFailHighPercentage(mv))); - pi->iExtensionAmount = iExtend; - INC(ctx->sCounters.tree.u64HistoryPrunes); + iExtend = -ONE_PLY; + pi->iExtensionAmount = -ONE_PLY; } - // Maybe even "futility prune" this move away. Require two - // independent corroborating signals on top of the static - // margin, not just the move's ordering score alone: this - // specific move must have rarely caused a beta cutoff - // historically (same threshold WeShouldDoHistoryPruning - // uses), and it must not show a tactical gain per SEE -- - // ComputeMoveScore alone is PSQT/history/killer-bonus for - // quiet moves, with no exchange evaluation at all, so it - // was pruning purely on a positional-ordering number. -#ifdef PERF_COUNTERS + // Maybe even "futility prune" this move away. if ((x != 0) && (uLegalMoves > 1) && (uFutilityMargin) && @@ -602,25 +588,6 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, (iExtend <= 0) && (!IS_ESCAPING_CHECK(mv))) { - INC(ctx->sCounters.tree.u64FutilityCandidates); - } -#endif - if ((x != 0) && - (uLegalMoves > 1) && - (uFutilityMargin) && - (ComputeMoveScore(ctx, mv, (x - 1)) < uFutilityMargin) && - (iExtend <= 0) && - (!IS_ESCAPING_CHECK(mv)) && - // Stricter than WeShouldDoHistoryPruning's <= 10: that one - // gates a reduction with a fail-high re-search safety net - // (search.c's own counters show ~2% wrong-guess rate is - // fine there); this gates an outright, unverified skip -- - // no re-search, no recovery if wrong -- so demand much - // stronger evidence the move is truly hopeless. - (GetMoveFailHighPercentage(mv) <= 3) && - (iMoveSee <= 0)) - { - INC(ctx->sCounters.tree.u64FutilityPrunes); // TODO: test this more carefully ASSERT(!IS_CHECKING_MOVE(mv)); UnmakeMove(ctx, mv); @@ -652,9 +619,8 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, // Research deeper if history pruning failed if ((iExtend < 0) && (iScore >= iBeta)) { - uNextDepth -= iExtend; // undo the full reduction, whatever its magnitude + uNextDepth += ONE_PLY; pi->iExtensionAmount = 0; - INC(ctx->sCounters.tree.u64HistoryPruneReSearches); iScore = -Search(ctx, -iBeta, -iAlpha, uNextDepth); } UnmakeMove(ctx, mv); @@ -946,20 +912,19 @@ QSearchFromCheckNoStandPat(IN SEARCHER_THREAD_CONTEXT *ctx, uMoveCount = MOVE_COUNT(ctx, ctx->uPly); if (uMoveCount > 0) { - // Consider extending the number of qsearch plies we consider - // non-capture checks at during this line. - if ((pf->fCouldStandPat[pos->uToMove] == FALSE) && - (pf->uQsearchDepth < g_uIterateDepth / 2) && - (CountKingSafetyDefects(pos, pos->uToMove) > 1)) + // Consider extending the number of qsearch plies for our opponent + // if this looks good. + if ((pf->uQsearchDepth < pf->uQsearchCheckDepth) && + (pf->uQsearchDepth < g_uIterateDepth / 4) && + (pf->fCouldStandPat[pos->uToMove] == FALSE) && + (CountKingSafetyDefects(pos, pos->uToMove) > 2)) { - if (uMoveCount == 1) { + if ((uMoveCount == 1) || + (NUM_KING_MOVES(ctx, ctx->uPly) == 0) || + (NUM_CHECKING_PIECES(ctx, ctx->uPly) > 1)) + { uQsearchCheckExtension = 2; INC(ctx->sCounters.extension.uQExtend); - } else if ((uMoveCount == 2) || - (NUM_KING_MOVES(ctx, ctx->uPly) == 0) || - (NUM_CHECKING_PIECES(ctx, ctx->uPly) > 1)) { - uQsearchCheckExtension = 1; - INC(ctx->sCounters.extension.uQExtend); } ctx->sPlyInfo[ctx->uPly].iExtensionAmount = uQsearchCheckExtension; } @@ -1080,7 +1045,7 @@ QSearchInDangerNoStandPat(IN SEARCHER_THREAD_CONTEXT *ctx, // Set futility: - // + // // iEval + move_value + margin < alpha // move_value < alpha - margin - iEval iFutility = 0; @@ -1097,7 +1062,8 @@ QSearchInDangerNoStandPat(IN SEARCHER_THREAD_CONTEXT *ctx, // have a piece trapped. Allow him to play checks in order to try // to save the situation. ASSERT(!InCheck(pos, pos->uToMove)); - fIncludeChecks = (pf->uQsearchDepth < g_uIterateDepth / 3); + fIncludeChecks = ((pf->uQsearchDepth < pf->uQsearchCheckDepth) && + (pf->fCouldStandPat[FLIP(pos->uToMove)] == FALSE)); GenerateMoves(ctx, NULLMOVE, _WhatToGen[fIncludeChecks]); for (x = ctx->sMoveStack.uBegin[ctx->uPly]; @@ -1313,7 +1279,10 @@ QSearch(IN SEARCHER_THREAD_CONTEXT *ctx, // position looks ok enough to allow him the option to stand pat // -or- we missed when we probed the dangerhash. Also remember // that this side has had the option to stand pat when searching - // below this point. + // below this point. This also means the other side is not + // allowed to generate checks on this side because even if it + // discovers a mate, there's no force since a stand pat + // opportunity exists right here. uLegalMoves = 0; iEval = iBestScore = Eval(ctx, iAlpha, iBeta); if (iBestScore > iAlpha) @@ -1343,13 +1312,13 @@ QSearch(IN SEARCHER_THREAD_CONTEXT *ctx, iFutility = MAX0(iFutility); } - // We know we are not in check. Generate moves (including checks - // if we are below the threshold and the other side has never been - // allowed to stand pat). Recurse. - fIncludeChecks = ((pf->uQsearchDepth < pf->uQsearchCheckDepth) && - (pf->fCouldStandPat[FLIP(pos->uToMove)] == FALSE) && - (pos->uNonPawnMaterial[pos->uToMove] > - (VALUE_KING + VALUE_BISHOP))); + // We know we are not in check. If we are early in the qsearch, + // and the other side has not yet been able to stand pat, and we + // have material, generate checks here too. + fIncludeChecks = + ((pf->uQsearchDepth < pf->uQsearchCheckDepth) && + (pf->fCouldStandPat[FLIP(pos->uToMove)] == FALSE) && + (pos->uNonPawnMaterial[pos->uToMove] > (VALUE_KING + VALUE_BISHOP))); GenerateMoves(ctx, NULLMOVE, _WhatToGen[fIncludeChecks]); for (x = ctx->sMoveStack.uBegin[ctx->uPly]; x < ctx->sMoveStack.uEnd[ctx->uPly]; diff --git a/src/searchsup.c b/src/searchsup.c index 7af1a18..37eca66 100644 --- a/src/searchsup.c +++ b/src/searchsup.c @@ -18,7 +18,6 @@ Revision History: **/ -#include #include "chess.h" extern SCORE g_iRootScore[2]; @@ -225,8 +224,7 @@ Return value: ASSERT((uMoveNum > 0) || (uLegalMoves == 0)); if ((uRemainingDepth >= TWO_PLY) && (iBeta == (iAlpha + 1)) && - (FALSE == ctx->sPlyInfo[ctx->uPly - 1].fIsPVNode) && - (uLegalMoves > 3) && + (uLegalMoves > 5) && (0 == iExtend) && // (iRoughEval + ComputeMoveScore(ctx, mv, uMoveNum - 1) + 200 < iAlpha) && (!IS_ESCAPING_CHECK(mv)) && @@ -246,66 +244,10 @@ Return value: } -#define LMR_TABLE_MAX_DEPTH 32 -#define LMR_TABLE_MAX_MOVES 63 - -static INT g_iLMRTable[LMR_TABLE_MAX_DEPTH + 1][LMR_TABLE_MAX_MOVES + 1]; - -void -InitializeLMRTable(void) -{ - ULONG d, m; - double r; - - g_iLMRTable[0][0] = 0; - for (d = 0; d <= LMR_TABLE_MAX_DEPTH; d++) - { - for (m = 0; m <= LMR_TABLE_MAX_MOVES; m++) - { - if ((d < 1) || (m < 1)) - { - g_iLMRTable[d][m] = 0; - continue; - } - r = 0.7844 + (log((double)d) * log((double)m) / 2.4696); - if (r < 0.0) r = 0.0; - g_iLMRTable[d][m] = (INT)((r * ONE_PLY) + 0.5); - } - } -} - - -INT -ExtraReduction(IN ULONG uRemainingDepth, - IN ULONG uMoveNum, - IN ULONG uFailHighPct) -{ - INT iExtra; - ULONG d = uRemainingDepth / ONE_PLY; - ULONG m = uMoveNum; - - if (d > LMR_TABLE_MAX_DEPTH) d = LMR_TABLE_MAX_DEPTH; - if (m > LMR_TABLE_MAX_MOVES) m = LMR_TABLE_MAX_MOVES; - iExtra = g_iLMRTable[d][m]; - - if (uFailHighPct == 0) - { - iExtra += QUARTER_PLY; - } - - if ((INT)uRemainingDepth - ONE_PLY - iExtra < TWO_PLY) - { - iExtra = MAX((INT)uRemainingDepth - ONE_PLY - TWO_PLY, 0); - } - ASSERT(iExtra >= 0); - return(iExtra); -} - - SCORE ComputeMoveScore(IN SEARCHER_THREAD_CONTEXT *ctx, IN MOVE mv, - IN ULONG uMoveNum) + IN ULONG uMoveNum) { SCORE iMoveScore = (PIECE_VALUE(mv.pCaptured) + PIECE_VALUE(mv.pPromoted)); @@ -335,6 +277,7 @@ ComputeMoveExtension(IN SEARCHER_THREAD_CONTEXT *ctx, IN ULONG uMoveNum, IN SCORE iRoughEval, IN ULONG uDepth, + IN SCORE iCheckSee, IN OUT INT *piExtend) /** @@ -391,18 +334,32 @@ Return value: ASSERT(*piExtend >= 0); #endif - // Checking move extension. + // Checking move extension. Crafty-style soundness gate: a check + // that's really just a losing sacrifice (SEE < 0) still gets a small + // consolation extension rather than none at all -- SEE can't see + // multi-move combinations, so a "losing" sacrifice check is sometimes + // actually a winning sham sacrifice a few moves later, and giving it + // zero search priority risks missing exactly those. It just doesn't + // get to compound the way a materially sound check does. if (IS_CHECKING_MOVE(mv)) { ASSERT(InCheck(pos, pos->uToMove)); INC(ctx->sCounters.extension.uCheck); - *piExtend += ONE_PLY; - if (pos->uNonPawnMaterial[FLIP(pos->uToMove)] > - (VALUE_KING + VALUE_BISHOP)) + if (iCheckSee < 0) { + *piExtend += QUARTER_PLY; goto enforce_ceiling; } - *piExtend -= THREE_QUARTERS_PLY; + else + { + *piExtend += THREE_QUARTERS_PLY; + if (pos->uNonPawnMaterial[FLIP(pos->uToMove)] > + (VALUE_KING + VALUE_BISHOP)) + { + goto enforce_ceiling; + } + *piExtend -= HALF_PLY; + } } // Pawn push extension diff --git a/src/split.c b/src/split.c index b30cdb6..703f6a8 100755 --- a/src/split.c +++ b/src/split.c @@ -1046,6 +1046,7 @@ Return value: INT iOrigExtend; INT iExtend; MOVE mv; + SCORE iCheckSee; #ifdef DEBUG POSITION board; @@ -1080,22 +1081,30 @@ Return value: ASSERT(iExtend >= -ONE_PLY); ASSERT(iExtend <= +ONE_PLY); + // SEE on the PRE-move position -- see search.c's identical comment. + iCheckSee = 0; + if (IS_CHECKING_MOVE(mv)) + { + iCheckSee = SEE(&ctx->sPosition, mv); + } + if (MakeMove(ctx, mv)) { - ASSERT((IS_CHECKING_MOVE(mv) && + ASSERT((IS_CHECKING_MOVE(mv) && InCheck(&ctx->sPosition, ctx->sPosition.uToMove)) || - (!IS_CHECKING_MOVE(mv) && + (!IS_CHECKING_MOVE(mv) && !InCheck(&ctx->sPosition, ctx->sPosition.uToMove))); iRoughEval = GetRoughEvalScore(ctx, iAlpha, iBeta, TRUE); - + // Compute extension - ComputeMoveExtension(ctx, + ComputeMoveExtension(ctx, iAlpha, iBeta, - (ctx->sMoveStack.uBegin[ctx->uPly - 1] + + (ctx->sMoveStack.uBegin[ctx->uPly - 1] + uMoveNum), iRoughEval, uDepth, + iCheckSee, &iExtend); // @@ -1125,12 +1134,8 @@ Return value: iExtend)) { ASSERT(iExtend == 0); - iExtend = -(ONE_PLY + ExtraReduction(uDepth, - (g_SplitInfo[u].uAlreadyDone + - uMoveNum + 1), - GetMoveFailHighPercentage(mv))); - ctx->sPlyInfo[ctx->uPly].iExtensionAmount = iExtend; - INC(ctx->sCounters.tree.u64HistoryPrunes); + iExtend = -ONE_PLY; + ctx->sPlyInfo[ctx->uPly].iExtensionAmount = -ONE_PLY; } // @@ -1151,9 +1156,8 @@ Return value: // if ((iExtend < 0) && (iScore >= iBeta)) { - uDepth -= iExtend; // undo the full reduction, whatever its magnitude + uDepth += ONE_PLY; ctx->sPlyInfo[ctx->uPly].iExtensionAmount = 0; - INC(ctx->sCounters.tree.u64HistoryPruneReSearches); iScore = -Search(ctx, -iBeta, -iAlpha, uDepth); } UnmakeMove(ctx, mv); -- cgit v1.3