summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-08-30 12:48:34 -0700
committerScott Gasch <[email protected]>2026-08-30 12:48:34 -0700
commit3eac7f469add78edb9dd7dced36bde5427346321 (patch)
tree7b32f67728ee7973aa046df18423c6f6efbbd7a0
parent0eb79a56c9174397050535bbfdc3f1e767ba9ffc (diff)
Replace bishop/knight/rook/queen mobility jump tables with inline switch dispatch.
The per-square mobility ray-walk called through a function pointer for every square visited (piece type varies square to square, so the CPU's indirect-branch predictor couldn't learn it), and nearly every handler reduced to a couple of constant increments and a stop/continue flag. Replaced each PMOBILITY_HELPER table with a small case-tag table and an inlined switch, dropping all now-dead handler functions and the PMOBILITY_HELPER typedef. Also hoisted the ray-invariant rank/file direction test (rook's "connected" bonus, queen's bishop/rook xray cases) out of the per-square switch to compute once per ray instead. Verified semantics-preserving: node counts, solve/fail sets, and PVs are byte-for-byte identical to head_reference across all three curated ECM suites (ringers/confident_quick/hard_quick) at sd 10. bench shows a consistent ~6-7% NPS improvement over two back-to-back runs. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_012Q8wbZABsyG7PZQUd9WBAw
-rwxr-xr-xsrc/eval.c1686
1 files changed, 439 insertions, 1247 deletions
diff --git a/src/eval.c b/src/eval.c
index fc22127..a9be77f 100755
--- a/src/eval.c
+++ b/src/eval.c
@@ -22,7 +22,79 @@ Revision History:
#include "chess.h"
typedef void (*PEVAL_HELPER)(POSITION *, COOR, PAWN_HASH_ENTRY *);
-typedef FLAG (FASTCALL *PMOBILITY_HELPER)(POSITION *, COOR, ULONG *, ULONG *);
+
+//
+// Bishop-mobility ray-walk outcome categories -- see BMobCaseTable in
+// _EvalBishop. Replaces a table of function pointers (one indirect
+// call/ret per square visited) with a table of these tags dispatched
+// via switch, inlined directly into the ray-walking loop.
+//
+typedef enum _BMOB_CASE
+{
+ BMOB_EMPTY = 0, // empty square
+ BMOB_INVALID, // should never occur (off-board sentinel)
+ BMOB_FRIEND_PAWN, // own-color pawn
+ BMOB_ENEMY_PAWN, // enemy pawn (worth less than a bishop)
+ BMOB_FRIEND_BLOCK, // own-color knight/rook/king: blocks, no xray
+ BMOB_ENEMY_SAME, // enemy bishop/knight: captures, blocks
+ BMOB_FRIEND_XRAY, // own-color bishop/queen: xray through, keep going
+ BMOB_ENEMY_GREATER, // enemy rook/queen/king: captures, xray bit, keep going
+} BMOB_CASE;
+
+//
+// Knight-mobility outcome categories -- see NMobCaseTable in _EvalKnight.
+// Knight mobility only ever looks at the single landing square (no ray to
+// walk/stop), so there's no xray/stop concept here, just "does landing on
+// this square count as mobility."
+//
+typedef enum _NMOB_CASE
+{
+ NMOB_INVALID = 0, // should never occur (off-board sentinel)
+ NMOB_MOBILE_SQUARE, // empty square or enemy pawn: counts unless unsafe for a minor
+ NMOB_ENEMY_OTHER, // any other enemy piece: always counts
+ NMOB_FRIEND, // any friendly piece: never counts
+} NMOB_CASE;
+
+//
+// Rook-mobility outcome categories -- see RMobCaseTable in _EvalRook.
+// RMOB_FRIEND_ROOK carries a real side effect (the "connected rooks"
+// bonus), so unlike bishop/knight this isn't purely mobility/xray-bit
+// bookkeeping -- kept as a distinct case rather than folded into
+// RMOB_FRIEND_QUEEN even though both keep scanning with the xray bit set.
+//
+typedef enum _RMOB_CASE
+{
+ RMOB_EMPTY = 0, // empty square
+ RMOB_INVALID, // should never occur (off-board sentinel)
+ RMOB_ENEMY_LESS, // enemy pawn/knight/bishop: captures, blocks
+ RMOB_FRIEND_BLOCK, // own-color knight/bishop/king: blocks, no xray
+ RMOB_FRIEND_ROOK, // own-color rook: connected-rooks bonus, xray, keep going
+ RMOB_ENEMY_SAME, // enemy rook: captures, blocks
+ RMOB_FRIEND_QUEEN, // own-color queen: xray through, keep going
+ RMOB_ENEMY_GREATER, // enemy queen/king: captures, xray bit, keep going
+} RMOB_CASE;
+
+//
+// Queen-mobility outcome categories -- see QMobCaseTable in _EvalQueen.
+// A queen's ray set is the union of a bishop's 4 diagonals and a rook's
+// 4 orthogonals, so QMOB_FRIEND_BISHOP/QMOB_FRIEND_ROOK only let the
+// queen xray through when the *ray it's currently walking* matches that
+// piece's own move pattern (diagonal for a bishop, orthogonal for a
+// rook) -- computed once per ray below (fOrthogonalRay), not per square,
+// since every square on a given ray shares the same rank/file
+// relationship to the queen's home square.
+//
+typedef enum _QMOB_CASE
+{
+ QMOB_EMPTY = 0, // empty square
+ QMOB_INVALID, // should never occur (off-board sentinel)
+ QMOB_ENEMY_LESS, // enemy piece worth less than a queen: captures, blocks
+ QMOB_FRIEND_BLOCK, // own-color knight/king: blocks, no xray
+ QMOB_FRIEND_BISHOP, // own-color bishop: xray only on a diagonal ray
+ QMOB_FRIEND_ROOK, // own-color rook: xray only on an orthogonal ray
+ QMOB_FRIEND_QUEEN, // own-color queen: xray through, keep going
+ QMOB_ENEMY_GE, // enemy queen/king: captures, blocks
+} QMOB_CASE;
//
// To simplify code / maintenance I use the same loop for both colors
@@ -2371,1093 +2443,6 @@ Return value:
// ======================================================================
//
-static FLAG FASTCALL
-_InvalidMobilityHelper(UNUSED POSITION *pos,
- UNUSED COOR c,
- UNUSED ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
- This code should never be called
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
- UtilPanic(SHOULD_NOT_GET_HERE,
- NULL, NULL, NULL, NULL,
- __FILE__, __LINE__);
- return(TRUE);
-}
-
-// ----------------------------------------------------------------------
-
-static FLAG FASTCALL
-_BMinorToEnemyLess(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
- Consider a black minor (knight | bishop) taking an enemy pawn
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL : always TRUE, stop scanning in this direction
-
-**/
-{
-#ifdef DEBUG
- PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
- PIECE p = pos->rgSquare[c].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(!IS_EMPTY(p));
- ASSERT(PIECE_VALUE(p) < VALUE_BISHOP);
- ASSERT(!IS_EMPTY(pMinor));
- ASSERT(IS_PAWN(p));
- ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
- ASSERT(OPPOSITE_COLORS(p, pMinor));
- ASSERT(GET_COLOR(pMinor) == BLACK);
-#endif
- *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[WHITE]));
- ASSERT(*puMobility <= 8);
- return(TRUE); // stop scanning this dir
-}
-
-static FLAG FASTCALL
-_WMinorToEnemyLess(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
- PIECE p = pos->rgSquare[c].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(!IS_EMPTY(p));
- ASSERT(IS_PAWN(p));
- ASSERT(PIECE_VALUE(p) < VALUE_BISHOP);
- ASSERT(!IS_EMPTY(pMinor));
- ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
- ASSERT(OPPOSITE_COLORS(p, pMinor));
- ASSERT(GET_COLOR(pMinor) == WHITE);
-#endif
- *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[BLACK]));
- ASSERT(*puMobility <= 8);
- return(TRUE); // stop scanning this dir
-}
-
-static FLAG FASTCALL
-_WRookToEnemyLess(POSITION *pos,
- COOR c,
- ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ROOK(pRook));
- ASSERT(!IS_EMPTY(p));
- ASSERT(OPPOSITE_COLORS(p, pRook));
- ASSERT(PIECE_VALUE(p) < VALUE_ROOK);
- ASSERT(WHITE == GET_COLOR(pRook));
-#endif
- *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[BLACK]));
- ASSERT(*puMobility <= 7);
- return(TRUE); // stop scanning this dir
-}
-
-static FLAG FASTCALL
-_BRookToEnemyLess(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_ROOK(pRook));
- ASSERT(OPPOSITE_COLORS(p, pRook));
- ASSERT(PIECE_VALUE(p) < VALUE_ROOK);
- ASSERT(BLACK == GET_COLOR(pRook));
-#endif
- *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[WHITE]));
- ASSERT(*puMobility <= 7);
- return(TRUE); // stop scanning this dir
-}
-
-
-static FLAG FASTCALL
-_BQueenToEnemyLess(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_QUEEN(pQueen));
- ASSERT(PIECE_VALUE(p) < VALUE_QUEEN);
- ASSERT(GET_COLOR(pQueen) == BLACK);
- ASSERT(OPPOSITE_COLORS(pQueen, p));
-#endif
- *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[WHITE]));
- ASSERT(*puMobility <= 27);
- return(TRUE); // stop scanning this dir
-}
-
-
-static FLAG FASTCALL
-_WQueenToEnemyLess(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_QUEEN(pQueen));
- ASSERT(PIECE_VALUE(p) < VALUE_QUEEN);
- ASSERT(GET_COLOR(pQueen) == WHITE);
- ASSERT(OPPOSITE_COLORS(pQueen, p));
-#endif
- *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[BLACK]));
- ASSERT(*puMobility <= 27);
- return(TRUE); // stop scanning this dir
-}
-
-// ----------------------------------------------------------------------
-
-static FLAG FASTCALL
-_EMinorToEnemySame(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
- PIECE p = pos->rgSquare[c].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(!IS_EMPTY(p));
- ASSERT(!IS_EMPTY(pMinor));
- ASSERT(OPPOSITE_COLORS(p, pMinor));
-
- if (IS_BISHOP(pMinor))
- {
- ASSERT(PIECE_VALUE(p) == VALUE_BISHOP);
- }
- else
- {
- ASSERT(IS_KNIGHT(pMinor));
- ASSERT(PIECE_VALUE(p) >= VALUE_KNIGHT);
- }
-#endif
- *puMobility += 1;
- ASSERT(*puMobility <= 8);
- return(TRUE); // stop scanning this dir
-}
-
-
-static FLAG FASTCALL
-_ERookToEnemySame(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_ROOK(pRook));
- ASSERT(!IS_EMPTY(p));
- ASSERT(IS_ROOK(p));
- ASSERT(OPPOSITE_COLORS(p, pRook));
-#endif
- *puMobility += 1;
- ASSERT(*puMobility <= 7);
- return(TRUE); // stop scanning this dir
-}
-
-
-static FLAG FASTCALL
-_EQueenToEnemyGreaterEqual(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_QUEEN(pQueen));
- ASSERT(!IS_EMPTY(p));
- ASSERT(PIECE_VALUE(p) >= VALUE_QUEEN);
- ASSERT(OPPOSITE_COLORS(pQueen, p));
-#endif
- *puMobility += 1;
- ASSERT(*puMobility <= 27);
- return(TRUE); // stop scanning this dir
-}
-
-// ----------------------------------------------------------------------
-
-static FLAG FASTCALL
-_EMinorToEnemyGreater(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
- PIECE p = pos->rgSquare[c].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(!IS_EMPTY(p));
- ASSERT(PIECE_VALUE(p) > VALUE_BISHOP);
- ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
- ASSERT(OPPOSITE_COLORS(p, pMinor));
-#endif
- *puMobility += 1;
- ASSERT(*puMobility <= 8);
- *puBit = MINOR_XRAY_BIT;
- return(FALSE); // keep scanning this dir
-}
-
-static FLAG FASTCALL
-_ERookToEnemyGreater(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_ROOK(pRook));
- ASSERT(!IS_EMPTY(p));
- ASSERT(OPPOSITE_COLORS(p, pRook));
- ASSERT(PIECE_VALUE(p) > VALUE_ROOK);
-#endif
- *puMobility += 1;
- ASSERT(*puMobility <= 7);
- *puBit = ROOK_XRAY_BIT;
- return(FALSE); // keep scanning this dir
-}
-
-// ----------------------------------------------------------------------
-
-static FLAG FASTCALL
-_AnythingToFriendNoXray(IN POSITION *pos,
- IN COOR c,
- UNUSED ULONG *puMobility,
- UNUSED ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- COOR cMover = pos->cPiece;
- PIECE pMover = pos->rgSquare[cMover].pPiece;
- PIECE pFriend = pos->rgSquare[c].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(cMover));
- ASSERT(!IS_EMPTY(pFriend));
- ASSERT(!IS_EMPTY(pMover));
- ASSERT(GET_COLOR(pMover) == GET_COLOR(pFriend));
- if (IS_BISHOP(pMover))
- {
- ASSERT(!IS_BISHOP(pFriend));
- ASSERT(!IS_QUEEN(pFriend));
- }
- else if (IS_ROOK(pMover))
- {
- ASSERT(!IS_QUEEN(pFriend));
- ASSERT(!IS_ROOK(pFriend));
- }
- else if (IS_QUEEN(pMover))
- {
- ASSERT(!IS_BISHOP(pFriend));
- ASSERT(!IS_ROOK(pFriend));
- ASSERT(!IS_QUEEN(pFriend));
- }
-#endif
- return(TRUE); // stop scanning this dir
-}
-
-// ----------------------------------------------------------------------
-
-static FLAG FASTCALL
-_EMinorToFriendXray(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
- PIECE p = pos->rgSquare[c].pPiece;
-
- ASSERT(!IS_EMPTY(p));
- ASSERT(!IS_EMPTY(pMinor));
- ASSERT(IS_BISHOP(pMinor));
- ASSERT(GET_COLOR(p) == GET_COLOR(pMinor));
-#endif
- *puBit = MINOR_XRAY_BIT;
- return(FALSE);
-}
-
-static FLAG FASTCALL
-_BRookToFriendRook(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
- COOR cRook = pos->cPiece;
- FLAG fHoriz = ((c & 0xF0) == (cRook & 0xF0));
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pRook = pos->rgSquare[cRook].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(cRook));
- ASSERT(IS_ROOK(pRook));
- ASSERT(!IS_EMPTY(p));
- ASSERT(IS_ROOK(p));
- ASSERT(GET_COLOR(p) == GET_COLOR(pRook));
- ASSERT(GET_COLOR(p) == BLACK);
- ASSERT((fHoriz && (RANK(c) == RANK(pos->cPiece))) ||
- (!fHoriz && (FILE(c) == FILE(pos->cPiece))));
-#endif
- EVAL_TERM(BLACK,
- ROOK,
- c,
- pos->iScore[BLACK],
- (ROOK_CONNECTED_HORIZ * fHoriz +
- ROOK_CONNECTED_VERT * FLIP(fHoriz)),
- "rook connected");
- *puBit = ROOK_XRAY_BIT;
- return(FALSE);
-}
-
-
-static FLAG FASTCALL
-_WRookToFriendRook(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
- COOR cRook = pos->cPiece;
- FLAG fHoriz = ((c & 0xF0) == (cRook & 0xF0));
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pRook = pos->rgSquare[cRook].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(cRook));
- ASSERT(IS_ROOK(pRook));
- ASSERT(!IS_EMPTY(p));
- ASSERT(IS_ROOK(p));
- ASSERT(GET_COLOR(p) == GET_COLOR(pRook));
- ASSERT(GET_COLOR(p) == WHITE);
- ASSERT((fHoriz && (RANK(c) == RANK(pos->cPiece))) ||
- (!fHoriz && (FILE(c) == FILE(pos->cPiece))));
-#endif
- EVAL_TERM(WHITE,
- ROOK,
- c,
- pos->iScore[WHITE],
- (ROOK_CONNECTED_HORIZ * fHoriz +
- ROOK_CONNECTED_VERT * FLIP(fHoriz)),
- "rook connected");
- *puBit = ROOK_XRAY_BIT;
- return(FALSE);
-}
-
-
-static FLAG FASTCALL
-_ERookToFriendQueen(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_ROOK(pRook));
- ASSERT(!IS_EMPTY(p));
- ASSERT(IS_QUEEN(p));
- ASSERT(GET_COLOR(p) == GET_COLOR(pRook));
-#endif
- *puBit = ROOK_XRAY_BIT;
- return(FALSE);
-}
-
-static FLAG FASTCALL
-_EQueenToFriendBishop(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
- COOR cQueen = pos->cPiece;
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pQueen = pos->rgSquare[cQueen].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(cQueen));
- ASSERT(IS_QUEEN(pQueen));
- ASSERT(IS_BISHOP(p));
- ASSERT(GET_COLOR(p) == GET_COLOR(pQueen));
-#endif
- *puBit = QUEEN_XRAY_BIT;
- return((((c & 0xF0) == (cQueen & 0xF0)) ||
- ((c & 0x0F) == (cQueen & 0x0F))));
-}
-
-
-static FLAG FASTCALL
-_EQueenToFriendRook(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
- COOR cQueen = pos->cPiece;
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pQueen = pos->rgSquare[cQueen].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(cQueen));
- ASSERT(IS_QUEEN(pQueen));
- ASSERT(IS_ROOK(p));
- ASSERT(GET_COLOR(p) == GET_COLOR(pQueen));
-#endif
- *puBit = QUEEN_XRAY_BIT;
- return(FLIP((((c & 0xF0) == (cQueen & 0xF0)) ||
- ((c & 0x0F) == (cQueen & 0x0F)))));
-}
-
-
-static FLAG FASTCALL
-_EQueenToFriendQueen(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- COOR cQueen = pos->cPiece;
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pQueen = pos->rgSquare[cQueen].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(cQueen));
- ASSERT(IS_QUEEN(pQueen));
- ASSERT(IS_QUEEN(p));
- ASSERT(GET_COLOR(p) == GET_COLOR(pQueen));
-#endif
- *puBit = QUEEN_XRAY_BIT;
- return(FALSE);
-}
-
-
-// ----------------------------------------------------------------------
-
-static FLAG FASTCALL
-_BMinorToEmpty(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
- PIECE p = pos->rgSquare[c].pPiece;
-
- ASSERT(IS_EMPTY(p));
- ASSERT(!IS_EMPTY(pMinor));
- ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
- ASSERT(GET_COLOR(pMinor) == BLACK);
-#endif
- *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[WHITE]));
- ASSERT(*puMobility <= 8);
- return(FALSE);
-}
-
-static FLAG FASTCALL
-_WMinorToEmpty(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE pMinor = pos->rgSquare[pos->cPiece].pPiece;
- PIECE p = pos->rgSquare[c].pPiece;
-
- ASSERT(IS_EMPTY(p));
- ASSERT(!IS_EMPTY(pMinor));
- ASSERT(IS_BISHOP(pMinor) || IS_KNIGHT(pMinor));
- ASSERT(GET_COLOR(pMinor) == WHITE);
-#endif
- *puMobility += (!UNSAFE_FOR_MINOR(pos->rgSquare[c|8].bvAttacks[BLACK]));
- ASSERT(*puMobility <= 8);
- return(FALSE);
-}
-
-static FLAG FASTCALL
-_WRookToEmpty(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_ROOK(pRook));
- ASSERT(IS_EMPTY(p));
- ASSERT(GET_COLOR(pRook) == WHITE);
-#endif
- *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[BLACK]));
- ASSERT(*puMobility <= 7);
- return(FALSE);
-}
-
-static FLAG FASTCALL
-_BRookToEmpty(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pRook = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_ROOK(pRook));
- ASSERT(IS_EMPTY(p));
- ASSERT(GET_COLOR(pRook) == BLACK);
-#endif
- *puMobility += (!UNSAFE_FOR_ROOK(pos->rgSquare[c|8].bvAttacks[WHITE]));
- ASSERT(*puMobility <= 7);
- return(FALSE);
-}
-
-static FLAG FASTCALL
-_BQueenToEmpty(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_QUEEN(pQueen));
- ASSERT(IS_EMPTY(p));
- ASSERT(GET_COLOR(pQueen) == BLACK);
-#endif
- *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[WHITE]));
- ASSERT(*puMobility <= 27);
- return(FALSE);
-}
-
-static FLAG FASTCALL
-_WQueenToEmpty(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE p = pos->rgSquare[c].pPiece;
- PIECE pQueen = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_QUEEN(pQueen));
- ASSERT(IS_EMPTY(p));
- ASSERT(GET_COLOR(pQueen) == WHITE);
-#endif
- *puMobility += (!UNSAFE_FOR_QUEEN(pos->rgSquare[c|8].bvAttacks[BLACK]));
- ASSERT(*puMobility <= 27);
- return(FALSE);
-}
-
-
-
-static FLAG FASTCALL
-_EBishopToFriendPawn(IN POSITION *pos,
- IN COOR c,
- IN OUT ULONG *puMobility,
- IN OUT ULONG *puBit)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR c,
- ULONG *puMobility,
- ULONG *puBit
-
-Return value:
-
- static FLAG FASTCALL
-
-**/
-{
-#ifdef DEBUG
- PIECE pPawn = pos->rgSquare[c].pPiece;
- PIECE pBishop = pos->rgSquare[pos->cPiece].pPiece;
-
- ASSERT(IS_ON_BOARD(c));
- ASSERT(IS_ON_BOARD(pos->cPiece));
- ASSERT(IS_BISHOP(pBishop));
- ASSERT(IS_PAWN(pPawn));
- ASSERT(GET_COLOR(pBishop) == GET_COLOR(pPawn));
-#endif
- *puMobility += ((pos->bb & COOR_TO_BB(c)) != 0);
- return(TRUE);
-}
-
-
-
-
-//
-// ======================================================================
-//
-
static void
_RecordTrappedCandidate(IN OUT POSITION *pos,
IN ULONG uColor,
@@ -3514,39 +2499,48 @@ Return value:
{
static const BITBOARD bbColorSq[2] = { 0x55aa55aa55aa55aaULL,
0xaa55aa55aa55aa55ULL };
- static const PMOBILITY_HELPER BMobJumpTable[2][14] =
+ //
+ // Mobility outcome for each (mover-color, piece-landed-on) pair,
+ // replacing a table of function pointers with a table of case tags
+ // dispatched via switch -- avoids an indirect call/ret (and the
+ // associated indirect-branch-predictor miss, since the target piece
+ // varies square to square) per square visited on every bishop ray,
+ // the hottest inner loop in eval. See the switch in the ray-walking
+ // loop below for what each tag actually does.
+ //
+ static const UCHAR BMobCaseTable[2][14] =
{
{// (black)
- _BMinorToEmpty, // EMPTY_SQUARE (0)
- _InvalidMobilityHelper, // INVALID_PIECE (1)
- _EBishopToFriendPawn, // BLACK_PAWN (2)
- _BMinorToEnemyLess, // WHITE_PAWN (3)
- _AnythingToFriendNoXray, // BLACK_KNIGHT (4)
- _EMinorToEnemySame, // WHITE_KNIGHT (5)
- _EMinorToFriendXray, // BLACK_BISHOP (6)
- _EMinorToEnemySame, // WHITE_BISHOP (7)
- _AnythingToFriendNoXray, // BLACK_ROOK (8)
- _EMinorToEnemyGreater, // WHITE_ROOK (9)
- _EMinorToFriendXray, // BLACK_QUEEN (10)
- _EMinorToEnemyGreater, // WHITE_QUEEN (11)
- _AnythingToFriendNoXray, // BLACK_KING (12)
- _EMinorToEnemyGreater, // WHITE_KING (13)
+ BMOB_EMPTY, // EMPTY_SQUARE (0)
+ BMOB_INVALID, // INVALID_PIECE (1)
+ BMOB_FRIEND_PAWN, // BLACK_PAWN (2)
+ BMOB_ENEMY_PAWN, // WHITE_PAWN (3)
+ BMOB_FRIEND_BLOCK, // BLACK_KNIGHT (4)
+ BMOB_ENEMY_SAME, // WHITE_KNIGHT (5)
+ BMOB_FRIEND_XRAY, // BLACK_BISHOP (6)
+ BMOB_ENEMY_SAME, // WHITE_BISHOP (7)
+ BMOB_FRIEND_BLOCK, // BLACK_ROOK (8)
+ BMOB_ENEMY_GREATER, // WHITE_ROOK (9)
+ BMOB_FRIEND_XRAY, // BLACK_QUEEN (10)
+ BMOB_ENEMY_GREATER, // WHITE_QUEEN (11)
+ BMOB_FRIEND_BLOCK, // BLACK_KING (12)
+ BMOB_ENEMY_GREATER, // WHITE_KING (13)
},
{// (white)
- _WMinorToEmpty, // EMPTY_SQUARE (0)
- _InvalidMobilityHelper, // INVALID_PIECE (1)
- _WMinorToEnemyLess, // BLACK_PAWN (2)
- _EBishopToFriendPawn, // WHITE_PAWN (3)
- _EMinorToEnemySame, // BLACK_KNIGHT (4)
- _AnythingToFriendNoXray, // WHITE_KNIGHT (5)
- _EMinorToEnemySame, // BLACK_BISHOP (6)
- _EMinorToFriendXray, // WHITE_BISHOP (7)
- _EMinorToEnemyGreater, // BLACK_ROOK (8)
- _AnythingToFriendNoXray, // WHITE_ROOK (9)
- _EMinorToEnemyGreater, // BLACK_QUEEN (10)
- _EMinorToFriendXray, // WHITE_QUEEN (11)
- _EMinorToEnemyGreater, // BLACK_KING (12)
- _AnythingToFriendNoXray, // WHITE_KING (13)
+ BMOB_EMPTY, // EMPTY_SQUARE (0)
+ BMOB_INVALID, // INVALID_PIECE (1)
+ BMOB_ENEMY_PAWN, // BLACK_PAWN (2)
+ BMOB_FRIEND_PAWN, // WHITE_PAWN (3)
+ BMOB_ENEMY_SAME, // BLACK_KNIGHT (4)
+ BMOB_FRIEND_BLOCK, // WHITE_KNIGHT (5)
+ BMOB_ENEMY_SAME, // BLACK_BISHOP (6)
+ BMOB_FRIEND_XRAY, // WHITE_BISHOP (7)
+ BMOB_ENEMY_GREATER, // BLACK_ROOK (8)
+ BMOB_FRIEND_BLOCK, // WHITE_ROOK (9)
+ BMOB_ENEMY_GREATER, // BLACK_QUEEN (10)
+ BMOB_FRIEND_XRAY, // WHITE_QUEEN (11)
+ BMOB_ENEMY_GREATER, // BLACK_KING (12)
+ BMOB_FRIEND_BLOCK, // WHITE_KING (13)
}
};
static const COOR cBishopAtHome[2][2] =
@@ -3566,7 +2560,6 @@ Return value:
ULONG uCurrentMobility;
ULONG uBit;
PIECE p;
- PMOBILITY_HELPER pFun;
ASSERT(IS_ON_BOARD(c));
p = pos->rgSquare[c].pPiece;
@@ -3672,6 +2665,8 @@ Return value:
while(IS_ON_BOARD(cSquare))
{
+ FLAG fStop;
+
//
// Always toggle attack table bits.
//
@@ -3679,15 +2674,63 @@ Return value:
pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
//
- // What did we hit?
+ // What did we hit? Dispatched via switch instead of an
+ // indirect call through a function pointer -- the target
+ // piece varies square to square, so the old jump table
+ // defeated the CPU's indirect-branch predictor on every
+ // step of every ray. See BMOB_CASE above for what each tag
+ // means.
//
p = pos->rgSquare[cSquare].pPiece;
- pFun = BMobJumpTable[uColor][p];
- ASSERT(pFun);
- if (TRUE == (*pFun)(pos,
- cSquare,
- &uCurrentMobility,
- &uBit))
+ switch (BMobCaseTable[uColor][p])
+ {
+ case BMOB_EMPTY:
+ uCurrentMobility +=
+ !UNSAFE_FOR_MINOR(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]);
+ fStop = FALSE;
+ break;
+
+ case BMOB_ENEMY_PAWN:
+ uCurrentMobility +=
+ !UNSAFE_FOR_MINOR(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]);
+ fStop = TRUE;
+ break;
+
+ case BMOB_FRIEND_PAWN:
+ uCurrentMobility += ((pos->bb & COOR_TO_BB(cSquare)) != 0);
+ fStop = TRUE;
+ break;
+
+ case BMOB_FRIEND_BLOCK:
+ fStop = TRUE;
+ break;
+
+ case BMOB_ENEMY_SAME:
+ uCurrentMobility += 1;
+ fStop = TRUE;
+ break;
+
+ case BMOB_FRIEND_XRAY:
+ uBit = MINOR_XRAY_BIT;
+ fStop = FALSE;
+ break;
+
+ case BMOB_ENEMY_GREATER:
+ uCurrentMobility += 1;
+ uBit = MINOR_XRAY_BIT;
+ fStop = FALSE;
+ break;
+
+ case BMOB_INVALID:
+ default:
+ UtilPanic(SHOULD_NOT_GET_HERE,
+ NULL, NULL, NULL, NULL,
+ __FILE__, __LINE__);
+ fStop = TRUE;
+ break;
+ }
+ ASSERT(uCurrentMobility <= 8);
+ if (TRUE == fStop)
{
break;
}
@@ -3716,38 +2759,34 @@ Return value:
"consecutive bishop mobility");
//
- // Look for bishops with no mobility who are under attack. These
- // pieces are trapped!
+ // Look for bishops with no mobility, they are trapped and, later,
+ // we'll see if they are also under attack too.
//
if (uTotalMobility == 0)
{
_RecordTrappedCandidate(pos, uColor, c);
}
+
+#if 0
+ // This is never used right now.
uTotalMobility /= 2;
ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
ASSERT((uTotalMobility & 0x80000000) == 0);
pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
uTotalMobility);
+#endif
//
// Bonus for a bishop that's securely placed -- safe from ever
// being challenged by an enemy pawn, and (checked below) defended
- // by a friendly one -- near the enemy king. This is really a
- // bishop-specific king-tropism/outpost bonus; despite the
- // historical "active bad bishop" name, it does NOT check whether
- // the bishop is actually "bad" (see the good/bad pawn-count terms
- // above) before applying. Candidate for folding into a unified
- // per-piece-type tropism system alongside
- // KNIGHT_KING_TROPISM_BONUS/QUEEN_KING_TROPISM (shelved for now,
- // pending a look at what every piece type currently does).
+ // by a friendly one -- near the enemy king. This is a
+ // bishop-specific king-tropism/outpost bonus.
//
bb = pHash->bbPawnLocations[FLIP(uColor)] &
(~pHash->bbStationaryPawns[FLIP(uColor)]);
if (TRUE == _IsSquareSafeFromEnemyPawn(pos, c, bb))
{
- //
- // Give a bonus based on distance from enemy king
- //
+ // Defended (and defending) a friendly pawn.
if (pos->rgSquare[c|8].bvAttacks[uColor].small.uPawn)
{
#ifdef DEBUG
@@ -3790,39 +2829,39 @@ Return value:
**/
{
static const int iPawnStart[2] = { -17, +15 };
- static const PMOBILITY_HELPER NMobJumpTable[2][14] =
+ static const UCHAR NMobCaseTable[2][14] =
{
{// (black)
- _BMinorToEmpty, // EMPTY_SQUARE (0)
- _InvalidMobilityHelper, // INVALID_PIECE (1)
- _AnythingToFriendNoXray, // BLACK_PAWN (2)
- _BMinorToEnemyLess, // WHITE_PAWN (3)
- _AnythingToFriendNoXray, // BLACK_KNIGHT (4)
- _EMinorToEnemySame, // WHITE_KNIGHT (5)
- _AnythingToFriendNoXray, // BLACK_BISHOP (6)
- _EMinorToEnemySame, // WHITE_BISHOP (7)
- _AnythingToFriendNoXray, // BLACK_ROOK (8)
- _EMinorToEnemySame, // WHITE_ROOK (9)
- _AnythingToFriendNoXray, // BLACK_QUEEN (10)
- _EMinorToEnemySame, // WHITE_QUEEN (11)
- _AnythingToFriendNoXray, // BLACK_KING (12)
- _EMinorToEnemySame, // WHITE_KING (13)
+ NMOB_MOBILE_SQUARE, // EMPTY_SQUARE (0)
+ NMOB_INVALID, // INVALID_PIECE (1)
+ NMOB_FRIEND, // BLACK_PAWN (2)
+ NMOB_MOBILE_SQUARE, // WHITE_PAWN (3)
+ NMOB_FRIEND, // BLACK_KNIGHT (4)
+ NMOB_ENEMY_OTHER, // WHITE_KNIGHT (5)
+ NMOB_FRIEND, // BLACK_BISHOP (6)
+ NMOB_ENEMY_OTHER, // WHITE_BISHOP (7)
+ NMOB_FRIEND, // BLACK_ROOK (8)
+ NMOB_ENEMY_OTHER, // WHITE_ROOK (9)
+ NMOB_FRIEND, // BLACK_QUEEN (10)
+ NMOB_ENEMY_OTHER, // WHITE_QUEEN (11)
+ NMOB_FRIEND, // BLACK_KING (12)
+ NMOB_ENEMY_OTHER, // WHITE_KING (13)
},
{// (white)
- _WMinorToEmpty, // EMPTY_SQUARE (0)
- _InvalidMobilityHelper, // INVALID_PIECE (1)
- _WMinorToEnemyLess, // BLACK_PAWN (2)
- _AnythingToFriendNoXray, // WHITE_PAWN (3)
- _EMinorToEnemySame, // BLACK_KNIGHT (4)
- _AnythingToFriendNoXray, // WHITE_KNIGHT (5)
- _EMinorToEnemySame, // BLACK_BISHOP (6)
- _AnythingToFriendNoXray, // WHITE_BISHOP (7)
- _EMinorToEnemySame, // BLACK_ROOK (8)
- _AnythingToFriendNoXray, // WHITE_ROOK (9)
- _EMinorToEnemySame, // BLACK_QUEEN (10)
- _AnythingToFriendNoXray, // WHITE_QUEEN (11)
- _EMinorToEnemySame, // BLACK_KING (12)
- _AnythingToFriendNoXray, // WHITE_KING (13)
+ NMOB_MOBILE_SQUARE, // EMPTY_SQUARE (0)
+ NMOB_INVALID, // INVALID_PIECE (1)
+ NMOB_MOBILE_SQUARE, // BLACK_PAWN (2)
+ NMOB_FRIEND, // WHITE_PAWN (3)
+ NMOB_ENEMY_OTHER, // BLACK_KNIGHT (4)
+ NMOB_FRIEND, // WHITE_KNIGHT (5)
+ NMOB_ENEMY_OTHER, // BLACK_BISHOP (6)
+ NMOB_FRIEND, // WHITE_BISHOP (7)
+ NMOB_ENEMY_OTHER, // BLACK_ROOK (8)
+ NMOB_FRIEND, // WHITE_ROOK (9)
+ NMOB_ENEMY_OTHER, // BLACK_QUEEN (10)
+ NMOB_FRIEND, // WHITE_QUEEN (11)
+ NMOB_ENEMY_OTHER, // BLACK_KING (12)
+ NMOB_FRIEND, // WHITE_KING (13)
}
};
static const COOR cKnightAtHome[2][2] =
@@ -3839,7 +2878,6 @@ Return value:
ULONG uMobilitySquares;
SCORE i;
ULONG uDist;
- PMOBILITY_HELPER pFun;
p = pos->rgSquare[c].pPiece;
ASSERT(p && IS_KNIGHT(p));
@@ -4013,16 +3051,31 @@ Return value:
pos->rgSquare[cSquare|8].bvAttacks[uColor].small.uMinor = 1;
//
- // See what we hit
+ // See what 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;
- pFun = NMobJumpTable[uColor][p];
- if (pFun != _AnythingToFriendNoXray)
+ switch (NMobCaseTable[uColor][p])
{
- (void)(*pFun)(pos,
- cSquare,
- &uMobilitySquares,
- NULL);
+ case NMOB_MOBILE_SQUARE:
+ uMobilitySquares +=
+ !UNSAFE_FOR_MINOR(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]);
+ break;
+
+ case NMOB_ENEMY_OTHER:
+ uMobilitySquares += 1;
+ break;
+
+ case NMOB_FRIEND:
+ break;
+
+ case NMOB_INVALID:
+ default:
+ UtilPanic(SHOULD_NOT_GET_HERE,
+ NULL, NULL, NULL, NULL,
+ __FILE__, __LINE__);
+ break;
}
//
@@ -4044,10 +3097,14 @@ Return value:
{
_RecordTrappedCandidate(pos, uColor, c);
}
+
+#if 0
+ // This is never used right now.
ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
ASSERT((uMobilitySquares & 0x80000000) == 0);
pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
uMobilitySquares);
+#endif
}
static void
@@ -4070,39 +3127,39 @@ Return value:
**/
{
- static const PMOBILITY_HELPER RMobJumpTable[2][14] =
+ static const UCHAR RMobCaseTable[2][14] =
{
{// (black)
- _BRookToEmpty, // EMPTY_SQUARE (0)
- _InvalidMobilityHelper, // INVALID_PIECE (1)
- _AnythingToFriendNoXray, // BLACK_PAWN (2)
- _BRookToEnemyLess, // WHITE_PAWN (3)
- _AnythingToFriendNoXray, // BLACK_KNIGHT (4)
- _BRookToEnemyLess, // WHITE_KNIGHT (5)
- _AnythingToFriendNoXray, // BLACK_BISHOP (6)
- _BRookToEnemyLess, // WHITE_BISHOP (7)
- _BRookToFriendRook, // BLACK_ROOK (8)
- _ERookToEnemySame, // WHITE_ROOK (9)
- _ERookToFriendQueen, // BLACK_QUEEN (10)
- _ERookToEnemyGreater, // WHITE_QUEEN (11)
- _AnythingToFriendNoXray, // BLACK_KING (12)
- _ERookToEnemyGreater, // WHITE_KING (13)
+ 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)
- _WRookToEmpty, // EMPTY_SQUARE (0)
- _InvalidMobilityHelper, // INVALID_PIECE (1)
- _WRookToEnemyLess, // BLACK_PAWN (2)
- _AnythingToFriendNoXray, // WHITE_PAWN (3)
- _WRookToEnemyLess, // BLACK_KNIGHT (4)
- _AnythingToFriendNoXray, // WHITE_KNIGHT (5)
- _WRookToEnemyLess, // BLACK_BISHOP (6)
- _AnythingToFriendNoXray, // WHITE_BISHOP (7)
- _ERookToEnemySame, // BLACK_ROOK (8)
- _WRookToFriendRook, // WHITE_ROOK (9)
- _ERookToEnemyGreater, // BLACK_QUEEN (10)
- _ERookToFriendQueen, // WHITE_QUEEN (11)
- _ERookToEnemyGreater, // BLACK_KING (12)
- _AnythingToFriendNoXray, // WHITE_KING (13)
+ 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)
},
};
@@ -4116,7 +3173,6 @@ Return value:
COOR cSquare;
BITBOARD bb;
ULONG uBit;
- PMOBILITY_HELPER pFun;
SCORE i;
ASSERT(IS_ON_BOARD(c));
@@ -4283,12 +3339,20 @@ Return value:
ASSERT(g_iRDeltas[u] != 0);
do
{
+ // 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;
+
uCurrentMobility = 0;
uBit = ROOK_BIT;
cSquare = c + g_iRDeltas[u];
+ fHoriz = ((cSquare & 0xF0) == (c & 0xF0));
while(IS_ON_BOARD(cSquare))
{
+ FLAG fStop;
+
//
// Twiddle our attack table bits.
//
@@ -4296,14 +3360,67 @@ Return value:
ASSERT((cSquare | 8) == (cSquare + 8));
//
- // What did we hit?
+ // 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;
- pFun = RMobJumpTable[uColor][p];
- if (TRUE == (*pFun)(pos,
- cSquare,
- &uCurrentMobility,
- &uBit))
+ switch (RMobCaseTable[uColor][p])
+ {
+ case RMOB_EMPTY:
+ uCurrentMobility +=
+ !UNSAFE_FOR_ROOK(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]);
+ fStop = FALSE;
+ break;
+
+ case RMOB_ENEMY_LESS:
+ uCurrentMobility +=
+ !UNSAFE_FOR_ROOK(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]);
+ 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;
+ break;
+
+ case RMOB_FRIEND_QUEEN:
+ uBit = ROOK_XRAY_BIT;
+ fStop = FALSE;
+ break;
+
+ case RMOB_ENEMY_GREATER:
+ uCurrentMobility += 1;
+ uBit = ROOK_XRAY_BIT;
+ fStop = FALSE;
+ break;
+
+ 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;
}
@@ -4340,10 +3457,13 @@ Return value:
ROOK_MAX_MOBILITY_IN_A_ROW_BONUS[uMaxMobility],
"consecutive rook mobility");
+#if 0
+ // This is never used right now.
ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
ASSERT((uTotalMobility & 0x80000000) == 0);
pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
uTotalMobility);
+#endif
if (uTotalMobility < 3)
{
//
@@ -4427,39 +3547,39 @@ Return value:
**/
{
- static const PMOBILITY_HELPER QMobJumpTable[2][14] =
+ static const UCHAR QMobCaseTable[2][14] =
{
{
- _BQueenToEmpty, // EMPTY_SQUARE (0)
- _InvalidMobilityHelper, // INVALID_PIECE (1)
- _AnythingToFriendNoXray, // BLACK_PAWN (2)
- _BQueenToEnemyLess, // WHITE_PAWN (3)
- _AnythingToFriendNoXray, // BLACK_KNIGHT (4)
- _BQueenToEnemyLess, // WHITE_KNIGHT (5)
- _EQueenToFriendBishop, // BLACK_BISHOP (6)
- _BQueenToEnemyLess, // WHITE_BISHOP (7)
- _EQueenToFriendRook, // BLACK_ROOK (8)
- _BQueenToEnemyLess, // WHITE_ROOK (9)
- _EQueenToFriendQueen, // BLACK_QUEEN (10)
- _EQueenToEnemyGreaterEqual, // WHITE_QUEEN (11)
- _AnythingToFriendNoXray, // BLACK_KING (12)
- _EQueenToEnemyGreaterEqual, // WHITE_KING (13)
+ QMOB_EMPTY, // EMPTY_SQUARE (0)
+ QMOB_INVALID, // INVALID_PIECE (1)
+ QMOB_FRIEND_BLOCK, // BLACK_PAWN (2)
+ QMOB_ENEMY_LESS, // WHITE_PAWN (3)
+ QMOB_FRIEND_BLOCK, // BLACK_KNIGHT (4)
+ QMOB_ENEMY_LESS, // WHITE_KNIGHT (5)
+ QMOB_FRIEND_BISHOP, // BLACK_BISHOP (6)
+ QMOB_ENEMY_LESS, // WHITE_BISHOP (7)
+ QMOB_FRIEND_ROOK, // BLACK_ROOK (8)
+ QMOB_ENEMY_LESS, // WHITE_ROOK (9)
+ QMOB_FRIEND_QUEEN, // BLACK_QUEEN (10)
+ QMOB_ENEMY_GE, // WHITE_QUEEN (11)
+ QMOB_FRIEND_BLOCK, // BLACK_KING (12)
+ QMOB_ENEMY_GE, // WHITE_KING (13)
},
{
- _WQueenToEmpty, // EMPTY_SQUARE (0)
- _InvalidMobilityHelper, // INVALID_PIECE (1)
- _WQueenToEnemyLess, // BLACK_PAWN (2)
- _AnythingToFriendNoXray, // WHITE_PAWN (3)
- _WQueenToEnemyLess, // BLACK_KNIGHT (4)
- _AnythingToFriendNoXray, // WHITE_KNIGHT (5)
- _WQueenToEnemyLess, // BLACK_BISHOP (6)
- _EQueenToFriendBishop, // WHITE_BISHOP (7)
- _WQueenToEnemyLess, // BLACK_ROOK (8)
- _EQueenToFriendRook, // WHITE_ROOK (9)
- _EQueenToEnemyGreaterEqual, // BLACK_QUEEN (10)
- _EQueenToFriendQueen, // WHITE_QUEEN (11)
- _EQueenToEnemyGreaterEqual, // BLACK_KING (12)
- _AnythingToFriendNoXray, // WHITE_KING (13)
+ QMOB_EMPTY, // EMPTY_SQUARE (0)
+ QMOB_INVALID, // INVALID_PIECE (1)
+ QMOB_ENEMY_LESS, // BLACK_PAWN (2)
+ QMOB_FRIEND_BLOCK, // WHITE_PAWN (3)
+ QMOB_ENEMY_LESS, // BLACK_KNIGHT (4)
+ QMOB_FRIEND_BLOCK, // WHITE_KNIGHT (5)
+ QMOB_ENEMY_LESS, // BLACK_BISHOP (6)
+ QMOB_FRIEND_BISHOP, // WHITE_BISHOP (7)
+ QMOB_ENEMY_LESS, // BLACK_ROOK (8)
+ QMOB_FRIEND_ROOK, // WHITE_ROOK (9)
+ QMOB_ENEMY_GE, // BLACK_QUEEN (10)
+ QMOB_FRIEND_QUEEN, // WHITE_QUEEN (11)
+ QMOB_ENEMY_GE, // BLACK_KING (12)
+ QMOB_FRIEND_BLOCK, // WHITE_KING (13)
},
};
@@ -4469,7 +3589,6 @@ Return value:
ULONG uTotalMobility;
ULONG u;
ULONG uBit;
- PMOBILITY_HELPER pFun;
COOR cKing;
ASSERT(IS_ON_BOARD(c));
@@ -4522,24 +3641,83 @@ Return value:
ASSERT(g_iQKDeltas[u] != 0);
do
{
+ // Ray-invariant: every square on this ray shares the same
+ // rank/file relationship to c as the very first step does, so
+ // this only needs computing once per direction, not per square
+ // (or even per friend-slider hit).
+ FLAG fOrthogonalRay;
+
uBit = QUEEN_BIT;
cSquare = c + g_iQKDeltas[u];
+ fOrthogonalRay = (((cSquare & 0xF0) == (c & 0xF0)) ||
+ ((cSquare & 0x0F) == (c & 0x0F)));
while(IS_ON_BOARD(cSquare))
{
+ FLAG fStop;
+
//
// Toggle attack table bits.
//
pos->rgSquare[cSquare|8].bvAttacks[uColor].uWholeThing |= uBit;
//
- // What did we hit?
+ // 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;
- pFun = QMobJumpTable[uColor][p];
- if (TRUE == (*pFun)(pos,
- cSquare,
- &uTotalMobility,
- &uBit))
+ switch (QMobCaseTable[uColor][p])
+ {
+ case QMOB_EMPTY:
+ uTotalMobility +=
+ !UNSAFE_FOR_QUEEN(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]);
+ fStop = FALSE;
+ break;
+
+ case QMOB_ENEMY_LESS:
+ uTotalMobility +=
+ !UNSAFE_FOR_QUEEN(pos->rgSquare[cSquare|8].bvAttacks[FLIP(uColor)]);
+ fStop = TRUE;
+ break;
+
+ case QMOB_FRIEND_BLOCK:
+ fStop = TRUE;
+ break;
+
+ case QMOB_FRIEND_BISHOP:
+ // Bishop only xrays a diagonal ray; blocks on an
+ // orthogonal one.
+ uBit = QUEEN_XRAY_BIT;
+ fStop = fOrthogonalRay;
+ break;
+
+ case QMOB_FRIEND_ROOK:
+ // Rook only xrays an orthogonal ray; blocks on a
+ // diagonal one.
+ uBit = QUEEN_XRAY_BIT;
+ fStop = !fOrthogonalRay;
+ break;
+
+ case QMOB_FRIEND_QUEEN:
+ uBit = QUEEN_XRAY_BIT;
+ fStop = FALSE;
+ break;
+
+ case QMOB_ENEMY_GE:
+ uTotalMobility += 1;
+ fStop = TRUE;
+ break;
+
+ case QMOB_INVALID:
+ default:
+ UtilPanic(SHOULD_NOT_GET_HERE,
+ NULL, NULL, NULL, NULL,
+ __FILE__, __LINE__);
+ fStop = TRUE;
+ break;
+ }
+ ASSERT(uTotalMobility <= 27);
+ if (TRUE == fStop)
{
break;
}
@@ -4565,10 +3743,13 @@ Return value:
{
_RecordTrappedCandidate(pos, uColor, c);
}
+#if 0
+ // This is never used right now
ASSERT((pos->uMinMobility[uColor] & 0x80000000) == 0);
ASSERT((uTotalMobility & 0x80000000) == 0);
pos->uMinMobility[uColor] = MINU(pos->uMinMobility[uColor],
uTotalMobility);
+#endif
//
// Removed 2026-08-30 ("pointing near enemy K" /
@@ -5626,7 +4807,10 @@ Return value:
pos->iMaterialBalance[BLACK]);
// ASSERT(!InCheck(pos, pos->uToMove));
+#if 0
+ // This is never used right now.
pos->uMinMobility[BLACK] = pos->uMinMobility[WHITE] = 100;
+#endif
pos->uNumTrapped[BLACK] = pos->uNumTrapped[WHITE] = 0;
pos->iScore[BLACK] =
@@ -6016,6 +5200,9 @@ Return value:
#endif
}
+#if 0
+ //
+ // Never used right now.
//
// Make one more pass over the piece list for the side on move now
// that the full attack table is computed to detect
@@ -6024,6 +5211,7 @@ Return value:
//
ctx->sPlyInfo[ctx->uPly].uMinMobility[BLACK] = pos->uMinMobility[BLACK];
ctx->sPlyInfo[ctx->uPly].uMinMobility[WHITE] = pos->uMinMobility[WHITE];
+#endif
//
// _EvalLookForDanger/_EvalTrappedPieces only ever *add* a hint
@@ -6161,7 +5349,11 @@ Return value:
(iScoreForSideToMove < +NMATE));
ASSERT(abs(ctx->sPlyInfo[ctx->uPly].iKingScore[BLACK]) < 700);
ASSERT(abs(ctx->sPlyInfo[ctx->uPly].iKingScore[WHITE]) < 700);
+
+#if 0
+ // Never used.
ASSERT(ctx->sPlyInfo[ctx->uPly].uMinMobility[BLACK] <= 100);
ASSERT(ctx->sPlyInfo[ctx->uPly].uMinMobility[WHITE] <= 100);
+#endif
return(iScoreForSideToMove);
}