diff options
Diffstat (limited to 'src/chess.h')
| -rwxr-xr-x | src/chess.h | 242 |
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 |
