summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/chess.h13
-rwxr-xr-xsrc/eval.c490
2 files changed, 311 insertions, 192 deletions
diff --git a/src/chess.h b/src/chess.h
index 305c681..421667f 100755
--- a/src/chess.h
+++ b/src/chess.h
@@ -739,6 +739,19 @@ typedef struct _POSITION
// 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];
+
ULONG uWhiteSqBishopCount[2]; // num bishops on white squares
SCORE iMaterialBalance[2]; // material balance
diff --git a/src/eval.c b/src/eval.c
index bb19d9d..9eafc1a 100755
--- a/src/eval.c
+++ b/src/eval.c
@@ -1260,51 +1260,153 @@ _IsSquareXrayedByMinor(IN POSITION *pos,
}
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];
- FLAG fFoundXrayBlocker = FALSE;
- //
- // First pass: walk to the first blocker (or edge),
- // exactly like the direct-attack ray would, purely to
- // classify whether that first blocker is x-ray-worthy
- // -- no marking yet.
- //
while (IS_ON_BOARD(cWalk) && IS_EMPTY(pos->rgSquare[cWalk].pPiece))
{
cWalk += g_iBDeltas[d];
}
- if (IS_ON_BOARD(cWalk))
+ while (IS_ON_BOARD(cWalk))
{
PIECE pq = pos->rgSquare[cWalk].pPiece;
+ FLAG fWorthy;
if (GET_COLOR(pq) == uColor)
{
- fFoundXrayBlocker = (IS_BISHOP(pq) || IS_QUEEN(pq));
+ fWorthy = (IS_BISHOP(pq) || IS_QUEEN(pq));
}
else
{
- fFoundXrayBlocker = (IS_ROOK(pq) || IS_QUEEN(pq) ||
- IS_KING(pq));
+ 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];
}
}
- if (!fFoundXrayBlocker)
+ }
+ }
+ 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))
{
- continue;
+ cWalk += g_iRDeltas[d];
}
- //
- // Single hop past that one blocker: mark empty
- // squares as x-ray, then mark and stop at the very
- // next piece of any kind (or the edge) -- do not
- // classify that second piece and potentially continue
- // again, unlike the old chain-following walk.
- //
- cWalk += g_iBDeltas[d];
while (IS_ON_BOARD(cWalk))
{
- bbTrueXray |= COOR_TO_BB(cWalk);
- if (!IS_EMPTY(pos->rgSquare[cWalk].pPiece))
+ 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_iBDeltas[d];
+ 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];
+ }
}
}
}
@@ -1314,7 +1416,6 @@ _IsSquareXrayedByMinor(IN POSITION *pos,
return fResult;
}
-
static ULONG
_WhoControlsSquareFast(IN POSITION *pos,
IN COOR c)
@@ -1348,21 +1449,26 @@ Return value:
//
// .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 contribution to it
- // moved to pos->bbMinorXrayAttacks, rook/queen's haven't converted
- // yet so their xray sub-bits are still valid straight off .uXray.
+ // the right constant to OR in here) -- bishop's and now rook's
+ // contributions moved to pos->bbMinorXrayAttacks/bbRookXrayAttacks,
+ // queen hasn't converted yet so its xray sub-bit is still valid
+ // straight off .uXray.
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);
+ (_IsSquareXrayedByMinor(pos, WHITE, c) ? MINOR_BIT : 0) |
+ (_IsSquareAttackedByRook(pos, WHITE, c) ? ROOK_BIT : 0) |
+ (_IsSquareXrayedByRook(pos, WHITE, c) ? ROOK_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);
+ (_IsSquareXrayedByMinor(pos, BLACK, c) ? MINOR_BIT : 0) |
+ (_IsSquareAttackedByRook(pos, BLACK, c) ? ROOK_BIT : 0) |
+ (_IsSquareXrayedByRook(pos, BLACK, c) ? ROOK_BIT : 0);
ULONG u;
PIECE p;
CHAR ch;
@@ -1434,6 +1540,8 @@ _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;
+ pos->bbRookXrayAttacks[WHITE] = pos->bbRookXrayAttacks[BLACK] = 0;
#if 1
CLEAR_A_SQ; c += 16;
CLEAR_A_SQ; c += 16;
@@ -2835,38 +2943,51 @@ Return value:
// X-ray: squares seen through a friendly bishop/queen
// (BMOB_FRIEND_XRAY) or an enemy rook/queen/king
// (BMOB_ENEMY_GREATER) -- the only two case-table entries that
- // don't stop the ray outright. Recompute with just that
- // blocker excluded from occupancy and keep only the squares
- // beyond the original attack set.
+ // don't stop the ray outright.
//
- // Deliberate behavior change from the old ray-walk, for speed
- // (2026-09-05): this is a single hop only. The old walk 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, both
- // contributing to the mobility count along the way); this
- // version does not re-check whether the newly-revealed
- // terminal square is itself x-ray-worthy and extend again.
- // Judged an acceptable trade given how rare a ray with >=2
- // consecutive x-ray-worthy pieces is -- see
- // _IsSquareXrayedByMinor's DEBUG cross-check, which verifies
- // against this same single-hop rule (not the old unbounded
- // one) via an independent mailbox walk.
+ // Originally shipped 2026-09-05 as a single-hop-only
+ // approximation (see rook's identical, now-superseded comment
+ // for the reasoning) on the theory that >=2 consecutive
+ // x-ray-worthy blockers on one diagonal is rare. Backported
+ // rook's bounded chain-following fix once that theory was
+ // actually checked instead of assumed: bishop's own rate is
+ // indeed low (2/191, ~1%, vs. rook's 14%) but the fix is
+ // mechanically identical and effectively free (the loop only
+ // iterates again when a real chained battery exists), so there
+ // is no reason left to keep the approximation once rook's
+ // fidelity-preserving version exists to copy. See
+ // _IsSquareXrayedByMinor's DEBUG cross-check, updated to the
+ // same chain-following rule.
//
{
- BITBOARD bbXrayBlockers = bbAttack &
- (pos->bbPieces[uColor][BISHOP] | pos->bbPieces[uColor][QUEEN] |
- pos->bbPieces[FLIP(uColor)][ROOK] |
- pos->bbPieces[FLIP(uColor)][QUEEN] |
- COOR_TO_BB(pos->cNonPawns[FLIP(uColor)][0]));
- if (bbXrayBlockers)
+ BITBOARD bbXrayAccum = 0;
+ BITBOARD bbExclude = 0;
+ BITBOARD bbFrontier = bbAttack;
+ for (;;)
{
- BITBOARD bbBeyond =
- _BishopAttacksBB(c, pos->bbOccupied & ~bbXrayBlockers) &
- ~bbAttack;
- pos->bbMinorXrayAttacks[uColor] |= bbBeyond;
+ BITBOARD bbBlockers = bbFrontier &
+ (pos->bbPieces[uColor][BISHOP] |
+ pos->bbPieces[uColor][QUEEN] |
+ pos->bbPieces[FLIP(uColor)][ROOK] |
+ pos->bbPieces[FLIP(uColor)][QUEEN] |
+ COOR_TO_BB(pos->cNonPawns[FLIP(uColor)][0]));
+ BITBOARD bbBeyond;
+
+ if (!bbBlockers)
+ {
+ break;
+ }
+ bbExclude |= bbBlockers;
+ bbBeyond = _BishopAttacksBB(c, pos->bbOccupied & ~bbExclude) &
+ ~bbAttack & ~bbXrayAccum;
+ if (!bbBeyond)
+ {
+ break;
+ }
+ bbXrayAccum |= bbBeyond;
+ bbFrontier = bbBeyond;
}
+ pos->bbMinorXrayAttacks[uColor] |= bbXrayAccum;
}
bbMobility = (bbAttack & bbEnemyNonPawnOcc) |
@@ -3207,52 +3328,14 @@ Return value:
**/
{
- static const UCHAR RMobCaseTable[2][14] =
- {
- {// (black)
- RMOB_EMPTY, // EMPTY_SQUARE (0)
- RMOB_INVALID, // INVALID_PIECE (1)
- RMOB_FRIEND_BLOCK, // BLACK_PAWN (2)
- RMOB_ENEMY_LESS, // WHITE_PAWN (3)
- RMOB_FRIEND_BLOCK, // BLACK_KNIGHT (4)
- RMOB_ENEMY_LESS, // WHITE_KNIGHT (5)
- RMOB_FRIEND_BLOCK, // BLACK_BISHOP (6)
- RMOB_ENEMY_LESS, // WHITE_BISHOP (7)
- RMOB_FRIEND_ROOK, // BLACK_ROOK (8)
- RMOB_ENEMY_SAME, // WHITE_ROOK (9)
- RMOB_FRIEND_QUEEN, // BLACK_QUEEN (10)
- RMOB_ENEMY_GREATER, // WHITE_QUEEN (11)
- RMOB_FRIEND_BLOCK, // BLACK_KING (12)
- RMOB_ENEMY_GREATER, // WHITE_KING (13)
- },
- {// (white)
- RMOB_EMPTY, // EMPTY_SQUARE (0)
- RMOB_INVALID, // INVALID_PIECE (1)
- RMOB_ENEMY_LESS, // BLACK_PAWN (2)
- RMOB_FRIEND_BLOCK, // WHITE_PAWN (3)
- RMOB_ENEMY_LESS, // BLACK_KNIGHT (4)
- RMOB_FRIEND_BLOCK, // WHITE_KNIGHT (5)
- RMOB_ENEMY_LESS, // BLACK_BISHOP (6)
- RMOB_FRIEND_BLOCK, // WHITE_BISHOP (7)
- RMOB_ENEMY_SAME, // BLACK_ROOK (8)
- RMOB_FRIEND_ROOK, // WHITE_ROOK (9)
- RMOB_ENEMY_GREATER, // BLACK_QUEEN (10)
- RMOB_FRIEND_QUEEN, // WHITE_QUEEN (11)
- RMOB_ENEMY_GREATER, // BLACK_KING (12)
- RMOB_FRIEND_BLOCK, // WHITE_KING (13)
- },
- };
-
PIECE p;
ULONG uPawnFile = FILE(c) + 1;
ULONG uColor;
ULONG u;
- ULONG uCurrentMobility;
ULONG uMaxMobility;
ULONG uTotalMobility;
COOR cSquare;
BITBOARD bb;
- ULONG uBit;
SCORE i;
ASSERT(IS_ON_BOARD(c));
@@ -3413,111 +3496,130 @@ Return value:
"increase in value/pawns");
//
- // Rook mobility
+ // Rook mobility (and update attack tables) -- board_representation/
+ // EVAL.md section 1b/9: _RookAttacksBB(c, pos->bbOccupied)
+ // (generate.c's magic-bitboard slider lookup) gives the whole
+ // ray-to-first-blocker attack set in one shot, same technique
+ // already landed for knight/bishop. The old RMobCaseTable's six
+ // live cases collapse to:
+ // - terminal enemy rook/queen/king (RMOB_ENEMY_SAME/_GREATER):
+ // counts unconditionally, no unsafe check -- capturing an
+ // equal-or-higher piece is never "unsafe" in the mobility
+ // sense. Queen/king additionally x-ray past (_GREATER); rook
+ // does not (_SAME).
+ // - empty or terminal enemy pawn/knight/bishop (RMOB_EMPTY /
+ // RMOB_ENEMY_LESS): counts unless the square is attacked by an
+ // enemy pawn or minor -- both terminal-square categories
+ // together are exactly "not friend-occupied and not
+ // enemy-rook/queen/king-occupied," the same partition
+ // bishop/knight's reductions already use with their own value
+ // thresholds.
+ // - any friendly piece (RMOB_FRIEND_BLOCK/_ROOK/_QUEEN): never
+ // counts, simply excluded by the friendly-occupied mask.
+ // Friendly rook/queen additionally x-ray past (no mobility
+ // credit at the blocker itself, matching the old table); a
+ // friendly rook blocker also earns the connected-rook bonus.
//
- u = uMaxMobility = uTotalMobility = 0;
- ASSERT(g_iRDeltas[u] != 0);
- do
+ pos->cPiece = c;
{
- // Ray-invariant, same reasoning as the queen's fOrthogonalRay:
- // every square on this ray shares the same rank relationship to
- // c as the first step does.
- FLAG fHoriz;
+ BITBOARD bbAttack = _RookAttacksBB(c, pos->bbOccupied);
+ BITBOARD bbFriendOcc = _BuildFriendlySideBB(pos, uColor);
+ BITBOARD bbEnemyGE = pos->bbPieces[FLIP(uColor)][ROOK] |
+ pos->bbPieces[FLIP(uColor)][QUEEN] |
+ COOR_TO_BB(pos->cNonPawns[FLIP(uColor)][0]);
+ BITBOARD bbUnsafeForRook = pos->bbPawnAttacks[FLIP(uColor)] |
+ pos->bbMinorAttacks[FLIP(uColor)];
+ BITBOARD bbMobility;
+ BITBOARD bbFriendRook;
+ ULONG d;
- uCurrentMobility = 0;
- uBit = ROOK_BIT;
- cSquare = c + g_iRDeltas[u];
- fHoriz = ((cSquare & 0xF0) == (c & 0xF0));
+ pos->bbRookAttacks[uColor] |= bbAttack;
- while(IS_ON_BOARD(cSquare))
+ //
+ // Connected-rook bonus: a friendly rook reached on this ray is
+ // a battery partner. At most one bit per ray direction can be
+ // this case (the attack set stops there), but more than one
+ // direction can each terminate at a different friendly rook.
+ //
+ bbFriendRook = bbAttack & pos->bbPieces[uColor][ROOK];
+ while (bbFriendRook)
{
- FLAG fStop;
-
- //
- // Twiddle our attack table bits.
- //
- pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
- ASSERT((cSquare | 8) == (cSquare + 8));
+ COOR cBlocker = CoorFromBitBoardRank8ToRank1(&bbFriendRook);
+ FLAG fHoriz = (RANK(cBlocker) == RANK(c));
+ EVAL_TERM(uColor,
+ ROOK,
+ cBlocker,
+ pos->iScore[uColor],
+ (ROOK_CONNECTED_HORIZ * fHoriz +
+ ROOK_CONNECTED_VERT * FLIP(fHoriz)),
+ "rook connected");
+ }
- //
- // What did we hit? Dispatched via switch instead of an
- // indirect call through a function pointer -- same
- // rationale as the bishop ray-walk above.
- //
- p = pos->rgSquare[cSquare].pPiece;
- switch (RMobCaseTable[uColor][p])
+ //
+ // X-ray: squares seen through a friendly rook/queen battery
+ // partner or an x-rayable enemy queen/king -- the only
+ // case-table entries that don't stop the ray outright.
+ //
+ // Unlike bishop's single-hop cut, this chains until it stops
+ // finding a new x-ray-worthy terminal: checked against the
+ // curated suites (2026-09-05), 14% of positions (27/191) have
+ // a genuine 2+-deep rook/queen battery on some ray, far more
+ // common than bishop's "rare" diagonal case -- a one-hop
+ // approximation here would be a real fidelity loss, not a
+ // negligible one. The stashed first bitboard-eval attempt
+ // (git stash@{1}, "measured 17-41% slower") already solved
+ // this correctly by walking blocker-to-blocker via bit-scan on
+ // bbRay & bbOccupied; this reproduces the same unbounded
+ // chain-following behavior via repeated magic-lookup
+ // recomputation instead (each iteration excludes one more
+ // ring of blockers), which stays cheap because the loop body
+ // only runs again when an actual chained battery exists --
+ // the common case exits after zero or one iteration.
+ //
+ {
+ BITBOARD bbXrayAccum = 0;
+ BITBOARD bbExclude = 0;
+ BITBOARD bbFrontier = bbAttack;
+ for (;;)
{
- case RMOB_EMPTY:
- uCurrentMobility +=
- !((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) ||
- _IsSquareAttackedByMinor(pos, FLIP(uColor), cSquare));
- fStop = FALSE;
- break;
+ BITBOARD bbBlockers = bbFrontier &
+ (pos->bbPieces[uColor][ROOK] |
+ pos->bbPieces[uColor][QUEEN] |
+ pos->bbPieces[FLIP(uColor)][QUEEN] |
+ COOR_TO_BB(pos->cNonPawns[FLIP(uColor)][0]));
+ BITBOARD bbBeyond;
- case RMOB_ENEMY_LESS:
- uCurrentMobility +=
- !((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) ||
- _IsSquareAttackedByMinor(pos, FLIP(uColor), cSquare));
- fStop = TRUE;
- break;
-
- case RMOB_FRIEND_BLOCK:
- fStop = TRUE;
- break;
-
- case RMOB_FRIEND_ROOK:
- EVAL_TERM(uColor,
- ROOK,
- cSquare,
- pos->iScore[uColor],
- (ROOK_CONNECTED_HORIZ * fHoriz +
- ROOK_CONNECTED_VERT * FLIP(fHoriz)),
- "rook connected");
- uBit = ROOK_XRAY_BIT;
- fStop = FALSE;
- break;
-
- case RMOB_ENEMY_SAME:
- uCurrentMobility += 1;
- fStop = TRUE;
+ if (!bbBlockers)
+ {
break;
-
- case RMOB_FRIEND_QUEEN:
- uBit = ROOK_XRAY_BIT;
- fStop = FALSE;
+ }
+ bbExclude |= bbBlockers;
+ bbBeyond = _RookAttacksBB(c, pos->bbOccupied & ~bbExclude) &
+ ~bbAttack & ~bbXrayAccum;
+ if (!bbBeyond)
+ {
break;
+ }
+ bbXrayAccum |= bbBeyond;
+ bbFrontier = bbBeyond;
+ }
+ pos->bbRookXrayAttacks[uColor] |= bbXrayAccum;
+ }
- case RMOB_ENEMY_GREATER:
- uCurrentMobility += 1;
- uBit = ROOK_XRAY_BIT;
- fStop = FALSE;
- break;
+ bbMobility = (bbAttack & bbEnemyGE) |
+ (bbAttack & ~bbFriendOcc & ~bbEnemyGE &
+ ~bbUnsafeForRook);
+ uTotalMobility = CountBits(bbMobility);
- case RMOB_INVALID:
- default:
- UtilPanic(SHOULD_NOT_GET_HERE,
- NULL, NULL, NULL, NULL,
- __FILE__, __LINE__);
- fStop = TRUE;
- break;
- }
- ASSERT(uCurrentMobility <= 7);
- if (TRUE == fStop)
- {
- break;
- }
- cSquare += g_iRDeltas[u];
+ uMaxMobility = 0;
+ for (d = 0; d < 4; d++)
+ {
+ ULONG uThisRay = CountBits(bbMobility & g_RookRayToEdge[d][c]);
+ uMaxMobility = MAXU(uMaxMobility, uThisRay);
}
- uTotalMobility += uCurrentMobility;
- ASSERT(uTotalMobility <= 14);
- ASSERT((uMaxMobility & 0x80000000) == 0);
- ASSERT((uCurrentMobility & 0x80000000) == 0);
- uMaxMobility = MAXU(uCurrentMobility, uMaxMobility);
- ASSERT(uMaxMobility <= 7);
- u++;
}
- while(g_iRDeltas[u] != 0);
ASSERT(uTotalMobility <= 14);
+ ASSERT(uMaxMobility <= 7);
ASSERT(pos->uArmyScaler[FLIP(uColor)] <= 31);
// Tuning can (and has) pushed this out of its original hand-picked
@@ -3754,8 +3856,7 @@ Return value:
uTotalMobility +=
!((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) ||
_IsSquareAttackedByMinor(pos, FLIP(uColor), cSquare) ||
- (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].uWholeThing &
- ROOK_BIT));
+ _IsSquareAttackedByRook(pos, FLIP(uColor), cSquare));
fStop = FALSE;
break;
@@ -3763,8 +3864,7 @@ Return value:
uTotalMobility +=
!((pos->bbPawnAttacks[FLIP(uColor)] & COOR_TO_BB(cSquare)) ||
_IsSquareAttackedByMinor(pos, FLIP(uColor), cSquare) ||
- (pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)].uWholeThing &
- ROOK_BIT));
+ _IsSquareAttackedByRook(pos, FLIP(uColor), cSquare));
fStop = TRUE;
break;
@@ -4010,19 +4110,25 @@ Return value:
((pos->bbPawnAttacks[ufColor] & COOR_TO_BB(cSquare)) ?
PAWN_BIT : 0) |
(_IsSquareAttackedByMinor(pos, ufColor, cSquare) ?
- MINOR_BIT : 0);
+ MINOR_BIT : 0) |
+ (_IsSquareAttackedByRook(pos, ufColor, cSquare) ?
+ ROOK_BIT : 0);
{
COOR cRealSquare = cSquare;
cSquare |= 8;
bvXray = pos->rgSquare[cSquare].bvAttacks[ufColor].uXray |
(_IsSquareXrayedByMinor(pos, ufColor, cRealSquare) ?
- MINOR_BIT : 0);
+ MINOR_BIT : 0) |
+ (_IsSquareXrayedByRook(pos, ufColor, cRealSquare) ?
+ ROOK_BIT : 0);
pos->rgSquare[cSquare].bvAttacks[uColor].small.uKing = 1;
bvDefend = pos->rgSquare[cSquare].bvAttacks[uColor].uSmall |
((pos->bbPawnAttacks[uColor] & COOR_TO_BB(cRealSquare)) ?
PAWN_BIT : 0) |
(_IsSquareAttackedByMinor(pos, uColor, cRealSquare) ?
- MINOR_BIT : 0);
+ MINOR_BIT : 0) |
+ (_IsSquareAttackedByRook(pos, uColor, cRealSquare) ?
+ ROOK_BIT : 0);
}
//