diff options
| -rwxr-xr-x | src/eval.c | 1686 |
1 files changed, 439 insertions, 1247 deletions
@@ -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); } |
