diff options
| author | Scott Gasch <[email protected]> | 2026-09-05 02:17:20 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-09-05 02:17:20 -0700 |
| commit | de3f3663483f846d369efa5234a84c7da385be95 (patch) | |
| tree | 71af0527a47c0996b0116351dee0d68409db2fad /src/chess.h | |
| parent | 7e3e6b69969cf6657f518102be515702da6a7343 (diff) | |
Bishop attack/mobility: bitboard rewrite, deliberate x-ray simplification
_EvalBishop's mobility ray-walk (per-square g_iBDeltas delta-walk +
BMobCaseTable switch dispatch) replaced with _BishopAttacksBB(c,
pos->bbOccupied) -- generate.c's magic-bitboard slider lookup,
already used by move generation -- plus bitboard masks for the
mobility count, matching knight's reduction pattern:
enemy-non-pawn-terminal counts unconditionally, empty-or-enemy-pawn-
terminal counts unless pawn-unsafe (via bbPawnAttacks), and the one
case that isn't a pure occupancy mask -- a terminal friendly,
non-stationary pawn on this bishop's own color complex -- keeps its
credit via bbPc (already computed for the existing good/bad
transient-pawn scoring, untouched this change).
Adds POSITION::bbMinorAttacks contributions from bishop (direct
attack bits) and POSITION::bbMinorXrayAttacks (new field) for squares
seen through a friendly bishop/queen battery partner or an
x-rayable enemy rook/queen/king.
Deliberate behavior change from the old ray-walk, made for speed per
direct instruction: the old walk's fStop=FALSE for the x-ray cases
meant it kept going -- and kept counting mobility -- through however
many x-ray-worthy blockers were stacked consecutively on one ray
(e.g. x-raying an enemy rook, then continuing to x-ray *through* an
enemy king sitting right behind it too). The bitboard version only
extends one hop past the first x-ray-worthy blocker; it does not
re-check whether the newly-revealed terminal square is itself
x-ray-worthy and extend again. This was found and deliberately kept
(not fixed) after a DEBUG assert caught the exact case on
8/1R1B4/2B1r3/5k2/2P2P2/1p6/1Kb5/7n w - - during precommit's random-
sample smoke test -- judged an acceptable trade given how rare a ray
with >=2 consecutive x-ray-worthy pieces is.
Two new transitional helpers (_IsSquareAttackedByMinor's bishop
contribution, and new _IsSquareXrayedByMinor) carry bishop's combined
state to every remaining consumer (rook/queen mobility-safety checks,
king's danger computation, _WhoControlsSquareFast) -- both DEBUG-
asserted against an independent from-scratch mailbox ray-walk (using
the still-live rgSquare representation, not any shared code with the
production bitboard technique) implementing this same single-hop
rule, so a real regression fails loudly rather than drifting into a
wrong score.
Verified via precommit_check.sh and the full tests/ecm_ringers.ep_
suite at sd10 against the prior commit (7e3e6b6): same 10/11 solved
(same single miss, ECM.335, in both), node counts now legitimately
differ per position (expected given the semantic change) but stay in
a bounded, reasonable range (-17% to +20%), nothing resembling the
60%+ blowups a real bug produced earlier in this same session before
being caught, isolated, and traced to this exact x-ray-chain gap.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01P6g6iF6mD1Hau6nCZCzwYj
Diffstat (limited to 'src/chess.h')
| -rwxr-xr-x | src/chess.h | 32 |
1 files changed, 21 insertions, 11 deletions
diff --git a/src/chess.h b/src/chess.h index 2e9189a..305c681 100755 --- a/src/chess.h +++ b/src/chess.h @@ -716,19 +716,29 @@ typedef struct _POSITION // bbRookAttacks/bbQueenAttacks that will retire the rest of it. BITBOARD bbPawnAttacks[2]; - // First mover of the bbMinorAttacks pair (knight only for now -- - // bishop is a separate, later step; see board_representation/ - // EVAL.md section 2). "Which squares does this side's knight(s) - // attack" -- computed via g_KnightAttacksBB[c] and OR'd in per - // knight, Eval()-scoped scratch like bbPawnAttacks above, cleared - // once per Eval() call in _ClearAttackTables since (unlike - // bbPawnAttacks) it's accumulated across multiple pieces via |=, - // not assigned wholesale. Bishop still writes its own minor-bit - // contribution into the old rgSquare[c|8].bvAttacks structure for - // now -- every consumer that needs "any minor's attack," not just - // knight's, ORs both sources together until bishop converts too. + // "Which squares does this side's knight(s) or bishop(s) attack" -- + // knight ORs in g_KnightAttacksBB[c] directly (no per-square + // bit-scan needed); bishop ORs in _BishopAttacksBB(c, + // pos->bbOccupied), generate.c's magic-bitboard slider lookup. + // Eval()-scoped scratch like bbPawnAttacks above, cleared once per + // Eval() call in _ClearAttackTables since (unlike bbPawnAttacks) + // it's accumulated across multiple pieces via |=, not assigned + // wholesale. Rook/queen/king are not converted yet and still write + // their own bits into the old rgSquare[c|8].bvAttacks structure -- + // see _IsSquareAttackedByMinor (eval.c), the transitional helper + // every consumer goes through until they convert too. BITBOARD bbMinorAttacks[2]; + // Squares seen *through* a friendly bishop/queen battery partner + // or an x-rayable enemy rook/queen/king, for bishops only (knights + // never x-ray) -- see _EvalBishop's mobility loop. Same lifetime/ + // clearing discipline as bbMinorAttacks above. Nothing else writes + // this yet (rook/queen have their own xray bits still living in + // the old bvAttacks structure), so unlike bbMinorAttacks' direct- + // bit case there's no old-structure fallback to combine with -- + // see _IsSquareXrayedByMinor. + BITBOARD bbMinorXrayAttacks[2]; + ULONG uWhiteSqBishopCount[2]; // num bishops on white squares SCORE iMaterialBalance[2]; // material balance |
