diff options
| author | Scott Gasch <[email protected]> | 2026-10-25 10:39:58 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-10-25 10:39:58 -0700 |
| commit | f97b2710981e936cfb500ad0cdf1ceab233efad8 (patch) | |
| tree | 0004275d9dae8f7df4b5f86f3b750d80bc3f4a52 /src/generate.c | |
| parent | 3927a4cac6ec254a8e34a5e864300f75c3efc9f3 (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.c | 1853 |
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); } |
