summaryrefslogtreecommitdiff
path: root/src/search.c
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-09-15 23:17:33 -0700
committerScott Gasch <[email protected]>2026-09-15 23:17:33 -0700
commitc0ac3d7845f60c7f6f2c3bfc306ceb0e4ac045ba (patch)
treee2b7427e212bd5b557f15131b815517a86b20486 /src/search.c
parent0bb4ae3052cb8ff9ffcf951b3ef0e6f50a7efdfa (diff)
Rework check/pawn-push/recapture extension gating on real SEE (GetMoveSee, generalized from GetCheckSee), restrict LMR to leftover moves only, and tighten recapture's window back to 1x after measuring a 6.8x node blowup from sharing the wider window.
Head-to-head match at 1170 games confirms parity with the prior head (score=0.510, LLR still between bounds) -- landing as a neutral-or-better baseline rather than a regression.
Diffstat (limited to 'src/search.c')
-rw-r--r--src/search.c36
1 files changed, 23 insertions, 13 deletions
diff --git a/src/search.c b/src/search.c
index 4e89a2c..573f78c 100644
--- a/src/search.c
+++ b/src/search.c
@@ -189,7 +189,7 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx,
ULONG uFutilityMargin = 0;
FLAG fAnyMoveEFPPruned = FALSE;
FLAG fThisMoveEFPPruned = FALSE;
- SCORE iCheckSee;
+ SCORE iMoveSee;
#ifdef DEBUG
ASSERT(IS_VALID_SCORE(iAlpha));
ASSERT(IS_VALID_SCORE(iBeta));
@@ -745,14 +745,22 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx,
#endif
// 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))
+ // exchange walk needs the piece still sitting on cFrom.
+ // ComputeMoveExtension uses it for two soundness gates: the
+ // check extension (Crafty-style: don't extend a checking move
+ // that's really just a losing sacrifice) and the recapture
+ // extension (don't extend a "recapture" that actually loses
+ // material). uDepth <= THREE_PLY mirrors the recapture
+ // extension's own depth gate -- cheap to test here since
+ // uDepth is already loop-invariant, and it keeps this from
+ // computing a SEE on every single non-pawn capture at every
+ // depth. One call per move regardless of which gate(s) end up
+ // wanting it -- SEE is too hot a routine to pay for twice.
+ iMoveSee = 0;
+ if (IS_CHECKING_MOVE(mv) ||
+ (mv.pCaptured && !IS_PAWN(mv.pCaptured) && (uDepth <= THREE_PLY)))
{
- iCheckSee = GetCheckSee(ctx,
+ iMoveSee = GetMoveSee(ctx,
mv,
(uStage == TRY_GENERATED_MOVES) ?
(x - 1) : (ULONG)-1);
@@ -773,7 +781,8 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx,
(x - 1), // Note: x==0 if doing mvHash
iEval,
uDepth,
- iCheckSee,
+ iMoveSee,
+ fIsLeftoverMove,
&iExtend);
// Note: MAX_EXTEND_PER_LINE (a flat, non-depth-relative cap on
@@ -786,8 +795,9 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx,
// Decide how much (if any) to reduce this move's depth --
// graded LMR.
if ((uDepth > TWO_PLY) &&
- (NODE_PV != pi->eNodeType) &&
+ (pi->eNodeType != NODE_PV) &&
(uLegalMoves > 5) &&
+ (fIsLeftoverMove) &&
(0 == iExtend) &&
(!IS_ESCAPING_CHECK(mv)) &&
(!IS_CAPTURE_OR_PROMOTION(mv)) &&
@@ -1570,7 +1580,7 @@ _ShouldWeConsiderThisMove(IN SEARCHER_THREAD_CONTEXT *ctx,
// a real (winning/even) iMoveValue gets the same value-plus-
// flat-bonus treatment as any other capture; a move with no
// usable value (SEE already called it losing) falls back to
- // GetCheckSee's real tactical judgment, exactly like the
+ // GetMoveSee's real tactical judgment, exactly like the
// quiet-check (VALUE_BISHOP) branch already does below.
if (IS_CHECKING_MOVE(mv) && (TRUE == fGeneratedChecks))
{
@@ -1590,7 +1600,7 @@ _ShouldWeConsiderThisMove(IN SEARCHER_THREAD_CONTEXT *ctx,
return(fConsider);
}
{
- FLAG fConsider = (GetCheckSee(ctx, mv, uMoveNum) >= 0);
+ FLAG fConsider = (GetMoveSee(ctx, mv, uMoveNum) >= 0);
#ifdef CALIBRATE_QSEARCH_FUTILITY
if (FALSE == fConsider)
{
@@ -1640,7 +1650,7 @@ _ShouldWeConsiderThisMove(IN SEARCHER_THREAD_CONTEXT *ctx,
return(TRUE);
}
{
- FLAG fConsider = (GetCheckSee(ctx, mv, uMoveNum) >= 0);
+ FLAG fConsider = (GetMoveSee(ctx, mv, uMoveNum) >= 0);
#ifdef CALIBRATE_QSEARCH_FUTILITY
if (FALSE == fConsider)
{