summaryrefslogtreecommitdiff
path: root/src/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/search.c')
-rwxr-xr-xsrc/search.c66
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);