summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/chess.h242
-rwxr-xr-xsrc/command.c3
-rwxr-xr-xsrc/eval.c742
3 files changed, 209 insertions, 778 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
diff --git a/src/command.c b/src/command.c
index 37686ed..a51bb33 100755
--- a/src/command.c
+++ b/src/command.c
@@ -267,7 +267,6 @@ Return value:
Trace("sizeof(PAWN_HASH_ENTRY). . . . . . . . . %u bytes\n"
"sizeof(HASH_ENTRY) . . . . . . . . . . . %u bytes\n"
"sizeof(MOVE) . . . . . . . . . . . . . . %u bytes\n"
- "sizeof(ATTACK_BITV). . . . . . . . . . . %u bytes\n"
"sizeof(SQUARE) . . . . . . . . . . . . . %u bytes\n"
"sizeof(POSITION) . . . . . . . . . . . . %u bytes\n"
"sizeof(MOVE_STACK) . . . . . . . . . . . %u bytes\n"
@@ -287,7 +286,7 @@ Return value:
"-------------------------------------------------\n"
"Current main hash table size . . . . . . %u bytes (~%u Mb)\n",
sizeof(PAWN_HASH_ENTRY), sizeof(HASH_ENTRY), sizeof(MOVE),
- sizeof(ATTACK_BITV), sizeof(SQUARE), sizeof(POSITION),
+ sizeof(SQUARE), sizeof(POSITION),
sizeof(MOVE_STACK), sizeof(PLY_INFO), sizeof(COUNTERS),
sizeof(SEARCHER_THREAD_CONTEXT), sizeof(GAME_OPTIONS),
sizeof(MOVE_TIMER), sizeof(PIECE_DATA), sizeof(VECTOR_DELTA),
diff --git a/src/eval.c b/src/eval.c
index 6adf27b..1ca2beb 100755
--- a/src/eval.c
+++ b/src/eval.c
@@ -1152,403 +1152,6 @@ Return value:
}
-//
-// Transitional helper, board_representation/EVAL.md section 2: during
-// the piece-by-piece migration off bvAttacks, knight now writes its
-// attacks into pos->bbMinorAttacks directly while bishop (not
-// converted yet) still writes the old per-square
-// rgSquare[c|8].bvAttacks[color].small.uMinor bit. Every consumer
-// that needs "does any minor (knight or bishop) attack this square"
-// goes through this one function instead of each hand-rolling its own
-// OR of the two sources -- once bishop converts too, this collapses
-// to a plain pos->bbMinorAttacks[color] read and this whole function
-// goes away; it is not meant to be a permanent fixture.
-//
-// DEBUG-only: cross-checked against an independent recomputation
-// (g_KnightAttacksBB / _BishopAttacksBB, both already-trusted
-// primitives used elsewhere in move generation, entirely separate
-// code from either the ray-walk's uBit bookkeeping or the new
-// bitboard population) so a bug in either mechanism fails loudly here
-// instead of silently drifting into a wrong score several plies deep
-// in search -- exactly the failure mode a prior, larger version of
-// this same migration hit and had to be rolled back for.
-//
-static FLAG
-_IsSquareAttackedByMinor(IN POSITION *pos,
- IN ULONG uColor,
- IN COOR c)
-{
- BITBOARD sq = COOR_TO_BB(c);
- FLAG fResult = ((pos->bbMinorAttacks[uColor] & sq) != 0) ||
- (pos->rgSquare[c|8].bvAttacks[uColor].small.uMinor != 0);
-#ifdef DEBUG
- {
- BITBOARD bbTrueMinorAttacks = 0;
- ULONG u;
- for (u = 1; u < pos->uNonPawnCount[uColor][0]; u++)
- {
- COOR cPiece = pos->cNonPawns[uColor][u];
- PIECE p = pos->rgSquare[cPiece].pPiece;
- if (IS_KNIGHT(p))
- {
- bbTrueMinorAttacks |= g_KnightAttacksBB[cPiece];
- }
- else if (IS_BISHOP(p))
- {
- bbTrueMinorAttacks |= _BishopAttacksBB(cPiece, pos->bbOccupied);
- }
- }
- ASSERT(((bbTrueMinorAttacks & sq) != 0) == (fResult != 0));
- }
-#endif
- return fResult;
-}
-
-//
-// Companion to _IsSquareAttackedByMinor, same transitional purpose:
-// bishop is the only minor that ever x-rays (knights don't), and its
-// x-ray bit is moving fully to pos->bbMinorXrayAttacks in this same
-// change -- unlike the direct-attack case, there's no old-structure
-// fallback to bridge here (nothing else has ever written a minor
-// x-ray bit), so this is just a plain bitboard read. Goes away once
-// rook/queen convert and _EvalKing/_WhoControlsSquareFast read their
-// xray bitboards directly instead of going through any helper.
-//
-// Deliberate behavior change from the old ray-walk, made for speed
-// per direct instruction (2026-09-05): the old BMobCaseTable's
-// fStop=FALSE for BMOB_FRIEND_XRAY/BMOB_ENEMY_GREATER meant the walk
-// kept going -- and kept counting mobility -- through however many
-// x-ray-worthy blockers were stacked consecutively on one ray (e.g. a
-// bishop x-raying an enemy rook, then continuing to x-ray *through*
-// an enemy king sitting right behind it too). _EvalBishop's bitboard
-// version only extends *one* hop past the first x-ray-worthy blocker
-// (recompute with just that blocker excluded, keep what's newly
-// revealed) -- it does not check whether the newly-revealed terminal
-// square is itself x-ray-worthy and continue again. This is simpler
-// and faster, and the position it changes behavior on (>=2 specific
-// piece types stacked on the same diagonal) is rare enough that
-// trading exact fidelity for it was judged worthwhile; if that
-// judgment turns out wrong, the fix is a bounded loop repeating the
-// "exclude terminal blocker, recompute" step until it stops finding a
-// new x-ray-worthy terminal, not a design change.
-//
-// DEBUG-only: cross-checked against a from-scratch mailbox ray-walk
-// that mirrors this same single-hop rule directly (not the old,
-// unbounded-chain rule) -- deliberately not sharing any code with
-// _EvalBishop's own "recompute with blocker excluded" bitboard
-// technique, so this is a genuinely independent check on that
-// technique, not a restatement of it.
-//
-static FLAG
-_IsSquareXrayedByMinor(IN POSITION *pos,
- IN ULONG uColor,
- IN COOR c)
-{
- BITBOARD sq = COOR_TO_BB(c);
- FLAG fResult = (pos->bbMinorXrayAttacks[uColor] & sq) != 0;
-#ifdef DEBUG
- {
- BITBOARD bbTrueXray = 0;
- ULONG u;
- for (u = 1; u < pos->uNonPawnCount[uColor][0]; u++)
- {
- COOR cBishop = pos->cNonPawns[uColor][u];
- ULONG d;
- if (!IS_BISHOP(pos->rgSquare[cBishop].pPiece))
- {
- continue;
- }
- for (d = 0; d < 4; d++)
- {
- // Chains: after marking squares past one x-ray-worthy
- // blocker up to the next piece, re-examine that next
- // piece and keep going if it's worthy too (matches the
- // production chain-following loop above, and rook's
- // identical cross-check).
- COOR cWalk = cBishop + g_iBDeltas[d];
- while (IS_ON_BOARD(cWalk) && IS_EMPTY(pos->rgSquare[cWalk].pPiece))
- {
- cWalk += g_iBDeltas[d];
- }
- while (IS_ON_BOARD(cWalk))
- {
- PIECE pq = pos->rgSquare[cWalk].pPiece;
- FLAG fWorthy;
- if (GET_COLOR(pq) == uColor)
- {
- fWorthy = (IS_BISHOP(pq) || IS_QUEEN(pq));
- }
- else
- {
- fWorthy = (IS_ROOK(pq) || IS_QUEEN(pq) ||
- IS_KING(pq));
- }
- if (!fWorthy)
- {
- break;
- }
- cWalk += g_iBDeltas[d];
- while (IS_ON_BOARD(cWalk))
- {
- bbTrueXray |= COOR_TO_BB(cWalk);
- if (!IS_EMPTY(pos->rgSquare[cWalk].pPiece))
- {
- break;
- }
- cWalk += g_iBDeltas[d];
- }
- }
- }
- }
- ASSERT(((bbTrueXray & sq) != 0) == (fResult != 0));
- }
-#endif
- return fResult;
-}
-
-
-//
-// Rook's turn to convert (board_representation/EVAL.md section 9,
-// 2026-09-05) -- same transitional purpose and same DEBUG cross-check
-// discipline as _IsSquareAttackedByMinor/_IsSquareXrayedByMinor above,
-// now that rook no longer writes ROOK_BIT/ROOK_XRAY_BIT into
-// rgSquare[c|8].bvAttacks at all. Goes away once queen converts and
-// _WhoControlsSquareFast reads pos->bbRookAttacks/bbRookXrayAttacks
-// directly instead of going through a helper.
-//
-static FLAG
-_IsSquareAttackedByRook(IN POSITION *pos,
- IN ULONG uColor,
- IN COOR c)
-{
- BITBOARD sq = COOR_TO_BB(c);
- FLAG fResult = (pos->bbRookAttacks[uColor] & sq) != 0;
-#ifdef DEBUG
- {
- BITBOARD bbTrueRookAttacks = 0;
- ULONG u;
- for (u = 1; u < pos->uNonPawnCount[uColor][0]; u++)
- {
- COOR cPiece = pos->cNonPawns[uColor][u];
- if (IS_ROOK(pos->rgSquare[cPiece].pPiece))
- {
- bbTrueRookAttacks |= _RookAttacksBB(cPiece, pos->bbOccupied);
- }
- }
- ASSERT(((bbTrueRookAttacks & sq) != 0) == (fResult != 0));
- }
-#endif
- return fResult;
-}
-
-//
-// Companion to _IsSquareAttackedByRook, same single-hop x-ray
-// simplification as bishop's _IsSquareXrayedByMinor (deliberate speed
-// tradeoff, not full chain-following -- see _EvalRook's mobility
-// comment). Cross-checked against an independent from-scratch mailbox
-// walk mirroring that same single-hop rule.
-//
-static FLAG
-_IsSquareXrayedByRook(IN POSITION *pos,
- IN ULONG uColor,
- IN COOR c)
-{
- BITBOARD sq = COOR_TO_BB(c);
- FLAG fResult = (pos->bbRookXrayAttacks[uColor] & sq) != 0;
-#ifdef DEBUG
- {
- BITBOARD bbTrueXray = 0;
- ULONG u;
- for (u = 1; u < pos->uNonPawnCount[uColor][0]; u++)
- {
- COOR cRook = pos->cNonPawns[uColor][u];
- ULONG d;
- if (!IS_ROOK(pos->rgSquare[cRook].pPiece))
- {
- continue;
- }
- for (d = 0; d < 4; d++)
- {
- // Unlike bishop's single-hop cross-check, this chains:
- // after marking squares past one x-ray-worthy blocker
- // up to the next piece, re-examine that next piece and
- // keep going if it's worthy too (matches the
- // production chain-following loop above, and the
- // stashed first attempt's blocker-to-blocker bit-scan
- // walk).
- COOR cWalk = cRook + g_iRDeltas[d];
- while (IS_ON_BOARD(cWalk) && IS_EMPTY(pos->rgSquare[cWalk].pPiece))
- {
- cWalk += g_iRDeltas[d];
- }
- while (IS_ON_BOARD(cWalk))
- {
- PIECE pq = pos->rgSquare[cWalk].pPiece;
- FLAG fWorthy;
- if (GET_COLOR(pq) == uColor)
- {
- fWorthy = (IS_ROOK(pq) || IS_QUEEN(pq));
- }
- else
- {
- fWorthy = (IS_QUEEN(pq) || IS_KING(pq));
- }
- if (!fWorthy)
- {
- break;
- }
- cWalk += g_iRDeltas[d];
- while (IS_ON_BOARD(cWalk))
- {
- bbTrueXray |= COOR_TO_BB(cWalk);
- if (!IS_EMPTY(pos->rgSquare[cWalk].pPiece))
- {
- break;
- }
- cWalk += g_iRDeltas[d];
- }
- }
- }
- }
- ASSERT(((bbTrueXray & sq) != 0) == (fResult != 0));
- }
-#endif
- return fResult;
-}
-
-//
-// Queen's turn to convert (board_representation/EVAL.md section 9,
-// 2026-09-05) -- same transitional purpose and same DEBUG cross-check
-// discipline as _IsSquareAttackedByRook/_IsSquareXrayedByRook above,
-// now that queen no longer writes QUEEN_BIT/QUEEN_XRAY_BIT into
-// rgSquare[c|8].bvAttacks at all. Goes away once king converts and
-// _EvalKing reads pos->bbQueenAttacks/bbQueenXrayAttacks directly.
-//
-static FLAG
-_IsSquareAttackedByQueen(IN POSITION *pos,
- IN ULONG uColor,
- IN COOR c)
-{
- BITBOARD sq = COOR_TO_BB(c);
- FLAG fResult = (pos->bbQueenAttacks[uColor] & sq) != 0;
-#ifdef DEBUG
- {
- BITBOARD bbTrueQueenAttacks = 0;
- ULONG u;
- for (u = 1; u < pos->uNonPawnCount[uColor][0]; u++)
- {
- COOR cPiece = pos->cNonPawns[uColor][u];
- if (IS_QUEEN(pos->rgSquare[cPiece].pPiece))
- {
- bbTrueQueenAttacks |= _RookAttacksBB(cPiece, pos->bbOccupied) |
- _BishopAttacksBB(cPiece, pos->bbOccupied);
- }
- }
- ASSERT(((bbTrueQueenAttacks & sq) != 0) == (fResult != 0));
- }
-#endif
- return fResult;
-}
-
-//
-// Companion to _IsSquareAttackedByQueen. Unlike rook/bishop, queen's
-// own case table never x-rays through *any* enemy piece (QMOB_ENEMY_GE
-// always stops) -- only through a friendly queen, or a friendly rook
-// on an orthogonal ray / friendly bishop on a diagonal ray (the same
-// per-ray-family split _EvalQueen's own mobility walk uses). Chains
-// arbitrarily deep, same as rook's own x-ray (not single-hop).
-//
-static FLAG
-_IsSquareXrayedByQueen(IN POSITION *pos,
- IN ULONG uColor,
- IN COOR c)
-{
- BITBOARD sq = COOR_TO_BB(c);
- FLAG fResult = (pos->bbQueenXrayAttacks[uColor] & sq) != 0;
-#ifdef DEBUG
- {
- BITBOARD bbTrueXray = 0;
- ULONG u;
- for (u = 1; u < pos->uNonPawnCount[uColor][0]; u++)
- {
- COOR cQueen = pos->cNonPawns[uColor][u];
- ULONG d;
- if (!IS_QUEEN(pos->rgSquare[cQueen].pPiece))
- {
- continue;
- }
- for (d = 0; d < 8; d++)
- {
- COOR cWalk = cQueen + g_iQKDeltas[d];
- FLAG fOrthogonal;
-
- if (!IS_ON_BOARD(cWalk))
- {
- continue;
- }
- fOrthogonal = (((cWalk & 0xF0) == (cQueen & 0xF0)) ||
- ((cWalk & 0x0F) == (cQueen & 0x0F)));
- while (IS_ON_BOARD(cWalk) && IS_EMPTY(pos->rgSquare[cWalk].pPiece))
- {
- cWalk += g_iQKDeltas[d];
- }
- while (IS_ON_BOARD(cWalk))
- {
- PIECE pq = pos->rgSquare[cWalk].pPiece;
- FLAG fWorthy;
-
- if (GET_COLOR(pq) != uColor)
- {
- break;
- }
- fWorthy = IS_QUEEN(pq) ||
- (fOrthogonal ? IS_ROOK(pq) : IS_BISHOP(pq));
- if (!fWorthy)
- {
- break;
- }
- cWalk += g_iQKDeltas[d];
- while (IS_ON_BOARD(cWalk))
- {
- bbTrueXray |= COOR_TO_BB(cWalk);
- if (!IS_EMPTY(pos->rgSquare[cWalk].pPiece))
- {
- break;
- }
- cWalk += g_iQKDeltas[d];
- }
- }
- }
- }
- ASSERT(((bbTrueXray & sq) != 0) == (fResult != 0));
- }
-#endif
- return fResult;
-}
-
-//
-// King's turn to convert (board_representation/EVAL.md section 9,
-// 2026-09-05) -- the last piece type contributing to bvAttacks. Same
-// transitional-helper purpose as the others, but simpler: no mobility
-// computation, no x-ray (a king can't move through a blocker), so
-// there's no companion _IsSquareXrayedByKing.
-//
-static FLAG
-_IsSquareAttackedByKing(IN POSITION *pos,
- IN ULONG uColor,
- IN COOR c)
-{
- BITBOARD sq = COOR_TO_BB(c);
- FLAG fResult = (pos->bbKingAttacks[uColor] & sq) != 0;
-#ifdef DEBUG
- {
- BITBOARD bbTrueKingAttacks = g_KingAttacksBB[pos->cNonPawns[uColor][0]];
- ASSERT(((bbTrueKingAttacks & sq) != 0) == (fResult != 0));
- }
-#endif
- return fResult;
-}
-
static ULONG
_WhoControlsSquareFast(IN POSITION *pos,
IN COOR c)
@@ -1574,55 +1177,46 @@ Return value:
**/
{
//
- // bvAttacks no longer carries the pawn bit (pawns write
- // pos->bbPawnAttacks[2] directly instead, see
- // _PopulatePawnAttackBits) -- OR it back in at its usual bit
- // position (PAWN_BIT) so g_SwapTable's indexing below sees the
- // same bit shape it always has.
+ // board_representation/EVAL.md section 9: bvAttacks/ATTACK_BITV
+ // retired entirely now that king (the last piece to write it) has
+ // converted -- every side's presence at this square is read
+ // straight off its own bbXAttacks accumulator instead. Bit
+ // positions (PAWN_BIT/MINOR_BIT/ROOK_BIT/QUEEN_BIT/KING_BIT) are
+ // unchanged so g_SwapTable's indexing below still sees the same
+ // shape it always has; x-ray-only presence (bbMinorXrayAttacks/
+ // bbRookXrayAttacks/bbQueenXrayAttacks) ORs into the same
+ // byte-scale bit as its direct-attack counterpart, matching the
+ // old struct's .uSmall/.uXray sharing one bit position for
+ // "attacks or x-rays" (see g_SwapTable's own construction). King
+ // has no x-ray (can't move through a blocker). This function is
+ // only ever called after *both* kings finish evaluating (the
+ // passed-pawn re-check and trapped-piece/danger passes all run
+ // after Eval()'s king-eval block), so pos->bbKingAttacks is always
+ // fully populated for both colors here -- unlike _EvalKing's own,
+ // deliberately asymmetric internal bvAttack (see that function's
+ // comment), this is a plain, symmetric fact query.
//
- // .uXray is a standalone byte view (see _IsSquareXrayedByMinor's
- // comment on why the byte-scale MINOR_BIT, not MINOR_XRAY_BIT, is
- // the right constant to OR in here) -- bishop's, rook's, and
- // queen's xray contributions all moved to pos->bbMinorXrayAttacks/
- // bbRookXrayAttacks/bbQueenXrayAttacks. King has no x-ray (can't
- // move through a blocker), and its direct-attack contribution is
- // added symmetrically for both colors below via
- // _IsSquareAttackedByKing -- unlike _EvalKing's own internal
- // bvAttack (which deliberately drops the *enemy* king's
- // contribution, see that function's comment on the black-then-
- // white evaluation-order asymmetry this sidesteps), this function
- // is only ever called after *both* kings have finished evaluating
- // (the passed-pawn re-check runs after the king-eval block in
- // Eval()'s own sequencing), so pos->bbKingAttacks is always fully
- // populated for both colors by the time this runs -- no asymmetry
- // to worry about here, this is a plain, symmetric fact query.
- ULONG uWhite = pos->rgSquare[c|8].bvAttacks[WHITE].uSmall |
- pos->rgSquare[c|8].bvAttacks[WHITE].uXray |
- ((pos->bbPawnAttacks[WHITE] & COOR_TO_BB(c)) ?
- PAWN_BIT : 0) |
- (_IsSquareAttackedByMinor(pos, WHITE, c) ? MINOR_BIT : 0) |
- (_IsSquareXrayedByMinor(pos, WHITE, c) ? MINOR_BIT : 0) |
- (_IsSquareAttackedByRook(pos, WHITE, c) ? ROOK_BIT : 0) |
- (_IsSquareXrayedByRook(pos, WHITE, c) ? ROOK_BIT : 0) |
- (_IsSquareAttackedByQueen(pos, WHITE, c) ? QUEEN_BIT : 0) |
- (_IsSquareXrayedByQueen(pos, WHITE, c) ? QUEEN_BIT : 0) |
- (_IsSquareAttackedByKing(pos, WHITE, c) ? KING_BIT : 0);
- ULONG uBlack = pos->rgSquare[c|8].bvAttacks[BLACK].uSmall |
- pos->rgSquare[c|8].bvAttacks[BLACK].uXray |
- ((pos->bbPawnAttacks[BLACK] & COOR_TO_BB(c)) ?
- PAWN_BIT : 0) |
- (_IsSquareAttackedByMinor(pos, BLACK, c) ? MINOR_BIT : 0) |
- (_IsSquareXrayedByMinor(pos, BLACK, c) ? MINOR_BIT : 0) |
- (_IsSquareAttackedByRook(pos, BLACK, c) ? ROOK_BIT : 0) |
- (_IsSquareXrayedByRook(pos, BLACK, c) ? ROOK_BIT : 0) |
- (_IsSquareAttackedByQueen(pos, BLACK, c) ? QUEEN_BIT : 0) |
- (_IsSquareXrayedByQueen(pos, BLACK, c) ? QUEEN_BIT : 0) |
- (_IsSquareAttackedByKing(pos, BLACK, c) ? KING_BIT : 0);
+ BITBOARD sq = COOR_TO_BB(c);
+ ULONG uWhite = ((pos->bbPawnAttacks[WHITE] & sq) ? PAWN_BIT : 0) |
+ ((pos->bbMinorAttacks[WHITE] & sq) ? MINOR_BIT : 0) |
+ ((pos->bbMinorXrayAttacks[WHITE] & sq) ? MINOR_BIT : 0) |
+ ((pos->bbRookAttacks[WHITE] & sq) ? ROOK_BIT : 0) |
+ ((pos->bbRookXrayAttacks[WHITE] & sq) ? ROOK_BIT : 0) |
+ ((pos->bbQueenAttacks[WHITE] & sq) ? QUEEN_BIT : 0) |
+ ((pos->bbQueenXrayAttacks[WHITE] & sq) ? QUEEN_BIT : 0) |
+ ((pos->bbKingAttacks[WHITE] & sq) ? KING_BIT : 0);
+ ULONG uBlack = ((pos->bbPawnAttacks[BLACK] & sq) ? PAWN_BIT : 0) |
+ ((pos->bbMinorAttacks[BLACK] & sq) ? MINOR_BIT : 0) |
+ ((pos->bbMinorXrayAttacks[BLACK] & sq) ? MINOR_BIT : 0) |
+ ((pos->bbRookAttacks[BLACK] & sq) ? ROOK_BIT : 0) |
+ ((pos->bbRookXrayAttacks[BLACK] & sq) ? ROOK_BIT : 0) |
+ ((pos->bbQueenAttacks[BLACK] & sq) ? QUEEN_BIT : 0) |
+ ((pos->bbQueenXrayAttacks[BLACK] & sq) ? QUEEN_BIT : 0) |
+ ((pos->bbKingAttacks[BLACK] & sq) ? KING_BIT : 0);
ULONG u;
PIECE p;
CHAR ch;
- ASSERT((c + 8) == (c | 8));
ASSERT((uWhite & 0xFFFFFF00) == 0);
ASSERT((uBlack & 0xFFFFFF00) == 0);
@@ -1649,7 +1243,13 @@ Return value:
Routine description:
- Zero out the attack table before building it.
+ Zero out the Eval()-scoped attack-bitboard accumulators before
+ building them for this call. Used to clear the old per-square
+ rgSquare[c|8].bvAttacks/ATTACK_BITV structure too (a full-board
+ macro-unrolled loop, since every square's storage needed zeroing);
+ retired along with that structure (2026-09-05, board_
+ representation/EVAL.md section 9) -- nothing left to clear but the
+ bbXAttacks accumulators themselves.
Parameters:
@@ -1660,33 +1260,9 @@ Return value:
void
**/
-#define CLEAR_A_SQ \
- pos->rgSquare[c].bvAttacks[0].uWholeThing = 0; \
- pos->rgSquare[c].bvAttacks[1].uWholeThing = 0;
-
-#define CLEAR_A_RANK \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c += 9;
-
-#define CLEAR_SHORT_RANK \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c++; \
- CLEAR_A_SQ; c += 10;
-
static void
_ClearAttackTables(IN OUT POSITION *pos)
{
- register COOR c = 8;
pos->bbMinorAttacks[WHITE] = pos->bbMinorAttacks[BLACK] = 0;
pos->bbMinorXrayAttacks[WHITE] = pos->bbMinorXrayAttacks[BLACK] = 0;
pos->bbRookAttacks[WHITE] = pos->bbRookAttacks[BLACK] = 0;
@@ -1694,33 +1270,6 @@ _ClearAttackTables(IN OUT POSITION *pos)
pos->bbQueenAttacks[WHITE] = pos->bbQueenAttacks[BLACK] = 0;
pos->bbQueenXrayAttacks[WHITE] = pos->bbQueenXrayAttacks[BLACK] = 0;
pos->bbKingAttacks[WHITE] = pos->bbKingAttacks[BLACK] = 0;
-#if 1
- CLEAR_A_SQ; c += 16;
- CLEAR_A_SQ; c += 16;
- CLEAR_A_SQ; c += 16;
- CLEAR_A_SQ; c += 16;
- CLEAR_A_SQ; c += 16;
- CLEAR_A_SQ; c += 16;
- CLEAR_A_SQ; c += 16;
- CLEAR_A_SQ; c = 9;
- CLEAR_SHORT_RANK;
- CLEAR_SHORT_RANK;
- CLEAR_SHORT_RANK;
- CLEAR_SHORT_RANK;
- CLEAR_SHORT_RANK;
- CLEAR_SHORT_RANK;
- CLEAR_SHORT_RANK;
- CLEAR_SHORT_RANK;
-#else
- CLEAR_A_RANK;
- CLEAR_A_RANK;
- CLEAR_A_RANK;
- CLEAR_A_RANK;
- CLEAR_A_RANK;
- CLEAR_A_RANK;
- CLEAR_A_RANK;
- CLEAR_A_RANK;
-#endif
}
@@ -1926,6 +1475,24 @@ Return value:
// IDEA: scale the candidate passer bonus based on rank AND on
// the distance the helper(s) have to go to get into position.
//
+ // KNOWN BUG, found 2026-09-05 while removing rgSquare[c|8].bvAttacks
+ // entirely (board_representation/EVAL.md section 9), NOT fixed
+ // here -- flagged for its own separate investigation instead of
+ // being bundled into a mechanical cleanup commit. This function
+ // runs from _EvalPawns, which is the *first* piece type evaluated
+ // each Eval() call -- every non-pawn piece (and, since commit
+ // 57502d6, pawns themselves) writes its attack bits later in the
+ // same call, so the "is c1 safe to advance a helper pawn into"
+ // check below has read an always-zero attack table for as long as
+ // bvAttacks has existed in its post-57502d6 form. The condition
+ // this used to gate on (skip a candidate passer if its helper
+ // square isn't actually safe to advance into) has therefore been
+ // unconditionally true -- a silent no-op -- since that commit,
+ // not something introduced by today's cleanup. Preserved exactly
+ // as that already-dead behavior (unconditional) rather than
+ // "fixed" here, since a real fix changes eval scoring and deserves
+ // its own before/after check, not one buried in a rename commit.
+ //
uHelpers = 0;
d1 = 16 * g_iAhead[uColor];
ASSERT(-d1 == 16 * g_iBehind[uColor]);
@@ -1933,39 +1500,33 @@ Return value:
if ((IS_ON_BOARD(c1)) && (pHash->uCountPerFile[uColor][FILE(c1) + 1]))
{
ASSERT(pos->bbPawns[uColor] & BBFILE[FILE(c1)]);
- if (!(pos->rgSquare[c1 + 8].bvAttacks[FLIP(uColor)].uWholeThing) ||
- (pos->rgSquare[c1 + 8].bvAttacks[uColor].uWholeThing))
+ //
+ // The square c1 the place a helper pawn must get to in
+ // order to aide the candidate past a sentry.
+ //
+ if (pos->rgSquare[c1].pPiece == pHelper)
+ {
+ uHelpers = 1;
+ goto do_left;
+ }
+
+ //
+ // There is no helper pawn in the support position yet.
+ // See if one can get there.
+ //
+ c1 = c1 - d1;
+ while (IS_ON_BOARD(c1))
{
- //
- // The square c1 the place a helper pawn must get to in
- // order to aide the candidate past a sentry.
- //
if (pos->rgSquare[c1].pPiece == pHelper)
{
uHelpers = 1;
- goto do_left;
+ break;
}
-
- //
- // There is no helper pawn in the support position yet.
- // See if one can get there.
- //
- c1 = c1 - d1;
- while (IS_ON_BOARD(c1) &&
- ((!(pos->rgSquare[c1+8].bvAttacks[FLIP(uColor)].uWholeThing)) ||
- (pos->rgSquare[c1+8].bvAttacks[uColor].uWholeThing)))
+ else if (pos->rgSquare[c1].pPiece == pSentry)
{
- if (pos->rgSquare[c1].pPiece == pHelper)
- {
- uHelpers = 1;
- break;
- }
- else if (pos->rgSquare[c1].pPiece == pSentry)
- {
- break;
- }
- c1 = c1 - d1;
+ break;
}
+ c1 = c1 - d1;
}
}
@@ -1975,39 +1536,33 @@ Return value:
{
ASSERT(pos->bbPawns[uColor] & BBFILE[FILE(c1)]);
- if (!(pos->rgSquare[c1 + 8].bvAttacks[FLIP(uColor)].uWholeThing) ||
- (pos->rgSquare[c1 + 8].bvAttacks[uColor].uWholeThing))
+ //
+ // The square c1 is the place a helper pawn must get to in
+ // order to aide the candidate.
+ //
+ if (pos->rgSquare[c1].pPiece == pHelper)
+ {
+ uHelpers++;
+ goto done_helpers;
+ }
+
+ //
+ // There is no pawn in the left support position yet. See
+ // if one can get there.
+ //
+ c1 -= d1;
+ while (IS_ON_BOARD(c1))
{
- //
- // The square c1 is the place a helper pawn must get to in
- // order to aide the candidate.
- //
if (pos->rgSquare[c1].pPiece == pHelper)
{
uHelpers++;
- goto done_helpers;
+ break;
}
-
- //
- // There is no pawn in the left support position yet. See
- // if one can get there.
- //
- c1 -= d1;
- while (IS_ON_BOARD(c1) &&
- ((!(pos->rgSquare[c1+8].bvAttacks[FLIP(uColor)].uWholeThing)) ||
- (pos->rgSquare[c1 + 8].bvAttacks[uColor].uWholeThing)))
+ else if (pos->rgSquare[c1].pPiece == pSentry)
{
- if (pos->rgSquare[c1].pPiece == pHelper)
- {
- uHelpers++;
- break;
- }
- else if (pos->rgSquare[c1].pPiece == pSentry)
- {
- break;
- }
- c1 -= d1;
+ break;
}
+ c1 -= d1;
}
}
@@ -2224,14 +1779,14 @@ Return value:
// diagonals need the *opposite* file excluded to prevent same-row
// wraparound) -- not repeated here.
//
-// Unlike the old version, this does NOT write PAWN_BIT into
-// rgSquare[c|8].bvAttacks -- pos->bbPawnAttacks[2] (chess.h) is now
-// the single source of truth for "does a pawn attack this square",
-// read directly by every consumer (UNSAFE_FOR_MINOR's old callers,
-// UNSAFE_FOR_ROOK/_QUEEN, _EvalKing's bvAttack/bvDefend). Knight/
-// bishop/rook/queen/king still populate/read the rest of bvAttacks
-// (uMinor/uRook/uQueen/uKing) the old way, so _ClearAttackTables(pos)
-// still needs to run here first.
+// Unlike the old version, this does NOT write PAWN_BIT into the old
+// rgSquare[c|8].bvAttacks/ATTACK_BITV mechanism (retired entirely as
+// of 2026-09-05, once king -- the last piece writing it -- converted
+// too) -- pos->bbPawnAttacks[2] (chess.h) is the single source of
+// truth for "does a pawn attack this square", read directly by every
+// consumer. _ClearAttackTables(pos) still needs to run here first, to
+// zero the other bbXAttacks accumulators knight/bishop/rook/queen/king
+// populate as they each evaluate.
static void
_PopulatePawnAttackBits(IN OUT POSITION *pos)
/**
@@ -4210,62 +3765,35 @@ Return value:
p = pos->rgSquare[cSquare].pPiece;
//
- // bvAttacks no longer carries the pawn bit (pawns write
- // pos->bbPawnAttacks[2] directly instead, see
- // _PopulatePawnAttackBits) -- OR it back in here from the
- // bitboard, keyed off the real board square (cSquare,
- // before the |8 below flips it into the invisible-half
- // storage index bvAttacks itself uses).
- //
- // No enemy-king contribution here, by direct instruction
- // (2026-09-05): the old mailbox version was already
- // asymmetric here (kings evaluate black-then-white, so
- // white's computation could see black's already-written
- // king bit but black's could never see white's, since
- // white hadn't run yet) -- rather than preserve or
- // "upgrade" that asymmetry now that both colors go through
- // an explicit helper either way, neither side sees the
- // enemy king as a threat here, matching the side that
- // already couldn't.
+ // board_representation/EVAL.md section 9: bvAttacks/
+ // ATTACK_BITV retired entirely -- every bit here now comes
+ // straight from a bbXAttacks accumulator read, no more
+ // c|8 shadow-index struct storage or per-square writes.
+ // No enemy-king contribution in bvAttack, by direct
+ // instruction (see this function's header comment on the
+ // black-then-white evaluation-order asymmetry this
+ // sidesteps). bvDefend's own-king bit is real, load-
+ // bearing signal (see the bvDefend &= ~8 below, which
+ // strips it back out when the square is x-rayed or
+ // multiply attacked -- "a lone king isn't adequate defense
+ // against that") -- not just self-consistency noise, so
+ // it keeps its own-color check.
//
- bvAttack = pos->rgSquare[cSquare|8].bvAttacks[ufColor].uSmall |
- ((pos->bbPawnAttacks[ufColor] & COOR_TO_BB(cSquare)) ?
- PAWN_BIT : 0) |
- (_IsSquareAttackedByMinor(pos, ufColor, cSquare) ?
- MINOR_BIT : 0) |
- (_IsSquareAttackedByRook(pos, ufColor, cSquare) ?
- ROOK_BIT : 0) |
- (_IsSquareAttackedByQueen(pos, ufColor, cSquare) ?
- QUEEN_BIT : 0);
{
- COOR cRealSquare = cSquare;
- cSquare |= 8;
- bvXray = pos->rgSquare[cSquare].bvAttacks[ufColor].uXray |
- (_IsSquareXrayedByMinor(pos, ufColor, cRealSquare) ?
- MINOR_BIT : 0) |
- (_IsSquareXrayedByRook(pos, ufColor, cRealSquare) ?
- ROOK_BIT : 0) |
- (_IsSquareXrayedByQueen(pos, ufColor, cRealSquare) ?
- QUEEN_BIT : 0);
- //
- // bvDefend's own-king bit is real, load-bearing signal
- // (see the bvDefend &= ~8 below, which strips it back
- // out when the square is x-rayed or multiply attacked
- // -- "a lone king isn't adequate defense against
- // that") -- not just self-consistency noise, so this
- // one keeps its own-color check.
- //
- bvDefend = pos->rgSquare[cSquare].bvAttacks[uColor].uSmall |
- ((pos->bbPawnAttacks[uColor] & COOR_TO_BB(cRealSquare)) ?
- PAWN_BIT : 0) |
- (_IsSquareAttackedByMinor(pos, uColor, cRealSquare) ?
- MINOR_BIT : 0) |
- (_IsSquareAttackedByRook(pos, uColor, cRealSquare) ?
- ROOK_BIT : 0) |
- (_IsSquareAttackedByQueen(pos, uColor, cRealSquare) ?
- QUEEN_BIT : 0) |
- (_IsSquareAttackedByKing(pos, uColor, cRealSquare) ?
- KING_BIT : 0);
+ BITBOARD sq = COOR_TO_BB(cSquare);
+
+ bvAttack = ((pos->bbPawnAttacks[ufColor] & sq) ? PAWN_BIT : 0) |
+ ((pos->bbMinorAttacks[ufColor] & sq) ? MINOR_BIT : 0) |
+ ((pos->bbRookAttacks[ufColor] & sq) ? ROOK_BIT : 0) |
+ ((pos->bbQueenAttacks[ufColor] & sq) ? QUEEN_BIT : 0);
+ bvXray = ((pos->bbMinorXrayAttacks[ufColor] & sq) ? MINOR_BIT : 0) |
+ ((pos->bbRookXrayAttacks[ufColor] & sq) ? ROOK_BIT : 0) |
+ ((pos->bbQueenXrayAttacks[ufColor] & sq) ? QUEEN_BIT : 0);
+ bvDefend = ((pos->bbPawnAttacks[uColor] & sq) ? PAWN_BIT : 0) |
+ ((pos->bbMinorAttacks[uColor] & sq) ? MINOR_BIT : 0) |
+ ((pos->bbRookAttacks[uColor] & sq) ? ROOK_BIT : 0) |
+ ((pos->bbQueenAttacks[uColor] & sq) ? QUEEN_BIT : 0) |
+ ((pos->bbKingAttacks[uColor] & sq) ? KING_BIT : 0);
}
//