summaryrefslogtreecommitdiff
path: root/src/chess.h
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-09-22 13:04:39 -0700
committerScott Gasch <[email protected]>2026-09-22 13:04:39 -0700
commitb7e4cdfeb3c1aadb3f488f6794e6d1a748dc6c8f (patch)
treeffc5bb4e2a4a4d9d027df38c9619739a3dbb478e /src/chess.h
parentf422daab223103bbd62a5611be0b73eaa6a5dc05 (diff)
eval.c: defer B/N/R mobility scoring near enemy king, queen king-adjacency fix, FLIP() -> precomputed xColor
Bishop/knight/rook mobility computed during their own eval pass only sees enemy pawn (B/N) or pawn+minor (R) attacks -- a square right next to the enemy king looks "safe" and counts toward mobility even though it plainly isn't (e.g. a pawn push cutting off a bishop's retreat onto squares next to the enemy king). Below EVAL_MOBILITY_CAREFULLY_BELOW (3) candidate squares, defer scoring to _EvalTrappedPieces, which re-derives the true safe-escape count once every piece type -- the enemy king included -- has contributed to the attack tables. Genuinely 0-mobility pieces are scored immediately instead: more attack info can only shrink an already-empty set, so there's nothing to gain by waiting. Queen doesn't need deferral (its own eval pass runs after every smaller piece type, so it already has complete information) -- instead bbUnsafeForQueen now also excludes squares adjacent to the enemy king unless we already defend them. Also: precompute xColor = FLIP(uColor) once per function/loop iteration everywhere eval.c could hit FLIP() more than once evaluating it, instead of recomputing it at each use site. Verified: precommit_check.sh (self-test + DEBUG smoke test) clean. Curated ECM suites at sd10 vs head_reference: ecm_ringers 4/11 (was 3/11), ecm_confident_quick 70/90 (flat), ecm_hard_quick 19/90 (was 18/90) -- no regressions. Overnight self-play SPRT trending positive (370 games, llr=+0.20). Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/chess.h')
-rwxr-xr-xsrc/chess.h37
1 files changed, 27 insertions, 10 deletions
diff --git a/src/chess.h b/src/chess.h
index 1dcb517..8d9a8d8 100755
--- a/src/chess.h
+++ b/src/chess.h
@@ -749,16 +749,33 @@ typedef struct _POSITION
// temporary storage space for use in eval
//
- // Small fixed-capacity list of zero-mobility piece candidates per
- // color (bishop/knight/rook/queen evals each can push one), not
- // just the single most-recently-evaluated one -- a single COOR
- // here used to silently let a later piece's candidacy overwrite an
- // earlier one on the same side, discarding it even if it was a
- // genuinely trapped (zero mobility + actually attacked) piece.
- // Capacity of 4 is deliberately generous; if a position somehow
- // has more than 4 simultaneously zero-mobility non-pawn pieces on
- // one side, the rest are just dropped, not a real concern.
- COOR cTrapped[2][4];
+ // Small fixed-capacity list of zero-mobility (or, for a deferred
+ // bishop/knight/rook -- see EVAL_MOBILITY_CAREFULLY_BELOW in
+ // eval.c -- low-mobility) piece candidates per color, not just the
+ // single most-recently-evaluated one -- a single COOR here used to
+ // silently let a later piece's candidacy overwrite an earlier one
+ // on the same side, discarding it even if it was a genuinely
+ // trapped (zero mobility + actually attacked) piece. Capacity of 6
+ // is deliberately generous; if a position somehow has more than 6
+ // simultaneously trapped-candidate non-pawn pieces on one side, the
+ // rest are just dropped, not a real concern.
+ //
+ // bbTrappedEscapes[side][u] is the nominating bishop/knight/rook's
+ // own bbMobility snapshot at nomination time, for a genuinely
+ // deferred candidate (see eval.c's _EvalBishop/_EvalKnight/
+ // _EvalRook) -- necessarily computed from incomplete attack-table
+ // information (the enemy king's, and for bishop/knight any
+ // not-yet-evaluated enemy slider's, attacks aren't known yet). Zero
+ // for every non-deferred candidate (queen, which never has this
+ // partial-information problem in the first place, or a
+ // bishop/knight/rook nominated at already-zero mobility -- nothing
+ // left to re-derive there, see eval.c's comment on why 0-mobility
+ // pieces are never deferred) -- _EvalTrappedPieces uses this being
+ // nonzero as the signal that a deferred re-check (and its own
+ // "mobility (deferred)" EVAL_TERM, skipped at nomination time) is
+ // owed to this candidate.
+ COOR cTrapped[2][6];
+ BITBOARD bbTrappedEscapes[2][6];
ULONG uNumTrapped[2];
ULONG uArmyScaler[2];
ULONG uClosedScaler;