summaryrefslogtreecommitdiff
path: root/src/generate.c
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-10-25 10:39:58 -0700
committerScott Gasch <[email protected]>2026-10-25 10:39:58 -0700
commitf97b2710981e936cfb500ad0cdf1ceab233efad8 (patch)
tree0004275d9dae8f7df4b5f86f3b750d80bc3f4a52 /src/generate.c
parent3927a4cac6ec254a8e34a5e864300f75c3efc9f3 (diff)
Make bitboard move generation unconditional; delete the mailbox fallback
All GENERATE_*_BITBOARD/EXPOSESCHECK_BITBOARD/ISATTACKED_BITBOARD/ UNBLOCKED_BITBOARD flags were already default-on (ifndef DISABLE_BITBOARD_MOVEGEN); this removes that opt-out entirely (GNUmakefile) and deletes the mailbox-era code the flags used to toggle between, since there's no longer a build configuration that still needs it: - generate.c: the mailbox per-piece generators and escape-generators (GenerateKnight/GenerateWhiteKnight/GenerateBishop/GenerateRook/ GenerateQueen/GenerateBlackKing/GenerateWhiteKing/GenerateWhitePawn/ GenerateBlackPawn and their SaveMe* escape-generator counterparts), _FindUnblockedSquares and its DEBUG-build cross-check inside _FindUnblockedSquaresBB, and the dispatch-table #if/#else pairs that chose between mailbox and bitboard functions (now unconditionally bitboard). WouldGiveCheck simplified to its UNBLOCKED_BITBOARD-only body. g_iBDeltas/g_iRDeltas (orphaned once their only consumers were deleted) removed; g_iNDeltas (still used by data.c's InitMagic) moved there, next to its real consumer. - movesup.c: mailbox FasterExposesCheck/ExposesCheck/ExposesCheckEp/ IsAttacked/InCheck deleted; chess.h's three-way macro choice simplified to a direct #define onto the BB versions (ExposesCheckBB/ IsAttackedBB/etc. are simply "the" implementation now). - testsee.c/testgenerate.c: deleted the mailbox-vs-BB comparison/speed harnesses that only existed to validate code just removed (TestIsAttackedBB, TestGenerateKnightSpeed/KingSpeed/RookSpeed/ BishopSpeed/QueenSpeed, TestFindUnblockedSquaresSpeed's mailbox arm). TestGetAttacks and the _GenerateAllMoves-vs-_GenerateAllMovesBB dispatch-overhead benchmark are unaffected -- GetAttacks' mailbox/asm predecessors were already retired independently, and that pair compares two still-live BB-only dispatch strategies, not mailbox vs BB. Verified: clean release build and a clean DEBUG=1 TEST=1 self-test run (move generation, perft-style legal-move checks, SAN/ICS parsing, search smoke test) with no assertion failures. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/generate.c')
-rw-r--r--src/generate.c1853
1 files changed, 19 insertions, 1834 deletions
diff --git a/src/generate.c b/src/generate.c
index cf31891..3411474 100644
--- a/src/generate.c
+++ b/src/generate.c
@@ -56,114 +56,6 @@ Revision History:
const INT g_iQKDeltas[] = {
-17, -16, -15, -1, +1, +17, +15, +16, 0 };
-// Only needed as a standalone call site when UNBLOCKED_BITBOARD is
-// off; under that toggle it's still referenced (DEBUG builds only) by
-// _FindUnblockedSquaresBB's cross-check, so it can't simply be
-// deleted yet -- see board_representation/MOVEGEN_MIGRATION.md.
-#if !defined(UNBLOCKED_BITBOARD) || defined(DEBUG) || defined(TEST)
-// Exposed non-static (like generate.c's other migration-era helpers,
-// e.g. _GenerateRookBB) whenever anything other than this file might
-// need it: the DEBUG cross-check inside _FindUnblockedSquaresBB below,
-// or testgenerate.c's correctness/speed harness under TEST.
-void
-_FindUnblockedSquares(IN MOVE_STACK *pStack,
- IN POSITION *pos)
-/**
-
-Routine description:
-
- Given a position, find, count and mark all squares that are
- unblocked for the king of the side not on move. For example:
-
- +---+---+---+---+- - - The squares marked with *'s in this
- |***| K |***|*Q*| diagram are unblocked for the K. As
- +---+---+---+---+- - - you can see, there are nine of them.
- |*P*|***|***| |
- +---+---+---+---+- - - Note the piece at the end of an unblocked
- | |***| |*P*| ray from the king is on an unblocked
- +---+---+---+---+- - - square (and its color doesn't matter)
- | |*R*| | |
- +---+---+---+---+- - - This stuff is used to flag checking moves
- | | | | | as they are generated.
- . . . . .
-
- Also note: this is one of the most called routines in the engine;
- speed is of the essence here.
-
-Parameters:
-
- MOVE_STACK *pStack : move stack pointer
- POSITION *pos : position pointer
-
-Return value:
-
- void
-
-**/
-{
- register ULONG u;
- COOR cKing = KingPosition(pos, FLIP(pos->uToMove));
- COOR c;
- ULONG uPly = pStack->uPly;
-#ifdef DEBUG
- PIECE pKing = pos->rgSquare[cKing].pPiece;
- ULONG uCount = 0;
- COOR cx;
-
- ASSERT(IS_ON_BOARD(cKing));
- ASSERT(IS_KING(pKing));
- ASSERT(GET_COLOR(pKing) != pos->uToMove);
-#endif
-
- //
- // Adjust the unblocked key value for this ply...
- //
- pStack->uUnblockedKeyValue[uPly]++;
-#ifdef DEBUG
- FOREACH_SQUARE(c)
- {
- if (!IS_ON_BOARD(c)) continue;
- ASSERT(pStack->sUnblocked[uPly][c].uKey !=
- pStack->uUnblockedKeyValue[uPly]);
- }
-#endif
-
- u = 0;
- ASSERT(g_iQKDeltas[u] != 0);
- do
- {
- c = cKing + g_iQKDeltas[u];
- while(IS_ON_BOARD(c))
- {
- pStack->sUnblocked[uPly][c].uKey =
- pStack->uUnblockedKeyValue[uPly];
- pStack->sUnblocked[uPly][c].iPointer = -1 * g_iQKDeltas[u];
-#ifdef DEBUG
- ASSERT(-g_iQKDeltas[u] == DIRECTION_BETWEEN_SQUARES(c,cKing));
- ASSERT(pStack->sUnblocked[uPly][c].iPointer != 0);
- cx = c;
- do
- {
- cx += pStack->sUnblocked[uPly][c].iPointer;
- }
- while(IS_ON_BOARD(cx) && (IS_EMPTY(pos->rgSquare[cx].pPiece)));
- ASSERT(cx == cKing);
- uCount++;
-#endif
- if (!IS_EMPTY(pos->rgSquare[c].pPiece))
- {
- break;
- }
- c += g_iQKDeltas[u];
- }
- u++;
- }
- while(g_iQKDeltas[u] != 0);
- ASSERT(uCount > 2);
- ASSERT(uCount < 28);
-}
-#endif // !defined(UNBLOCKED_BITBOARD) || defined(DEBUG)
-
// board_representation/MOVEGEN_MIGRATION.md's never-started
// _FindUnblockedSquares/WouldGiveCheck candidate. Membership (is this
// square unblocked for the opposing king) is exactly the set of
@@ -211,43 +103,8 @@ Return value:
pStack->bbUnblocked[uPly] =
_RookAttacksBB(cKing, pos->bbOccupied) |
_BishopAttacksBB(cKing, pos->bbOccupied);
-
-#ifdef DEBUG
- {
- // Cross-check against the mailbox walk every single call --
- // this is the correctness gate for bring-up, not a one-time
- // test: membership must match exactly, and for every square
- // the bitboard claims is unblocked, the direction back to the
- // king recomputed via DIRECTION_BETWEEN_SQUARES must match
- // what the mailbox ray walk actually stored.
- COOR c;
- BITBOARD bb = pStack->bbUnblocked[uPly];
-
- _FindUnblockedSquares(pStack, pos);
- FOREACH_SQUARE(c)
- {
- if (!IS_ON_BOARD(c)) continue;
- FLAG fBB = (0 != (bb & COOR_TO_BB(c)));
- FLAG fMailbox = (pStack->sUnblocked[uPly][c].uKey ==
- pStack->uUnblockedKeyValue[uPly]);
- ASSERT(fBB == fMailbox);
- if (fBB)
- {
- ASSERT(DIRECTION_BETWEEN_SQUARES(c, cKing) ==
- pStack->sUnblocked[uPly][c].iPointer);
- }
- }
- // Restore: the mailbox call above just bumped
- // uUnblockedKeyValue[uPly] a second time this ply, which is
- // harmless (it's just a generation counter) but leave the
- // real bbUnblocked value as computed above, not whatever the
- // mailbox call's side effects might suggest.
- pStack->bbUnblocked[uPly] = bb;
- }
-#endif
}
-#ifdef UNBLOCKED_BITBOARD
// GenerateMoves no longer builds bbUnblocked[uPly] eagerly -- it just
// bumps this ply's generation ticket (uUnblockedKeyValue[uPly], see
// its comment in chess.h) so WouldGiveCheck's own lazy check (below)
@@ -262,16 +119,6 @@ Return value:
(0 != (pStack->bbUnblocked[ctx->uPly] & COOR_TO_BB(c)))
#define DIR_FROM_SQ_TO_KING(c) \
DIRECTION_BETWEEN_SQUARES((c), xKing)
-#else
-// Mailbox path has no lazy build to defer to -- its own per-square
-// sUnblocked[][].uKey scheme (SQUARE_IS_UNBLOCKED/DIR_FROM_SQ_TO_KING
-// below) is written directly by _FindUnblockedSquares itself, so this
-// stays eager, same as it always was.
-#define MARK_UNBLOCKED_SQUARES_STALE(pStack, pos, uPly) \
- ((void)(uPly), _FindUnblockedSquares((pStack), (pos)))
-#define SQUARE_IS_UNBLOCKED(c) (uUnblocked == kp[(c)].uKey)
-#define DIR_FROM_SQ_TO_KING(c) (kp[(c)].iPointer)
-#endif
FLAG FORCEINLINE
WouldGiveCheck(IN SEARCHER_THREAD_CONTEXT *ctx,
@@ -282,18 +129,12 @@ Routine description:
Determine whether a move is a checking move or not.
- Under UNBLOCKED_BITBOARD (this build's active path): self-
- sufficient -- builds bbUnblocked[ctx->uPly] itself, lazily, on the
- first call for a given generation (see the lazy-rebuild block
+ Self-sufficient -- builds bbUnblocked[ctx->uPly] itself, lazily, on
+ the first call for a given generation (see the lazy-rebuild block
below and chess.h's uUnblockedBuiltFor comment). GenerateMoves no
longer builds it eagerly, only marks the generation stale
(MARK_UNBLOCKED_SQUARES_STALE); callers no longer need to remember
- to call _FindUnblockedSquares[BB] first.
-
- Under the mailbox fallback (no UNBLOCKED_BITBOARD): the older
- precondition still holds -- _FindUnblockedSquares must have been
- called at the start of generation (MARK_UNBLOCKED_SQUARES_STALE
- still does this eagerly for that path, same as it always did).
+ to call _FindUnblockedSquaresBB first.
Note: this is one of the most called codepaths in the engine,
speed is of the essence here.
@@ -320,10 +161,6 @@ Return value:
COOR cFrom = mv.cFrom;
PIECE pPiece = mv.pMoved;
COOR xKing = KingPosition(pos, FLIP(GET_COLOR(pPiece)));
-#ifndef UNBLOCKED_BITBOARD
- KEY_POINTER *kp = &(pStack->sUnblocked[ctx->uPly][0]);
- ULONG uUnblocked = pStack->uUnblockedKeyValue[ctx->uPly];
-#endif
COOR cEpSquare;
int iDelta;
@@ -335,7 +172,6 @@ Return value:
ASSERT(IS_ON_BOARD(cFrom));
ASSERT(pPiece);
-#ifdef UNBLOCKED_BITBOARD
// Lazy rebuild: GenerateMoves only bumps uUnblockedKeyValue[uPly]
// (MARK_UNBLOCKED_SQUARES_STALE above) instead of building
// bbUnblocked[uPly] eagerly. The first WouldGiveCheck call for a
@@ -355,7 +191,6 @@ Return value:
_FindUnblockedSquaresBB(pStack, pos);
pStack->uUnblockedBuiltFor[ctx->uPly] = pStack->uUnblockedKeyValue[ctx->uPly];
}
-#endif
//
// Phase 1: Does this move directly attack the king?
@@ -794,100 +629,6 @@ Return value:
ASSERT(SanityCheckMove(pos, pMvf->mv));
}
-
-const INT g_iNDeltas[] = {
- -33, -31, -18, -14, +14, +18, +31, +33, 0 };
-
-void
-GenerateKnight(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cKnight)
-/**
-
-Routine description:
-
- This function is called by GenerateMoves' JumpTable. Its job
- is to generate and push pseudo-legal knight moves for the
- knight sitting on square cKnight.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cKnight : the knight's location
-
-Return value:
-
- void
-
-**/
-{
- COOR c;
- ULONG u = 0;
- PIECE p;
-
- ASSERT(IS_KNIGHT(pos->rgSquare[cKnight].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cKnight].pPiece) == pos->uToMove);
- ASSERT(g_iNDeltas[u] != 0);
-
- do
- {
- c = cKnight + g_iNDeltas[u];
- u++;
- if (IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
-
- //
- // This logical OR replaced with bitwise OR; the effect is
- // the same the the bitwise is marginally faster.
- //
- if (IS_EMPTY(p) | (OPPOSITE_COLORS(p, pos->uToMove)))
- {
- _AddNormalMove(pStack, pos, cKnight, c, p);
- }
- }
- }
- while(0 != g_iNDeltas[u]);
-}
-
-void
-GenerateWhiteKnight(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cKnight)
-{
- COOR c;
- ULONG u = 0;
- PIECE p;
-
- ASSERT(IS_KNIGHT(pos->rgSquare[cKnight].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cKnight].pPiece) == pos->uToMove);
- ASSERT(g_iNDeltas[u] != 0);
-
- do
- {
- c = cKnight + g_iNDeltas[u];
- u++;
- if (IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
-
- //
- // Note: this test covers empty squares also -- it is just
- // testing that the low order bit (color bit) of p is zero
- // which is true for black pieces and empty squares. This
- // is done for speed over readability.
- //
- if (GET_COLOR(p) == BLACK)
- {
- ASSERT(IS_EMPTY(p) || (GET_COLOR(p) == BLACK));
- _AddNormalMove(pStack, pos, cKnight, c, p);
- }
- }
- }
- while(0 != g_iNDeltas[u]);
-}
-
//
// board_representation/MOVEGEN_MIGRATION.md section 3 step 1: bitboard
// knight generator, the pilot function for the whole migration --
@@ -1095,82 +836,6 @@ Return value:
}
//
-// These logical AND/ORs replaced with bitwise AND/OR; the effect is
-// the same the the bitwise is marginally faster.
-//
-#define BLOCKS_THE_CHECK(sq) \
- ((iAttackDelta != 0) & \
- (iAttackDelta == DIRECTION_BETWEEN_SQUARES(cAttacker, (sq))) & \
- (((cAttacker > cKing) & ((sq) > cKing)) | \
- ((cAttacker < cKing) & ((sq) < cKing))))
-
-void
-SaveMeKnight(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cKnight,
- IN COOR cKing,
- IN COOR cAttacker)
-/**
-
-Routine description:
-
- This routine is called by GenerateEscapes' JumpTable. Its job is
- to generate moves by the knight on square cKnight that alleviate
- check to the king on square cKing. The (lone) piece attacking the
- king is on square cAttacker.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cKnight : the location of the knight
- COOR cKing : the location of the friendly king
- COOR cAttacker : the location of the checking piece
-
-Return value:
-
- void
-
-**/
-{
- COOR c, cExposed;
- int iAttackDelta = DIRECTION_BETWEEN_SQUARES(cAttacker, cKing);
- ULONG u = 0;
- PIECE p;
-
- ASSERT(InCheck(pos, pos->uToMove));
- ASSERT(IS_KNIGHT(pos->rgSquare[cKnight].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cKnight].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cKnight].pPiece) ==
- GET_COLOR(pos->rgSquare[cKing].pPiece));
- ASSERT(OPPOSITE_COLORS(pos->rgSquare[cAttacker].pPiece,
- pos->rgSquare[cKing].pPiece));
- ASSERT(g_iNDeltas[u] != 0);
-
- do
- {
- c = cKnight + g_iNDeltas[u];
- u++;
- if (IS_ON_BOARD(c))
- {
- if ((c == cAttacker) || BLOCKS_THE_CHECK(c))
- {
- cExposed = ExposesCheck(pos, cKnight, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == c))
- {
- p = pos->rgSquare[c].pPiece;
- ASSERT(!p ||
- OPPOSITE_COLORS(p, pos->rgSquare[cKnight].pPiece));
- ASSERT(!p || (c == cAttacker));
- _AddNormalMove(pStack, pos, cKnight, c, p);
- }
- }
- }
- }
- while(0 != g_iNDeltas[u]);
-}
-
-//
// board_representation/MOVEGEN_MIGRATION.md section 6a Phase 2:
// bitboard equivalent of SaveMeKnight -- one AND against a
// precomputed bbTargetMask replaces the per-square (c == cAttacker) ||
@@ -1233,117 +898,6 @@ Return value:
}
-const INT g_iBDeltas[] = {
- -17, -15, +15, +17, 0 };
-
-void
-GenerateBishop(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cBishop)
-/**
-
-Routine description:
-
- This routine is called by GenerateMoves' JumpTable to generate
- pseudo-legal bishop moves by the piece at cBishop.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cBishop : the bishop location
-
-Return value:
-
- void
-
-**/
-{
- COOR c;
- PIECE p;
-
- ASSERT(IS_BISHOP(pos->rgSquare[cBishop].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cBishop].pPiece) == pos->uToMove);
-
- //
- // Note: manually unrolled loop
- //
- c = cBishop - 17;
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if (IS_EMPTY(p))
- {
- _AddNormalMove(pStack, pos, cBishop, c, 0);
- }
- else
- {
- if (OPPOSITE_COLORS(p, pos->uToMove))
- {
- _AddNormalMove(pStack, pos, cBishop, c, p);
- }
- break;
- }
- c += -17;
- }
-
- c = cBishop - 15;
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if (IS_EMPTY(p))
- {
- _AddNormalMove(pStack, pos, cBishop, c, 0);
- }
- else
- {
- if (OPPOSITE_COLORS(p, pos->uToMove))
- {
- _AddNormalMove(pStack, pos, cBishop, c, p);
- }
- break;
- }
- c += -15;
- }
-
- c = cBishop + 15;
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if (IS_EMPTY(p))
- {
- _AddNormalMove(pStack, pos, cBishop, c, 0);
- }
- else
- {
- if (OPPOSITE_COLORS(p, pos->uToMove))
- {
- _AddNormalMove(pStack, pos, cBishop, c, p);
- }
- break;
- }
- c += 15;
- }
-
- c = cBishop + 17;
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if (IS_EMPTY(p))
- {
- _AddNormalMove(pStack, pos, cBishop, c, 0);
- }
- else
- {
- if (OPPOSITE_COLORS(p, pos->uToMove))
- {
- _AddNormalMove(pStack, pos, cBishop, c, p);
- }
- break;
- }
- c += 17;
- }
-}
//
// board_representation/MOVEGEN_MIGRATION.md section 3 step 3:
@@ -1418,78 +972,6 @@ Return value:
}
-void
-SaveMeBishop(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cBishop,
- IN COOR cKing,
- IN COOR cAttacker)
-/**
-
-Routine description:
-
- This routine is called by GenerateEscapes' JumpTable in order to
- generate moves by the bishop at cBishop to alleviate check on its
- friendly king (at cKing) which is being checked by a piece at
- cAttacker.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cBishop : the bishop's location
- COOR cKing : the friendly king's location
- COOR cAttacker : the checking piece's location
-
-Return value:
-
- void
-
-**/
-{
- int iAttackDelta = DIRECTION_BETWEEN_SQUARES(cAttacker, cKing);
- COOR c;
- COOR cExposed;
- ULONG u = 0;
- PIECE p;
-
- ASSERT(InCheck(pos, pos->uToMove));
- ASSERT(IS_BISHOP(pos->rgSquare[cBishop].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cBishop].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cBishop].pPiece) ==
- GET_COLOR(pos->rgSquare[cKing].pPiece));
- ASSERT(OPPOSITE_COLORS(pos->rgSquare[cAttacker].pPiece,
- pos->rgSquare[cKing].pPiece));
- ASSERT(g_iBDeltas[u] != 0);
-
- do
- {
- c = cBishop + g_iBDeltas[u];
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if ((c == cAttacker) || BLOCKS_THE_CHECK(c))
- {
- ASSERT(!p ||
- OPPOSITE_COLORS(p, pos->rgSquare[cBishop].pPiece));
- ASSERT(!p || (c == cAttacker));
- cExposed = ExposesCheck(pos, cBishop, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == c))
- {
- _AddNormalMove(pStack, pos, cBishop, c, p);
- break;
- }
- }
- else if (!IS_EMPTY(p))
- {
- break;
- }
- c += g_iBDeltas[u];
- }
- u++;
- }
- while(0 != g_iBDeltas[u]);
-}
//
// board_representation/MOVEGEN_MIGRATION.md section 6a Phase 2:
@@ -1551,118 +1033,6 @@ Return value:
}
-const INT g_iRDeltas[] = {
- -1, +1, +16, -16, 0 };
-
-
-void
-GenerateRook(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cRook)
-/**
-
-Routine description:
-
- This routine is called by GenerateMoves' JumpTable in order to
- generate pseudo-legal moves for the rook at position cRook.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cRook : the rook's location
-
-Return value:
-
- void
-
-**/
-{
- COOR c;
- PIECE p;
-
- ASSERT(IS_ROOK(pos->rgSquare[cRook].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cRook].pPiece) == pos->uToMove);
-
- //
- // Note: manually unrolled loop
- //
- c = cRook - 1;
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if (IS_EMPTY(p))
- {
- _AddNormalMove(pStack, pos, cRook, c, 0);
- }
- else
- {
- if (OPPOSITE_COLORS(p, pos->uToMove))
- {
- _AddNormalMove(pStack, pos, cRook, c, p);
- }
- break;
- }
- c += -1;
- }
-
- c = cRook + 1;
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if (IS_EMPTY(p))
- {
- _AddNormalMove(pStack, pos, cRook, c, 0);
- }
- else
- {
- if (OPPOSITE_COLORS(p, pos->uToMove))
- {
- _AddNormalMove(pStack, pos, cRook, c, p);
- }
- break;
- }
- c += 1;
- }
-
- c = cRook + 16;
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if (IS_EMPTY(p))
- {
- _AddNormalMove(pStack, pos, cRook, c, 0);
- }
- else
- {
- if (OPPOSITE_COLORS(p, pos->uToMove))
- {
- _AddNormalMove(pStack, pos, cRook, c, p);
- }
- break;
- }
- c += 16;
- }
-
- c = cRook - 16;
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if (IS_EMPTY(p))
- {
- _AddNormalMove(pStack, pos, cRook, c, 0);
- }
- else
- {
- if (OPPOSITE_COLORS(p, pos->uToMove))
- {
- _AddNormalMove(pStack, pos, cRook, c, p);
- }
- break;
- }
- c += -16;
- }
-}
//
// board_representation/MOVEGEN_MIGRATION.md section 3 step 3: magic-
@@ -1735,78 +1105,6 @@ Return value:
}
}
-void
-SaveMeRook(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cRook,
- IN COOR cKing,
- IN COOR cAttacker)
-/**
-
-Routine description:
-
- This routine is called by GenerateEscapes' JumpTable in order to
- generate moves by the rook at location cRook that alleviate check
- to the king at cKing. The lone checking piece is at cAttacker.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cRook : the rook's location
- COOR cKing : the king's location
- COOR cAttacker : the checker's location
-
-Return value:
-
- void
-
-**/
-{
- int iAttackDelta = DIRECTION_BETWEEN_SQUARES(cAttacker, cKing);
- COOR c;
- COOR cExposed;
- ULONG u = 0;
- PIECE p;
-
- ASSERT(InCheck(pos, pos->uToMove));
- ASSERT(IS_ROOK(pos->rgSquare[cRook].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cRook].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cRook].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cRook].pPiece) ==
- GET_COLOR(pos->rgSquare[cKing].pPiece));
- ASSERT(OPPOSITE_COLORS(pos->rgSquare[cAttacker].pPiece,
- pos->rgSquare[cKing].pPiece));
- ASSERT(g_iRDeltas[u] != 0);
-
- do
- {
- c = cRook + g_iRDeltas[u];
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if ((c == cAttacker) || BLOCKS_THE_CHECK(c))
- {
- ASSERT(!p ||
- OPPOSITE_COLORS(p, pos->rgSquare[cRook].pPiece));
- ASSERT(!p || (c == cAttacker));
- cExposed = ExposesCheck(pos, cRook, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == c))
- {
- _AddNormalMove(pStack, pos, cRook, c, p);
- break;
- }
- }
- else if (!IS_EMPTY(p))
- {
- break;
- }
- c += g_iRDeltas[u];
- }
- u++;
- }
- while(0 != g_iRDeltas[u]);
-}
//
// board_representation/MOVEGEN_MIGRATION.md section 6a Phase 2:
@@ -1868,61 +1166,6 @@ Return value:
}
-void
-GenerateQueen(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cQueen)
-/**
-
-Routine description:
-
- This routine is called by GenerateMoves' JumpTable in order to
- generate pseudo-legal moves for the queen at position cQueen.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cQueen : the queen's location
-
-Return value:
-
- void
-
-**/
-{
- COOR c;
- ULONG u = 0;
- PIECE p;
-
- ASSERT(IS_QUEEN(pos->rgSquare[cQueen].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cQueen].pPiece) == pos->uToMove);
- ASSERT(g_iQKDeltas[u] != 0);
-
- do
- {
- c = cQueen + g_iQKDeltas[u];
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if (IS_EMPTY(p))
- {
- _AddNormalMove(pStack, pos, cQueen, c, 0);
- }
- else
- {
- if (OPPOSITE_COLORS(p, pos->uToMove))
- {
- _AddNormalMove(pStack, pos, cQueen, c, p);
- }
- break;
- }
- c += g_iQKDeltas[u];
- }
- u++;
- }
- while(0 != g_iQKDeltas[u]);
-}
//
// board_representation/MOVEGEN_MIGRATION.md section 3 step 4: queen is
@@ -2001,79 +1244,6 @@ Return value:
}
-void
-SaveMeQueen(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cQueen,
- IN COOR cKing,
- IN COOR cAttacker)
-/**
-
-Routine description:
-
- This routine is called by code in GenerateEscapes in order to
- generate moves by the queen at square cQueen that alleviate check
- on the friendly king at square cKing. The lone enemy piece that
- is checking the king is sitting on square cAttacker.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cQueen : the queen's location
- COOR cKing : the friendly king's location
- COOR cAttacker : the attacker's location
-
-Return value:
-
- void
-
-**/
-{
- COOR c;
- COOR cExposed;
- int iAttackDelta = DIRECTION_BETWEEN_SQUARES(cAttacker, cKing);
- ULONG u = 0;
- PIECE p;
-
- ASSERT(InCheck(pos, pos->uToMove));
- ASSERT(IS_QUEEN(pos->rgSquare[cQueen].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cQueen].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cQueen].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cQueen].pPiece) ==
- GET_COLOR(pos->rgSquare[cKing].pPiece));
- ASSERT(OPPOSITE_COLORS(pos->rgSquare[cAttacker].pPiece,
- pos->rgSquare[cKing].pPiece));
- ASSERT(g_iQKDeltas[u] != 0);
-
- do
- {
- c = cQueen + g_iQKDeltas[u];
- while(IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
- if ((c == cAttacker) || BLOCKS_THE_CHECK(c))
- {
- ASSERT(!p ||
- OPPOSITE_COLORS(p, pos->rgSquare[cQueen].pPiece));
- ASSERT(!p || (c == cAttacker));
- cExposed = ExposesCheck(pos, cQueen, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == c))
- {
- _AddNormalMove(pStack, pos, cQueen, c, p);
- break;
- }
- }
- else if (!IS_EMPTY(p))
- {
- break;
- }
- c += g_iQKDeltas[u];
- }
- u++;
- }
- while(0 != g_iQKDeltas[u]);
-}
//
// board_representation/MOVEGEN_MIGRATION.md section 6a Phase 2:
@@ -2135,178 +1305,6 @@ Return value:
}
}
-void
-GenerateBlackKing(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cKing)
-/**
-
-Routine description:
-
- This function is called by GenerateMoves in order to generate
- pseudo-legal moves for the black king at square cKing. Note: this
- function often generates illegal castling moves and relies on the
- MakeMove code to decide about the legality of the castle.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cKing : the king location
-
-Return value:
-
- void
-
-**/
-{
- COOR c;
- ULONG u = 0;
- PIECE p;
-
- ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) == pos->uToMove);
- ASSERT(g_iQKDeltas[u] != 0);
-
- do
- {
- c = cKing + g_iQKDeltas[u];
- u++;
- if (IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
-
- //
- // This logical OR replaced with bitwise OR; the effect is
- // the same the the bitwise is marginally faster.
- //
- if (IS_EMPTY(p) | (GET_COLOR(p)))
- {
- _AddNormalMove(pStack, pos, cKing, c, p);
- }
- }
- }
- while(0 != g_iQKDeltas[u]);
-
- if ((pos->bvCastleInfo & BLACK_CAN_CASTLE) == 0) return;
-#ifdef DEBUG
- p = pos->rgSquare[E8].pPiece;
- ASSERT(IS_KING(p));
- ASSERT(cKing == E8);
-#endif
-
- //
- // Note: no castling through check is enforced at the time the
- // move is played. This is a "pseudo-legal" move when generated.
- //
- if ((pos->bvCastleInfo & CASTLE_BLACK_SHORT) &&
- (IS_EMPTY(pos->rgSquare[G8].pPiece)) &&
- (IS_EMPTY(pos->rgSquare[F8].pPiece)))
- {
- ASSERT(pos->rgSquare[H8].pPiece == BLACK_ROOK);
- _AddCastle(pStack, pos, E8, G8);
- }
-
- if ((pos->bvCastleInfo & CASTLE_BLACK_LONG) &&
- (IS_EMPTY(pos->rgSquare[C8].pPiece)) &&
- (IS_EMPTY(pos->rgSquare[D8].pPiece)) &&
- (IS_EMPTY(pos->rgSquare[B8].pPiece)))
- {
- ASSERT(pos->rgSquare[A8].pPiece == BLACK_ROOK);
- _AddCastle(pStack, pos, E8, C8);
- }
-}
-
-//
-// N.B. There is no SaveYourselfBlackKing or SaveYourselfWhiteKing
-// because this functionality is built into phase 1 of
-// GenerateEscapes.
-//
-
-void
-GenerateWhiteKing(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cKing)
-/**
-
-Routine description:
-
- This function is called by GenerateMoves in order to generate
- pseudo-legal king moves by the white king at square cKing. Note:
- it often generates illegal castling moves and relies on the code
- in MakeMove to determine the legality of castles.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cKing : the king location
-
-Return value:
-
- void
-
-**/
-{
- COOR c;
- ULONG u = 0;
- PIECE p;
-
- ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cKing].pPiece) == pos->uToMove);
- ASSERT(g_iQKDeltas[u] != 0);
-
- do
- {
- c = cKing + g_iQKDeltas[u];
- u++;
- if (IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
-
- //
- // Note: this test covers empty squares also -- it is just
- // testing that the low order bit (color bit) of p is zero
- // which is true for black pieces and empty squares. This
- // is done for speed over readability.
- //
- if (GET_COLOR(p) == BLACK)
- {
- ASSERT(IS_EMPTY(p) || (GET_COLOR(p) == BLACK));
- _AddNormalMove(pStack, pos, cKing, c, p);
- }
- }
- }
- while(0 != g_iQKDeltas[u]);
-
- if ((pos->bvCastleInfo & WHITE_CAN_CASTLE) == 0) return;
-#ifdef DEBUG
- p = pos->rgSquare[E1].pPiece;
- ASSERT(IS_KING(p));
- ASSERT(cKing == E1);
-#endif
-
- //
- // Note: no castling through check is enforced at the time the
- // move is played. This is a "pseudo-legal" move when generated.
- //
- if ((pos->bvCastleInfo & CASTLE_WHITE_SHORT) &&
- (IS_EMPTY(pos->rgSquare[G1].pPiece)) &&
- (IS_EMPTY(pos->rgSquare[F1].pPiece)))
- {
- ASSERT(pos->rgSquare[H1].pPiece == WHITE_ROOK);
- _AddCastle(pStack, pos, E1, G1);
- }
-
- if ((pos->bvCastleInfo & CASTLE_WHITE_LONG) &&
- (IS_EMPTY(pos->rgSquare[C1].pPiece)) &&
- (IS_EMPTY(pos->rgSquare[B1].pPiece)) &&
- (IS_EMPTY(pos->rgSquare[D1].pPiece)))
- {
- ASSERT(pos->rgSquare[A1].pPiece == WHITE_ROOK);
- _AddCastle(pStack, pos, E1, C1);
- }
-}
//
// board_representation/MOVEGEN_MIGRATION.md section 3 step 2: bitboard
@@ -2425,406 +1423,6 @@ Return value:
}
}
-
-void
-GenerateWhitePawn(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cPawn)
-/**
-
-Routine description:
-
- This function is called by GenerateMoves in order to generate
- pseudo-legal pawn moves by the pawn at cPawn. It handles
- en passant captures, double jumps, promotions, etc...
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cPawn : the pawn's location
-
-Return value:
-
- void
-
-**/
-{
- ULONG uRank = RANK(cPawn);
- PIECE p;
- COOR cTo;
-
- ASSERT(IS_PAWN(pos->rgSquare[cPawn].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) == pos->uToMove);
- ASSERT((RANK(cPawn) >= 2) && (RANK(cPawn) <= 7));
-
- if (uRank != 7)
- {
- cTo = cPawn - 16;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- _AddNormalMove(pStack, pos, cPawn, cTo, 0);
- if (uRank == 2)
- {
- cTo = cPawn - 32;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- _AddDoubleJump(pStack, pos, cPawn, cTo);
- }
- }
- }
- cTo = cPawn - 15;
- if (IS_ON_BOARD(cTo))
- {
- if (cTo == pos->cEpSquare)
- {
- _AddEnPassant(pStack, pos, cPawn, cTo);
- }
- p = pos->rgSquare[cTo].pPiece;
-
- //
- // This logical AND replaced with bitwise AND; the effect
- // is the same the the bitwise is marginally faster.
- //
- if (!IS_EMPTY(p) & (GET_COLOR(p) == BLACK))
- {
- _AddNormalMove(pStack, pos, cPawn, cTo, p);
- }
- }
- cTo = cPawn - 17;
- if (IS_ON_BOARD(cTo))
- {
- if (cTo == pos->cEpSquare)
- {
- _AddEnPassant(pStack, pos, cPawn, cTo);
- }
- p = pos->rgSquare[cTo].pPiece;
-
- //
- // This logical AND replaced with bitwise AND; the effect
- // is the same the the bitwise is marginally faster.
- //
- if (!IS_EMPTY(p) & (GET_COLOR(p) == BLACK))
- {
- _AddNormalMove(pStack, pos, cPawn, cTo, p);
- }
- }
- }
- else
- {
- ASSERT(RANK7(cPawn));
- cTo = cPawn - 16;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- cTo = cPawn - 15;
- if (IS_ON_BOARD(cTo))
- {
- p = pos->rgSquare[cTo].pPiece;
-
- //
- // This logical AND replaced with bitwise AND; the effect
- // is the same the the bitwise is marginally faster.
- //
- if (!IS_EMPTY(p) & (GET_COLOR(p) == BLACK))
- {
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- }
- cTo = cPawn - 17;
- if (IS_ON_BOARD(cTo))
- {
- p = pos->rgSquare[cTo].pPiece;
-
- //
- // This logical AND replaced with bitwise AND; the effect
- // is the same the the bitwise is marginally faster.
- //
- if (!IS_EMPTY(p) & (GET_COLOR(p) == BLACK))
- {
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- }
- }
-}
-
-
-void
-SaveMeWhitePawn(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cPawn,
- IN COOR cKing,
- IN COOR cAttacker)
-/**
-
-Routine description:
-
- This function is called by the GenerateEscapes code in order to
- ask for a pawn's help in alleviating check on the king at square
- cKing. The lone attacker to said king is on square cAttacker.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cPawn : the pawn's location
- COOR cKing : the friendly king's location
- COOR cAttacker : the location of the lone checker to the king
-
-Return value:
-
- void
-
-**/
-{
- ULONG uRank = RANK(cPawn);
- PIECE p;
- COOR cTo;
- COOR cExposed;
- int iAttackDelta = DIRECTION_BETWEEN_SQUARES(cAttacker, cKing);
-
- ASSERT(InCheck(pos, pos->uToMove));
- ASSERT(IS_PAWN(pos->rgSquare[cPawn].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) == WHITE);
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) ==
- GET_COLOR(pos->rgSquare[cKing].pPiece));
- ASSERT(OPPOSITE_COLORS(pos->rgSquare[cAttacker].pPiece,
- pos->rgSquare[cKing].pPiece));
- ASSERT((RANK(cPawn) >= 2) && (RANK(cPawn) <= 7));
-
- if (uRank != 7)
- {
- cTo = cPawn - 16;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- if (BLOCKS_THE_CHECK(cTo) &&
- !IS_ON_BOARD(ExposesCheck(pos, cPawn, cKing)))
- {
- _AddNormalMove(pStack, pos, cPawn, cTo, 0);
- }
-
- if (uRank == 2)
- {
- cTo = cPawn - 32;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece) &&
- BLOCKS_THE_CHECK(cTo) &&
- !IS_ON_BOARD(ExposesCheck(pos, cPawn, cKing)))
- {
- _AddDoubleJump(pStack, pos, cPawn, cTo);
- }
- }
- }
-
- cTo = cPawn - 15;
- if (cTo == cAttacker)
- {
- cExposed = ExposesCheck(pos, cPawn, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == cAttacker))
- {
- p = pos->rgSquare[cTo].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(GET_COLOR(p) == BLACK);
- ASSERT(IS_ON_BOARD(cTo));
- _AddNormalMove(pStack, pos, cPawn, cTo, p);
- }
- }
-
- //
- // N.B. There is no possible way to block check with an
- // en-passant capture because by definition the last move made
- // by the other side was the pawn double jump. So only handle
- // if the double jumping enemy pawn is the attacker and we can
- // kill it en passant.
- //
- if ((cTo == pos->cEpSquare) && (cAttacker == cTo + 16))
- {
- _AddEnPassant(pStack, pos, cPawn, cTo);
- }
-
- cTo = cPawn - 17;
- if (cTo == cAttacker)
- {
- cExposed = ExposesCheck(pos, cPawn, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == cAttacker))
- {
- p = pos->rgSquare[cTo].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(GET_COLOR(p) == BLACK);
- ASSERT(IS_ON_BOARD(cTo));
- _AddNormalMove(pStack, pos, cPawn, cTo, p);
- }
- }
- if ((cTo == pos->cEpSquare) && (cAttacker == cTo + 16))
- {
- _AddEnPassant(pStack, pos, cPawn, cTo);
- }
- }
- else
- {
- ASSERT(RANK7(cPawn));
- cTo = cPawn - 16;
- if (BLOCKS_THE_CHECK(cTo) && IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- _AddPromote(pStack, pos, cPawn, cTo);
- }
-
- cTo = cPawn - 15;
- if (cTo == cAttacker)
- {
- cExposed = ExposesCheck(pos, cPawn, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == cAttacker))
- {
- p = pos->rgSquare[cTo].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(GET_COLOR(p) == BLACK);
- ASSERT(IS_ON_BOARD(cTo));
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- }
-
- cTo = cPawn - 17;
- if (cTo == cAttacker)
- {
- cExposed = ExposesCheck(pos, cPawn, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == cAttacker))
- {
- p = pos->rgSquare[cTo].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(GET_COLOR(p) == BLACK);
- ASSERT(IS_ON_BOARD(cTo));
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- }
- }
-}
-
-
-void
-GenerateBlackPawn(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cPawn)
-/**
-
-Routine description:
-
- This code is called by GenerateMoves in order to handle move
- generation for the black pawn on square cPawn. It handles
- en passant captures, double jumps, and promotion.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the position
- COOR cPawn : the pawn location
-
-Return value:
-
- void
-
-**/
-{
- ULONG uRank = RANK(cPawn);
- PIECE p;
- COOR cTo;
-
- ASSERT(IS_PAWN(pos->rgSquare[cPawn].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) == pos->uToMove);
- ASSERT((RANK(cPawn) >= 2) && (RANK(cPawn) <= 7));
-
- if (uRank != 2)
- {
- cTo = cPawn + 16;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- _AddNormalMove(pStack, pos, cPawn, cTo, 0);
- if (uRank == 7)
- {
- cTo = cPawn + 32;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- _AddDoubleJump(pStack, pos, cPawn, cTo);
- }
- }
- }
- cTo = cPawn + 15;
- if (IS_ON_BOARD(cTo))
- {
- if (cTo == pos->cEpSquare)
- {
- _AddEnPassant(pStack, pos, cPawn, cTo);
- }
- p = pos->rgSquare[cTo].pPiece;
-
- //
- // This logical AND replaced with bitwise AND; the effect
- // is the same the the bitwise is marginally faster.
- //
- if (!IS_EMPTY(p) & (GET_COLOR(p)))
- {
- _AddNormalMove(pStack, pos, cPawn, cTo, p);
- }
- }
- cTo = cPawn + 17;
- if (IS_ON_BOARD(cTo))
- {
- if (cTo == pos->cEpSquare)
- {
- _AddEnPassant(pStack, pos, cPawn, cTo);
- }
- p = pos->rgSquare[cTo].pPiece;
-
- //
- // This logical AND replaced with bitwise AND; the effect
- // is the same the the bitwise is marginally faster.
- //
- if (!IS_EMPTY(p) & (GET_COLOR(p)))
- {
- _AddNormalMove(pStack, pos, cPawn, cTo, p);
- }
- }
- }
- else
- {
- ASSERT(RANK2(cPawn));
- cTo = cPawn + 16;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- cTo = cPawn + 15;
- if (IS_ON_BOARD(cTo))
- {
- p = pos->rgSquare[cTo].pPiece;
-
- //
- // This logical AND replaced with bitwise AND; the effect
- // is the same the the bitwise is marginally faster.
- //
- if (!IS_EMPTY(p) & (GET_COLOR(p)))
- {
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- }
- cTo = cPawn + 17;
- if (IS_ON_BOARD(cTo))
- {
- p = pos->rgSquare[cTo].pPiece;
-
- //
- // This logical AND replaced with bitwise AND; the effect
- // is the same the the bitwise is marginally faster.
- //
- if (!IS_EMPTY(p) & (GET_COLOR(p)))
- {
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- }
- }
-}
-
//
// board_representation/MOVEGEN_MIGRATION.md section 3 step 5: bulk,
// whole-side pawn generator using the classic shift-and-mask technique
@@ -3033,160 +1631,6 @@ Return value:
}
-void
-SaveMeBlackPawn(IN MOVE_STACK *pStack,
- IN POSITION *pos,
- IN COOR cPawn,
- IN COOR cKing,
- IN COOR cAttacker)
-/**
-
-Routine description:
-
- This code is called to ask for a black pawn's help in alleviating
- check to its king. The pawn is on square cPawn. The friendly
- king is on square cKing. The lone enemy piece attacking it is on
- square cAttacker.
-
-Parameters:
-
- MOVE_STACK *pStack : the move stack
- POSITION *pos : the board position
- COOR cPawn : the pawn location
- COOR cKing : the friendly king location
- COOR cAttacker : the lone checker location
-
-Return value:
-
- void
-
-**/
-{
- ULONG uRank = RANK(cPawn);
- PIECE p;
- COOR cTo;
- COOR cExposed;
- int iAttackDelta = DIRECTION_BETWEEN_SQUARES(cAttacker, cKing);
-
- ASSERT(InCheck(pos, pos->uToMove));
- ASSERT(IS_PAWN(pos->rgSquare[cPawn].pPiece));
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) == BLACK);
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) == pos->uToMove);
- ASSERT(GET_COLOR(pos->rgSquare[cPawn].pPiece) ==
- GET_COLOR(pos->rgSquare[cKing].pPiece));
- ASSERT(OPPOSITE_COLORS(pos->rgSquare[cAttacker].pPiece,
- pos->rgSquare[cKing].pPiece));
- ASSERT((RANK(cPawn) >= 2) && (RANK(cPawn) <= 7));
-
- if (uRank != 2)
- {
- cTo = cPawn + 16;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- if (BLOCKS_THE_CHECK(cTo) &&
- !IS_ON_BOARD(ExposesCheck(pos, cPawn, cKing)))
- {
- _AddNormalMove(pStack, pos, cPawn, cTo, 0);
- }
-
- if (uRank == 7)
- {
- cTo = cPawn + 32;
- if (IS_EMPTY(pos->rgSquare[cTo].pPiece) &&
- BLOCKS_THE_CHECK(cTo) &&
- !IS_ON_BOARD(ExposesCheck(pos, cPawn, cKing)))
- {
- _AddDoubleJump(pStack, pos, cPawn, cTo);
- }
- }
- }
-
- cTo = cPawn + 15;
- if (cTo == cAttacker)
- {
- cExposed = ExposesCheck(pos, cPawn, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == cAttacker))
- {
- p = pos->rgSquare[cTo].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(GET_COLOR(p) == WHITE);
- ASSERT(IS_ON_BOARD(cTo));
- _AddNormalMove(pStack, pos, cPawn, cTo, p);
- }
- }
-
- //
- // N.B. There is no possible way to block check with an
- // en-passant capture because by definition the last move made
- // by the other side was the pawn double jump. So only handle
- // if the double jumping enemy pawn is the attacker and we can
- // kill it en passant.
- //
- if ((cTo == pos->cEpSquare) &&
- (cAttacker == cTo - 16))
- {
- _AddEnPassant(pStack, pos, cPawn, cTo);
- }
-
- cTo = cPawn + 17;
- if (cTo == cAttacker)
- {
- cExposed = ExposesCheck(pos, cPawn, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == cAttacker))
- {
- p = pos->rgSquare[cTo].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(GET_COLOR(p) == WHITE);
- ASSERT(IS_ON_BOARD(cTo));
- _AddNormalMove(pStack, pos, cPawn, cTo, p);
- }
- }
- if ((cTo == pos->cEpSquare) &&
- (cAttacker == cTo - 16))
- {
- _AddEnPassant(pStack, pos, cPawn, cTo);
- }
- }
- else
- {
- ASSERT(RANK2(cPawn));
- cTo = cPawn + 16;
- if (BLOCKS_THE_CHECK(cTo) &&
- IS_EMPTY(pos->rgSquare[cTo].pPiece))
- {
- _AddPromote(pStack, pos, cPawn, cTo);
- }
-
- cTo = cPawn + 15;
- if (cTo == cAttacker)
- {
- cExposed = ExposesCheck(pos, cPawn, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == cAttacker))
- {
- p = pos->rgSquare[cTo].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(GET_COLOR(p) == WHITE);
- ASSERT(IS_ON_BOARD(cTo));
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- }
-
- cTo = cPawn + 17;
- if (cTo == cAttacker)
- {
- cExposed = ExposesCheck(pos, cPawn, cKing);
- if (!IS_ON_BOARD(cExposed) || (cExposed == cAttacker))
- {
- p = pos->rgSquare[cTo].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(GET_COLOR(p) == WHITE);
- ASSERT(IS_ON_BOARD(cTo));
- _AddPromote(pStack, pos, cPawn, cTo);
- }
- }
- }
-}
//
// board_representation/MOVEGEN_MIGRATION.md section 6a Phase 2: bulk
@@ -3969,45 +2413,19 @@ Return value:
InvalidGenerator, // EMPTY | WHITE
InvalidGenerator, // 2 (BLACK_PAWN)
InvalidGenerator, // 3 (WHITE_PAWN)
- // MOVEGEN_MIGRATION.md section 6 toggle -- one #define per
- // piece type, independent of the others. _GenerateKnightBB
- // serves both slots; see its header comment for why the
- // mailbox pair's color split doesn't carry over to bitboards.
-#if defined(GENERATE_KNIGHT_BITBOARD)
+ // _GenerateKnightBB serves both slots; see its header comment
+ // for why the mailbox pair's old color split doesn't carry
+ // over to bitboards.
_GenerateKnightBB, // 4 (BLACK_KNIGHT)
_GenerateKnightBB, // 5 (WHITE_KNIGHT)
-#else
- GenerateKnight, // 4 (BLACK_KNIGHT)
- GenerateWhiteKnight, // 5 (WHITE_KNIGHT)
-#endif
-#if defined(GENERATE_BISHOP_BITBOARD)
_GenerateBishopBB, // 6 (BLACK_BISHOP)
_GenerateBishopBB, // 7 (WHITE_BISHOP)
-#else
- GenerateBishop, // 6 (BLACK_BISHOP)
- GenerateBishop, // 7 (WHITE_BISHOP)
-#endif
-#if defined(GENERATE_ROOK_BITBOARD)
_GenerateRookBB, // 8 (BLACK_ROOK)
_GenerateRookBB, // 9 (WHITE_ROOK)
-#else
- GenerateRook, // 8 (BLACK_ROOK)
- GenerateRook, // 9 (WHITE_ROOK)
-#endif
-#if defined(GENERATE_QUEEN_BITBOARD)
_GenerateQueenBB, // 10 (BLACK_QUEEN)
_GenerateQueenBB, // 11 (WHITE_QUEEN)
-#else
- GenerateQueen, // 10 (BLACK_QUEEN)
- GenerateQueen, // 11 (WHITE_QUEEN)
-#endif
-#if defined(GENERATE_KING_BITBOARD)
_GenerateKingBB, // 12 (BLACK_KING)
_GenerateKingBB // 13 (WHITE_KING)
-#else
- GenerateBlackKing, // 12 (BLACK_KING)
- GenerateWhiteKing // 13 (WHITE_KING)
-#endif
};
#ifdef DEBUG
PIECE p;
@@ -4017,17 +2435,9 @@ Return value:
// _GenerateKnightBB's header comment: computed once per node here,
// before any piece-type dispatch, so every bitboard-backed
// generator invoked below shares this build instead of each
- // recomputing it -- extend this #if with each new
- // GENERATE_*_BITBOARD toggle as piece types migrate.
-#if defined(GENERATE_KNIGHT_BITBOARD) || defined(GENERATE_KING_BITBOARD) || \
- defined(GENERATE_ROOK_BITBOARD) || defined(GENERATE_BISHOP_BITBOARD) || \
- defined(GENERATE_QUEEN_BITBOARD)
+ // recomputing it.
pStack->bbFriendlyOccupied = _BuildFriendlySideBB(pos, pos->uToMove);
-#endif
-#if defined(GENERATE_ROOK_BITBOARD) || defined(GENERATE_BISHOP_BITBOARD) || \
- defined(GENERATE_QUEEN_BITBOARD)
pStack->bbOccupied = pos->bbOccupied;
-#endif
{
BITBOARD bbNonPawns = NON_KING_PIECES_BB(pos, pos->uToMove) |
@@ -4045,39 +2455,7 @@ Return value:
}
}
-#if defined(GENERATE_PAWN_BITBOARD)
_GenerateAllPawnMovesBB(pStack, pos, pos->uToMove);
-#else
- if (pos->uToMove == BLACK)
- {
- BITBOARD bbPawnsToWalk = pos->bbPawns[BLACK];
-
- while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk)))
- {
-#ifdef DEBUG
- p = pos->rgSquare[c].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(IS_PAWN(p));
- ASSERT(GET_COLOR(p) == pos->uToMove);
-#endif
- GenerateBlackPawn(pStack, pos, c);
- }
- } else {
- BITBOARD bbPawnsToWalk = pos->bbPawns[WHITE];
-
- ASSERT(pos->uToMove == WHITE);
- while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk)))
- {
-#ifdef DEBUG
- p = pos->rgSquare[c].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(IS_PAWN(p));
- ASSERT(GET_COLOR(p) == pos->uToMove);
-#endif
- GenerateWhitePawn(pStack, pos, c);
- }
- }
-#endif
}
//
@@ -4148,9 +2526,6 @@ Return value:
BITBOARD bb;
ULONG uBitIndex;
COOR c;
-#if defined(DEBUG) && !defined(GENERATE_PAWN_BITBOARD)
- PIECE p;
-#endif
pStack->bbFriendlyOccupied = _BuildFriendlySideBB(pos, uSide);
pStack->bbOccupied = pos->bbOccupied;
@@ -4203,59 +2578,17 @@ Return value:
ASSERT(IS_KING(pos->rgSquare[c].pPiece));
_GenerateKingBB(pStack, pos, c);
- // Pawns: unchanged from _GenerateAllMoves -- not in scope for this
- // migration (section 3 step 5's pawn note) unless
- // GENERATE_PAWN_BITBOARD is also defined, in which case pawns get
- // the same bulk treatment via _GenerateAllPawnMovesBB -- pawns'
- // own toggle is independent of the five above (section 6).
-#if defined(GENERATE_PAWN_BITBOARD)
+ // Pawns get the same bulk treatment via _GenerateAllPawnMovesBB.
_GenerateAllPawnMovesBB(pStack, pos, uSide);
-#else
- if (uSide == BLACK)
- {
- BITBOARD bbPawnsToWalk = pos->bbPawns[BLACK];
-
- while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk)))
- {
-#ifdef DEBUG
- p = pos->rgSquare[c].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(IS_PAWN(p));
- ASSERT(GET_COLOR(p) == uSide);
-#endif
- GenerateBlackPawn(pStack, pos, c);
- }
- }
- else
- {
- BITBOARD bbPawnsToWalk = pos->bbPawns[WHITE];
-
- ASSERT(uSide == WHITE);
- while (IS_ON_BOARD(c = CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk)))
- {
-#ifdef DEBUG
- p = pos->rgSquare[c].pPiece;
- ASSERT(!IS_EMPTY(p));
- ASSERT(IS_PAWN(p));
- ASSERT(GET_COLOR(p) == uSide);
-#endif
- GenerateWhitePawn(pStack, pos, c);
- }
- }
-#endif
}
// Whole-dispatch fork -- see _GenerateAllMovesBB's block comment for
// why this is a #define swap of the entire function (matching
// chess.h's GetAttacks precedent) rather than a branch nested inside
-// _GenerateAllMoves. Only fires when every non-pawn, non-castling
-// piece type is bitboard-backed; any partial mix still uses
-// _GenerateAllMoves's cNonPawns/JumpTable path unchanged.
-#if defined(GENERATE_KNIGHT_BITBOARD) && defined(GENERATE_KING_BITBOARD) && \
- defined(GENERATE_ROOK_BITBOARD) && defined(GENERATE_BISHOP_BITBOARD) && \
- defined(GENERATE_QUEEN_BITBOARD)
+// _GenerateAllMoves. _GenerateAllMoves itself (the JumpTable/cNonPawns
+// version above) is kept only as testgenerate.c's named comparison
+// point -- production always goes through this redirect.
#define _GenerateAllMoves _GenerateAllMovesBB
-#endif
static ULONG
@@ -4285,47 +2618,12 @@ Return value:
**/
{
-#if !defined(GENERATE_ESCAPES_KING_BITBOARD) || !defined(GENERATE_ESCAPES_BLOCK_BITBOARD)
- ULONG u;
-#endif
-#if !defined(GENERATE_ESCAPES_KING_BITBOARD)
- ULONG v;
-#endif
COOR c;
-#if !defined(GENERATE_ESCAPES_BLOCK_BITBOARD)
- COOR cDefender;
-#endif
PIECE p;
PIECE pKing;
COOR cKing = KingPosition(pos, pos->uToMove);
-#if !defined(GENERATE_ESCAPES_KING_BITBOARD)
- int iIndex;
-#endif
SEE_LIST rgCheckers;
-#if !defined(GENERATE_ESCAPES_KING_BITBOARD)
- int iDelta;
-#endif
ULONG uReturn = 0;
-#if !defined(GENERATE_ESCAPES_BLOCK_BITBOARD)
- static void (*JumpTable[])
- (MOVE_STACK *, POSITION *, COOR, COOR, COOR) =
- {
- InvalidSaveMe, // EMPTY
- InvalidSaveMe, // EMPTY | WHITE
- InvalidSaveMe, // 2 (BLACK_PAWN)
- InvalidSaveMe, // 3 (WHITE_PAWN)
- SaveMeKnight, // 4 (BLACK_KNIGHT)
- SaveMeKnight, // 5 (WHITE_KNIGHT)
- SaveMeBishop, // 6 (BLACK_BISHOP)
- SaveMeBishop, // 7 (WHITE_BISHOP)
- SaveMeRook, // 8 (BLACK_ROOK)
- SaveMeRook, // 9 (WHITE_ROOK)
- SaveMeQueen, // 10 (BLACK_QUEEN)
- SaveMeQueen, // 11 (WHITE_QUEEN)
- InvalidSaveMe, // kings already considered
- InvalidSaveMe // kings already considered
- };
-#endif
ASSERT(IS_KING(pos->rgSquare[cKing].pPiece));
ASSERT(TRUE == InCheck(pos, pos->uToMove));
@@ -4349,7 +2647,6 @@ Return value:
ASSERT(GET_COLOR(pKing) == pos->uToMove);
ASSERT(IS_KING(pKing));
ASSERT(OPPOSITE_COLORS(pKing, rgCheckers.data[0].pPiece));
-#if defined(GENERATE_ESCAPES_KING_BITBOARD)
//
// board_representation/MOVEGEN_MIGRATION.md section 6a Phase 1:
// g_KingAttacksBB gives every candidate flight square in one
@@ -4392,69 +2689,6 @@ Return value:
}
}
}
-#else
- u = 0;
- while(0 != g_iQKDeltas[u])
- {
- c = cKing + g_iQKDeltas[u];
- u++;
- if (IS_ON_BOARD(c))
- {
- p = pos->rgSquare[c].pPiece;
-
- //
- // This logical OR replaced with bitwise OR; the effect is
- // the same the the bitwise is marginally faster.
- //
- if (IS_EMPTY(p) | (OPPOSITE_COLORS(p, pKing)))
- {
- if (FALSE == IsAttacked(c, pos, FLIP(pos->uToMove)))
- {
- //
- // So we know the destination square is not under
- // attack right now... but that could be because
- // the present (pre-move) king position "blocks"
- // the attack. Detect this.
- //
- for (v = 0;
- v < rgCheckers.uCount;
- v++)
- {
- ASSERT(OPPOSITE_COLORS(pKing,
- rgCheckers.data[v].pPiece));
- if (!IS_PAWN(rgCheckers.data[v].pPiece) &&
- !IS_KNIGHT(rgCheckers.data[v].pPiece))
- {
- iIndex = (int)rgCheckers.data[v].cLoc -
- (int)cKing;
- iDelta = CHECK_DELTA_WITH_INDEX(iIndex);
- ASSERT(iDelta);
-
- iIndex = (int)rgCheckers.data[v].cLoc -
- (int)c;
- if (iDelta == CHECK_DELTA_WITH_INDEX(iIndex))
- {
- goto loop;
- }
- }
- }
- ASSERT(v == rgCheckers.uCount);
-
- //
- // If we get here the square is not under attack
- // and it does not contain our own piece. It's
- // either empty or contains an enemy piece.
- //
- ASSERT(!p || OPPOSITE_COLORS(pKing, p));
- _AddNormalMove(pStack, pos, cKing, c, p);
- uReturn += 0x00010000;
- }
- }
- }
- loop:
- ;
- }
-#endif
//
// N.B. If there is more than one piece checking the king then
@@ -4493,19 +2727,16 @@ Return value:
// checking piece.
//
c = rgCheckers.data[0].cLoc;
-#if defined(GENERATE_ESCAPES_BLOCK_BITBOARD)
//
// board_representation/MOVEGEN_MIGRATION.md section 6a Phase 2:
- // pos->cNonPawns[side][] mixes every non-pawn piece type together
- // (same reason as _GenerateAllMoves's own loop -- no contiguous
- // per-type range to slice), which is why the mailbox path above
- // needs JumpTable[p], an indirect call whose target changes almost
- // every iteration -- close to the worst case for a CPU's
- // indirect-branch predictor. pos->bbPieces[side][KNIGHT/BISHOP/
- // ROOK/QUEEN] sidesteps this exactly like _GenerateAllMovesBB did:
- // each piece type gets its own bit-extraction loop calling its
- // specific _SaveMe*BB function BY NAME, no function pointer
- // anywhere in this block.
+ // pos->cNonPawns[side][] mixed every non-pawn piece type together,
+ // which is why the old mailbox path needed JumpTable[p], an
+ // indirect call whose target changed almost every iteration --
+ // close to the worst case for a CPU's indirect-branch predictor.
+ // pos->bbPieces[side][KNIGHT/BISHOP/ROOK/QUEEN] sidesteps this
+ // exactly like _GenerateAllMovesBB does: each piece type gets its
+ // own bit-extraction loop calling its specific _SaveMe*BB function
+ // BY NAME, no function pointer anywhere in this block.
{
BITBOARD bbTargetMask;
BITBOARD bb;
@@ -4560,52 +2791,6 @@ Return value:
_SaveMeAllPawnMovesBB(pStack, pos, pos->uToMove, cKing, c,
bbTargetMask);
}
-#else
- {
- BITBOARD bbNonKingPieces = NON_KING_PIECES_BB(pos, pos->uToMove);
-
- while (IS_ON_BOARD(cDefender =
- CoorFromBitBoardRank8ToRank1(&bbNonKingPieces)))
- {
- p = pos->rgSquare[cDefender].pPiece;
- ASSERT(p && !IS_PAWN(p));
- ASSERT(GET_COLOR(p) == pos->uToMove);
-
- (JumpTable[p])(pStack, pos, cDefender, cKing, c);
- }
- }
-
- // Consider all pawns too
- if (pos->uToMove == BLACK)
- {
- BITBOARD bbPawnsToWalk = pos->bbPawns[BLACK];
-
- while (IS_ON_BOARD(cDefender =
- CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk)))
- {
-#ifdef DEBUG
- p = pos->rgSquare[cDefender].pPiece;
- ASSERT(p && IS_PAWN(p));
- ASSERT(GET_COLOR(p) == pos->uToMove);
-#endif
- SaveMeBlackPawn(pStack, pos, cDefender, cKing, c);
- }
- } else {
- BITBOARD bbPawnsToWalk = pos->bbPawns[WHITE];
-
- ASSERT(pos->uToMove == WHITE);
- while (IS_ON_BOARD(cDefender =
- CoorFromBitBoardRank8ToRank1(&bbPawnsToWalk)))
- {
-#ifdef DEBUG
- p = pos->rgSquare[cDefender].pPiece;
- ASSERT(p && IS_PAWN(p));
- ASSERT(GET_COLOR(p) == pos->uToMove);
-#endif
- SaveMeWhitePawn(pStack, pos, cDefender, cKing, c);
- }
- }
-#endif
return(uReturn);
}