diff options
Diffstat (limited to 'src/search.c')
| -rwxr-xr-x | src/search.c | 66 |
1 files changed, 60 insertions, 6 deletions
diff --git a/src/search.c b/src/search.c index 29bbc66..ff7e661 100755 --- a/src/search.c +++ b/src/search.c @@ -153,6 +153,7 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, ULONG uStage = TRY_HASH_MOVE; ULONG u; ULONG uFutilityMargin = 0; + SCORE iMoveSee = 0; #ifdef DEBUG ASSERT(IS_VALID_SCORE(iAlpha)); ASSERT(IS_VALID_SCORE(iBeta)); @@ -191,6 +192,7 @@ 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))); @@ -428,8 +430,19 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, // prune away moves we will also make sure there is // no per-move extension. ASSERT(!uFutilityMargin); - if ((iRoughEval + VALUE_ROOK <= iAlpha) && - (uDepth <= TWO_PLY) && + // 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) && (ctx->uPly >= 2) && (iOrigExtend == 0) && (ctx->sPlyInfo[ctx->uPly - 2].iExtensionAmount <= 0) && @@ -517,6 +530,16 @@ 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) + { + iMoveSee = SEE(pos, mv); + } + if (TRUE == MakeMove(ctx, mv)) { uLegalMoves++; @@ -556,11 +579,22 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, iExtend)) { ASSERT(iExtend == 0); - iExtend = -ONE_PLY; - pi->iExtensionAmount = -ONE_PLY; + iExtend = -(ONE_PLY + ExtraReduction(uDepth, (x - 1), + GetMoveFailHighPercentage(mv))); + pi->iExtensionAmount = iExtend; + INC(ctx->sCounters.tree.u64HistoryPrunes); } - // Maybe even "futility prune" this move away. + // 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 if ((x != 0) && (uLegalMoves > 1) && (uFutilityMargin) && @@ -568,6 +602,25 @@ 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); @@ -599,8 +652,9 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, // Research deeper if history pruning failed if ((iExtend < 0) && (iScore >= iBeta)) { - uNextDepth += ONE_PLY; + uNextDepth -= iExtend; // undo the full reduction, whatever its magnitude pi->iExtensionAmount = 0; + INC(ctx->sCounters.tree.u64HistoryPruneReSearches); iScore = -Search(ctx, -iBeta, -iAlpha, uNextDepth); } UnmakeMove(ctx, mv); |
