diff options
| author | Scott Gasch <[email protected]> | 2026-10-07 08:17:51 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-10-07 08:17:51 -0700 |
| commit | d14dbe2a50c220b2adac758c3d4f1a1fa67ece0b (patch) | |
| tree | cbf6d9928bcc41ef833b62b70479113f7d419925 /src/search.c | |
| parent | 447130db3df87b40d080dc26429d45e9213c19f7 (diff) | |
Speed up eval/move-gen/SEE; remove EvalLookForDanger, overhaul _EvalKing
SPRT-confirmed improvement (1814 games, st 4.0): candidate nps=1498118
vs head=1378448, avg depth 14.30 vs 13.87, ELO=+24.2+/-16.0,
LOWER95=0.5118, LLR=+3.126 crossing the H1 bound.
Most of the diff is non-semantic speed work across eval.c, generate.c,
movesup.c, see.c, probe.c and friends. Two real semantic changes:
removed EvalLookForDanger and overhauled _EvalKing's king-safety scoring.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/search.c')
| -rw-r--r-- | src/search.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/src/search.c b/src/search.c index d8ece8d..fcf8907 100644 --- a/src/search.c +++ b/src/search.c @@ -725,13 +725,19 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, case UNRECOGNIZED: break; case RECOGN_EXACT: - case RECOGN_EGTB: if ((iAlpha < iScore) && (iScore < iBeta)) { UpdatePV(ctx, RECOGNMOVE); } iBestScore = iScore; goto end; + case RECOGN_EGTB: + if ((iAlpha < iScore) && (iScore < iBeta)) + { + UpdatePV(ctx, EGTBMOVE); + } + iBestScore = iScore; + goto end; case RECOGN_LOWER: if (iScore >= iBeta) { @@ -1073,14 +1079,18 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, // leftover (matches pre-retirement behavior). if (MOVE_SCORING_IID_RESCORED == pi->eMoveScoringScheme) { - SelectBestNoHistory(ctx, x); + SelectBestNoHistory(ctx, x); // mv's score is search-based + // WouldGiveCheck already computed in RescoreMovesViaSearch + mv = ctx->sMoveStack.mvf[x].mv; } else { SelectBestWithHistory(ctx, x); + mv = ctx->sMoveStack.mvf[x].mv; + mv.bvFlags |= WouldGiveCheck(ctx, mv); + ctx->sMoveStack.mvf[x].mv = mv; // re-store WouldGiveCheck's result fIsLeftoverMove = (ctx->sMoveStack.mvf[x].iValue < GOOD_MOVE); } - mv = ctx->sMoveStack.mvf[x].mv; #ifdef DEBUG ASSERT(0 == (ctx->sMoveStack.mvf[x].bvFlags & MVF_MOVE_SEARCHED)); @@ -1107,7 +1117,6 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, uCMEvidenceBucket = _CMEvidenceBucket(uEvidence); } #endif - mv.bvFlags |= WouldGiveCheck(ctx, mv); // Note: x is the index of the NEXT move to be // considered, this move's index is (x-1). @@ -3021,13 +3030,19 @@ QSearch(IN SEARCHER_THREAD_CONTEXT *ctx, case UNRECOGNIZED: break; case RECOGN_EXACT: - case RECOGN_EGTB: if ((iAlpha < iScore) && (iScore < iBeta)) { UpdatePV(ctx, RECOGNMOVE); } iBestScore = iScore; goto end; + case RECOGN_EGTB: + if ((iAlpha < iScore) && (iScore < iBeta)) + { + UpdatePV(ctx, EGTBMOVE); + } + iBestScore = iScore; + goto end; case RECOGN_LOWER: if (iScore >= iBeta) { @@ -3238,7 +3253,17 @@ QSearch(IN SEARCHER_THREAD_CONTEXT *ctx, // If fIncludeChecks is FALSE then we still need to see if // this move is going to check the opponent; GenerateMoves // didn't do it for us to save time in the event of a fail - // high. + // high. Tried swapping this for a post-MakeMove InCheck call + // instead (the theory: at most one query, nothing to amortize + // WouldGiveCheck's table-build against) -- measured worse on + // 2 of 3 curated suites (ringers +7.2%, confident_quick +5.9%, + // hard_quick -1.2%, sd 10, node counts identical either way). + // The assumption was wrong: this loop tries more than one move + // per node whenever an earlier candidate raises alpha without + // failing high, and the lazy-built bbUnblocked[uPly] (see + // WouldGiveCheck) gets reused cheaply across all of those, + // while a fresh InCheck call pays full price every time with + // no reuse at all. Reverted -- WouldGiveCheck stays here. if (FALSE == fIncludeChecks) { mv.bvFlags |= WouldGiveCheck(ctx, mv); |
