diff options
| author | Scott Gasch <[email protected]> | 2026-09-08 20:18:20 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-09-08 20:18:20 -0700 |
| commit | 88a0787a7d19a5b4e19e540816f1d500e02dbfeb (patch) | |
| tree | d4a4c44df716aed5559d64ed132a31bf07791da7 /src/save/chess.h | |
| parent | 379a03bbd993247c8de9c1f1b163fcfab2fa1d69 (diff) | |
Fix BOOC opposite-bishop check, extract drawish-scaling, trim lazy margins
Three changes landed together, verified via the usual pipeline (release
+ DEBUG build, DEBUG smoke test, 40-game st1 match vs clean 434fa04,
score 0.600, llr +0.24):
1. New BOOC (bishops of opposite color) endgame drawish-scaling term
had a real bug in its opposite-color check:
(pos->uWhiteSqBishopCount[WHITE] && !pos->uWhiteSqBishopCount[BLACK])
only detects one of the two possible opposite-color configurations
and silently misses the mirror case (White dark-squared / Black
light-squared). Since each side's bishop-square-color flag is 0 or 1
whenever uNonPawnCount[side][BISHOP] == 1 (already checked above),
"opposite colors" is exactly the XOR of the two flags:
(pos->uWhiteSqBishopCount[WHITE] != pos->uWhiteSqBishopCount[BLACK])
2. Extracted the winning-chances/BOOC/fifty-move drawish scaling out of
Eval() into its own EvalLookForDrawishSituations(pos,
&iScoreForSideToMove) helper -- same semantics, cleaner separation.
Fixed two small issues in the extraction: missing `static` (every
other file-local eval.c helper is static; this had accidental
external linkage with no prototype anywhere) and a typo in a new
EVAL_DUMP trace string ("At of all pieces" -> "After all pieces").
Also reordered Eval()'s two king evaluations to go side-to-move
first / enemy second (via the already-cached uColor/xColor) instead
of always BLACK-then-WHITE -- confirmed safe, no dependency between
the two _EvalKing calls (each only reads attack-bitboard data
already populated by earlier phases).
3. Re-calibrated and trimmed SUPER_LAZY_MARGIN_BY_ARMY and
iSwingFloorByArmy. Both were originally derived by measuring
symmetric |real - lazy| swing, which conflates a swing *toward* the
alpha/beta boundary (the only direction that can make an exit
unsound) with a swing *away* from it (harmless). Re-ran
CALIBRATE_MARGIN_SAFETY against the same 1500-position
tests/twic_sample.ep_ (sd 8) with the harness fixed to measure only
the dangerous-direction swing: true max ran 15-50% below the old
symmetric measurement in most material buckets, several averaged in
the single digits, and every bucket showed exceeded=0 even before
adding any headroom back.
iSwingFloorByArmy: {1069,1069,1069,974,821,876,796,754}
-> {297,297,297,286,461,453,582,600}
SUPER_LAZY_MARGIN_BY_ARMY: {2000,1800,1800,1750,1000,850,850,850}
-> {300,1635,1800,1070,946,850,734,698}
(buckets 2 and 5 unchanged -- already tighter than a fresh 15%
headroom over the new directional max would give)
Motivation: the board-representation-migration branch exists to
close a measured 5x nps gap vs Crafty on the same CPU (profiled:
typhoon spends more of its search time in Eval() than Crafty does
in evaluate()); every lazy/super-lazy exit that fires is Eval()'s
fast path, so trimming unnecessary margin headroom directly
increases how often the cheap path is taken instead of a full
evaluation.
Not yet done: splitting alpha-margin and beta-margin into independent
per-bucket values (currently symmetric per bucket, no principled reason
they need to be) -- would need another calibration pass tracking the
two separately.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Ka9o3S2eKqh4jNfmxVZ6fH
Diffstat (limited to 'src/save/chess.h')
0 files changed, 0 insertions, 0 deletions
