summaryrefslogtreecommitdiff
path: root/src/chess.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/chess.h')
-rwxr-xr-xsrc/chess.h242
1 files changed, 73 insertions, 169 deletions
diff --git a/src/chess.h b/src/chess.h
index aababc0..acab153 100755
--- a/src/chess.h
+++ b/src/chess.h
@@ -542,105 +542,55 @@ typedef union _MOVE
// ----------------------------------------------------------------------
-#pragma pack(1)
-typedef union _ATTACK_BITV
-{
- ULONG uWholeThing;
- struct
- {
- union
- {
- UCHAR uSmall;
- struct
- {
- UCHAR uNumAttacks : 3; // 0..2
- UCHAR uKing : 1; // 4..7
- UCHAR uQueen : 1;
- UCHAR uRook : 1;
- UCHAR uMinor : 1;
- UCHAR uPawn : 1;
- } small;
- };
-
- // --------------------
- union
- {
- USHORT uBig;
- struct
- {
- USHORT uKing : 1; // 8..23
- USHORT uQueens : 4;
- USHORT uRooks : 4;
- USHORT uMinors : 4;
- USHORT uPawns : 2;
- USHORT uUnusedFlag1 : 1;
- } big;
- };
-
- // -------------------
- union
- {
- UCHAR uXray;
- struct
- {
- UCHAR uNumXrays : 3;
- UCHAR uUnusedFlag2 : 1;
- UCHAR uQueen : 1; // 24..28
- UCHAR uRook : 1;
- UCHAR uBishop : 1;
- UCHAR uUnusedFlag3 : 1;
- } xray;
- };
- };
-}
-ATTACK_BITV;
-
-// UNSAFE_FOR_MINOR retired as a bvAttacks-based macro 2026-09-05:
-// pawns no longer write PAWN_BIT into bvAttacks (see POSITION's
-// bbPawnAttacks[2] comment, chess.h) -- it was PAWN_BIT alone, so
-// every former call site now just tests
-// (pos->bbPawnAttacks[enemy] & COOR_TO_BB(sq)) directly, no macro
-// needed. UNSAFE_FOR_ROOK/_QUEEN's masks below are narrowed to drop
-// PAWN_BIT (0x80), which would otherwise silently always read 0 now
-// that nothing sets it -- callers combine these with an explicit
-// bbPawnAttacks test instead (see eval.c's _EvalRook/_EvalQueen).
-#define UNSAFE_FOR_ROOK(x) ((ULONG)((x).uWholeThing) & 0x00000040UL)
-#define UNSAFE_FOR_QUEEN(x) ((ULONG)((x).uWholeThing) & 0x00000060UL)
-
-#define PAWN_BIT 0x00000080UL
-#define MINOR_BIT 0x00000040UL
-#define MINOR_XRAY_BIT 0x40000000UL
-#define ROOK_BIT 0x00000020UL
-#define ROOK_XRAY_BIT 0x20000000UL
-#define QUEEN_BIT 0x00000010UL
-#define QUEEN_XRAY_BIT 0x10000000UL
+// ATTACK_BITV/bvAttacks retired entirely 2026-09-05 (board_
+// representation/EVAL.md section 9): the per-square, per-color
+// attack-bit union that used to live at rgSquare[c|8] (the "c|8"
+// shadow-index trick -- reusing the same 128-entry array the 0x88
+// board layout already needs for its own off-board sentinels, at
+// the indices real piece coordinates never use) is gone now that
+// king -- the last piece type writing it -- has converted to a
+// bitboard accumulator like every other piece type before it. Every
+// consumer reads a pos->bbXAttacks[color] bitboard directly instead.
+//
+// PAWN_BIT/MINOR_BIT/ROOK_BIT/QUEEN_BIT/KING_BIT below are NOT part
+// of that retired mechanism -- they're a separate, still-live
+// byte-scale bit-packing scheme _EvalKing/_WhoControlsSquareFast use
+// locally (BITV-typed variables, not struct fields) to build a
+// per-square "which piece types attack/defend/x-ray this square"
+// pattern from those same bbXAttacks reads, then index
+// KING_COUNTER_BY_ATTACK_PATTERN/g_SwapTable with it. Kept exactly as
+// before; only their old *storage* mechanism (ATTACK_BITV) is gone.
+#define PAWN_BIT 0x00000080UL
+#define MINOR_BIT 0x00000040UL
+#define ROOK_BIT 0x00000020UL
+#define QUEEN_BIT 0x00000010UL
// King never x-rays (it can't move through a blocker), so there's no
-// KING_XRAY_BIT to go with this -- matches struct _ATTACK_BITV's
-// .small.uKing bit position (byte 0, bit 3).
-#define KING_BIT 0x00000008UL
+// KING_XRAY_BIT to go with this.
+#define KING_BIT 0x00000008UL
#define INVALID_PIECE_INDEX (17)
#define IS_VALID_PIECE_INDEX(x) ((x) < INVALID_PIECE_INDEX)
-typedef union _SQUARE
+typedef struct _SQUARE
{
- struct
- {
- PIECE pPiece;
- ULONG uIndex;
- };
- ATTACK_BITV bvAttacks[2];
+ PIECE pPiece;
+ ULONG uIndex;
}
SQUARE;
-#pragma pack()
//
// POSITION
//
typedef struct _POSITION
{
- SQUARE rgSquare[128]; // where the pieces are,
- // also, the attack table
+ SQUARE rgSquare[128]; // where the pieces are
+ // (0x88 board layout -- the
+ // upper half of each rank's
+ // 16-entry span is off-board
+ // sentinel space, no longer
+ // double-purposed as attack-
+ // bit storage now that
+ // ATTACK_BITV is retired)
UINT64 u64NonPawnSig; // hash signature
UINT64 u64PawnSig; // pawn hash signature
ULONG uToMove; // whose turn?
@@ -700,97 +650,51 @@ typedef struct _POSITION
// not as something callers should call directly anymore.
BITBOARD bbOccupied;
- // First mover of board_representation/EVAL.md section 2's
- // bvAttacks replacement, added 2026-09-05: "which squares does
- // this side's pawns attack," computed fresh once per Eval() call
- // from bbPawns via a single shift-and-mask (see
- // _PopulatePawnAttackBits in eval.c, same technique as
- // generate.c's _GenerateAllPawnMovesBB) -- zero per-pawn mailbox
- // iteration, so unlike bbPieces/bbPawns/bbOccupied above this is
- // NOT incrementally maintained across moves; it's plain Eval()-
- // scoped scratch space, recomputed every call the same way
- // pos->iScore[] is. Pawns no longer write their attack bit into
- // rgSquare[c|8].bvAttacks at all -- every consumer of "does an
- // enemy/friendly pawn attack this square" reads this bitboard
- // directly instead (UNSAFE_FOR_MINOR/_ROOK/_QUEEN's pawn
- // component, _EvalKing's bvAttack/bvDefend). Knight/bishop/rook/
- // queen/king still populate/read bvAttacks for their own bits
- // (uMinor/uRook/uQueen/uKing) until their own conversions land --
- // see EVAL.md section 2 for the planned bbMinorAttacks/
- // bbRookAttacks/bbQueenAttacks that will retire the rest of it.
+ // Eval()-scoped attack-bitboard accumulators, one pair per piece
+ // family, populated by Eval()'s piece-by-piece walk (pawns, then
+ // knights/bishops, then rooks, then queens, then king) and read by
+ // _EvalKing/_WhoControlsSquareFast to answer "which side attacks
+ // this square, and with what." Landed piece-by-piece as
+ // board_representation/EVAL.md's bitboard-eval migration replaced
+ // the old per-square, per-color rgSquare[c|8] ATTACK_BITV
+ // mechanism (2026-09-04 through 2026-09-05, pawns first, king
+ // last) -- see EVAL.md for that history. All are cleared once per
+ // Eval() call in _ClearAttackTables and accumulated via |= as each
+ // piece evaluates (not incrementally maintained across moves, the
+ // way bbPieces/bbPawns/bbOccupied above are).
+ //
+ // bbPawnAttacks is the odd one out: computed in one shot from
+ // bbPawns via a shift-and-mask (_PopulatePawnAttackBits, same
+ // technique as generate.c's _GenerateAllPawnMovesBB), not
+ // per-piece, and assigned wholesale rather than OR-accumulated.
+ //
+ // Only bishop/rook/queen have a matching bbXXrayAttacks: squares
+ // seen *through* a friendly same-or-greater-value battery partner
+ // (and, for rook/bishop specifically, through an x-rayable enemy
+ // piece too -- queen's own case never x-rays past an enemy piece).
+ // Knight and king can't x-ray at all (no blocker-piercing move).
+ // Bishop's x-ray chains arbitrarily deep, same as rook's/queen's,
+ // not the single-hop approximation it originally shipped with (see
+ // EVAL.md's progress log for why that was revisited).
BITBOARD bbPawnAttacks[2];
-
- // "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];
-
- // Rook's turn to convert (board_representation/EVAL.md section
- // 9, 2026-09-05): "which squares does this side's rook(s) attack,"
- // ORed in via _RookAttacksBB(c, pos->bbOccupied) straight from
- // _EvalRook's mobility computation, same Eval()-scoped/cleared-
- // per-call lifetime as bbMinorAttacks. bbRookXrayAttacks mirrors
- // bbMinorXrayAttacks: squares seen past a friendly rook/queen
- // battery partner or an x-rayable enemy queen/king, single-hop
- // only (same deliberate simplification bishop already made, see
- // _EvalRook's mobility comment). Queen/king haven't converted yet
- // and still write their own bits into the old bvAttacks structure.
BITBOARD bbRookAttacks[2];
BITBOARD bbRookXrayAttacks[2];
-
- // Queen's turn to convert (board_representation/EVAL.md section
- // 9, 2026-09-05): "which squares does this side's queen(s)
- // attack," ORed in from the two-pass rook-direction/bishop-
- // direction magic lookups _EvalQueen's mobility computation
- // already needs (MOVEGEN_MIGRATION.md's own already-tested
- // "combined 8-ray table measured slower than reusing the
- // rook/bishop tables in two passes" finding -- reuse that
- // structure here too). bbQueenXrayAttacks mirrors
- // bbRookXrayAttacks/bbMinorXrayAttacks: squares seen past a
- // friendly queen/rook/bishop battery partner, chained arbitrarily
- // deep like rook's (not single-hop like bishop's original cut) --
- // queen's own case table never x-rays past an enemy piece (unlike
- // rook/bishop), only through friendly battery partners. King
- // hasn't converted yet and still writes its own bits into the old
- // bvAttacks structure.
BITBOARD bbQueenAttacks[2];
BITBOARD bbQueenXrayAttacks[2];
-
- // King's turn to convert (board_representation/EVAL.md section 9,
- // 2026-09-05) -- the last piece type contributing to the old
- // bvAttacks/ATTACK_BITV mechanism. Just g_KingAttacksBB[c]
- // (generate.c's precomputed table, already used by move
- // generation), no mobility computation involved and no x-ray
- // (a king can't move through a blocker). Same Eval()-scoped/
- // cleared-per-call lifetime as every other bbXAttacks accumulator
- // above -- this also reproduces, for free, an existing
- // order-dependent asymmetry _EvalKing's mailbox version already
- // had: kings are evaluated black-then-white (Eval()'s fixed
- // order), so white's king-safety computation can see black's
- // already-written attack bits but not vice versa. Once this
- // lands, nothing writes bvAttacks/ATTACK_BITV any more -- see
- // EVAL.md section 9 for the planned follow-up that deletes the
- // whole mechanism and simplifies the transitional
- // _IsSquareAttackedByX/_IsSquareXrayedByX helpers into plain
- // bitboard reads.
+ // bbKingAttacks reproduces, for free, an existing order-dependent
+ // asymmetry _EvalKing already had before this bitboard conversion:
+ // kings are evaluated black-then-white (Eval()'s fixed order), so
+ // by the time white's king-safety computation runs it can see
+ // black's already-written attacks but black's own computation
+ // never could (white hadn't run yet). _EvalKing's own bvAttack
+ // deliberately keeps this asymmetric (drops the enemy king's
+ // contribution entirely, matching the side that already couldn't
+ // see it, by direct instruction) -- but every other bbKingAttacks
+ // reader (_WhoControlsSquareFast, only ever called after *both*
+ // kings finish evaluating) sees a fully populated, symmetric
+ // bitboard for both colors.
BITBOARD bbKingAttacks[2];
ULONG uWhiteSqBishopCount[2]; // num bishops on white squares