summaryrefslogtreecommitdiff
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
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]>
-rw-r--r--src/GNUmakefile14
-rwxr-xr-xsrc/chess.h132
-rw-r--r--src/data.c6
-rw-r--r--src/generate.c1853
-rw-r--r--src/main.c6
-rw-r--r--src/movesup.c430
-rw-r--r--src/testgenerate.c406
-rw-r--r--src/testsee.c125
8 files changed, 48 insertions, 2924 deletions
diff --git a/src/GNUmakefile b/src/GNUmakefile
index 26c7b94..667495e 100644
--- a/src/GNUmakefile
+++ b/src/GNUmakefile
@@ -144,18 +144,18 @@ ifdef CROUTINES
PROFILE += -DCROUTINES
endif
-ifdef GETATTACKS_BITBOARD
- PROFILE += -DGETATTACKS_BITBOARD
-endif
-
-ifndef DISABLE_BITBOARD_MOVEGEN
- PROFILE += -DGENERATE_KNIGHT_BITBOARD -DGENERATE_KING_BITBOARD \
+# 2026-10-25: bitboard move generation is no longer optional -- this
+# project always uses it (the mailbox fallback predates magic
+# bitboards and is only still in the source tree as DEBUG/TEST
+# cross-check code, see generate.c/chess.h). GETATTACKS_BITBOARD
+# (checked nowhere in the source) and the DISABLE_BITBOARD_MOVEGEN
+# opt-out are both retired; these defines are simply always on.
+PROFILE += -DGENERATE_KNIGHT_BITBOARD -DGENERATE_KING_BITBOARD \
-DGENERATE_ROOK_BITBOARD -DGENERATE_BISHOP_BITBOARD \
-DGENERATE_QUEEN_BITBOARD -DGENERATE_PAWN_BITBOARD \
-DGENERATE_ESCAPES_KING_BITBOARD -DGENERATE_ESCAPES_BLOCK_BITBOARD \
-DEXPOSESCHECK_BITBOARD -DISATTACKED_BITBOARD \
-DUNBLOCKED_BITBOARD
-endif
ifdef EVERYTHING
PROFILE += -DEVAL_DUMP -DEVAL_TIME -DPERF_COUNTERS -DMP -DSMP -DTEST_NULL -DTREEDUMP -fbounds-checking -DMOVE_ORDERING_EVIDENCE_COLLECTION
diff --git a/src/chess.h b/src/chess.h
index 85b4bd7..2942f0a 100755
--- a/src/chess.h
+++ b/src/chess.h
@@ -950,17 +950,12 @@ MOVE_STACK;
#define GENERATE_DONT_SCORE (5)
// generate.c's _GenerateCapturesAndPromotions (GENERATE_CAPTURES_PROMS's
-// direct, non-filtered generator) exists only when every piece type is
-// on its bitboard generator -- see that function's block comment in
-// generate.c. Declared here, not in generate.c, so every translation
-// unit that needs to know whether it exists (main.c's test-registration
-// list, testgenerate.c's own tests) sees the same answer generate.c's
-// GenerateMoves dispatch does.
-#if defined(GENERATE_KNIGHT_BITBOARD) && defined(GENERATE_BISHOP_BITBOARD) && \
- defined(GENERATE_ROOK_BITBOARD) && defined(GENERATE_QUEEN_BITBOARD) && \
- defined(GENERATE_KING_BITBOARD) && defined(GENERATE_PAWN_BITBOARD)
+// direct, non-filtered generator) -- every piece type is always on its
+// bitboard generator now, so this is unconditional; kept as a named
+// macro (rather than inlined away) so main.c's test-registration list
+// and testgenerate.c's own tests keep one clearly-named thing to guard
+// on, matching generate.c's own #if there.
#define CAPTURES_PROMS_BITBOARD_PATH 1
-#endif
#ifdef TEST
#define GENERATE_ALL_MOVES_CHECK_OK (6)
@@ -3446,24 +3441,9 @@ DumpMove(ULONG u);
#define MOVE_TO_INDEX(mv) (((mv).uMove & 0xFFFF) + \
(0x10000 * GET_COLOR(mv.pMoved)))
-COOR
-FasterExposesCheck(POSITION *pos,
- COOR cRemove,
- COOR cLocation);
-
-COOR
-ExposesCheck(POSITION *pos,
- COOR cRemove,
- COOR cLocation);
-
-COOR
-ExposesCheckEp(POSITION *pos,
- COOR cTest,
- COOR cIgnore,
- COOR cBlock,
- COOR cKing);
-
-// board_representation/MOVEGEN_MIGRATION.md section 6b
+// board_representation/MOVEGEN_MIGRATION.md section 6b. The mailbox
+// originals (and the three-way #ifdef choice between them and these)
+// are retired -- these are simply the real implementations now.
COOR
FasterExposesCheckBB(POSITION *pos,
COOR cRemove,
@@ -3481,29 +3461,9 @@ ExposesCheckEpBB(POSITION *pos,
COOR cBlock,
COOR cKing);
-// Three-way choice matching GetAttacks's own pattern (MIGRATION.md
-// section 6): EXPOSESCHECK_BITBOARD defined -> the BB versions above;
-// else the mailbox versions declared right above this block.
-#if defined(EXPOSESCHECK_BITBOARD)
#define ExposesCheck ExposesCheckBB
#define FasterExposesCheck FasterExposesCheckBB
#define ExposesCheckEp ExposesCheckEpBB
-#endif
-
-// Real mailbox declarations first, unconditionally, so the plain names
-// "IsAttacked"/"InCheck" are always genuinely declared -- the #define
-// below only affects *later* call sites in files that include this
-// header after this point, matching GetAttacks's own three-way-choice
-// pattern (chess.h, `GetAttacks` block) exactly. Declaring these after
-// the #define instead (an earlier mistake here, caught by testsee.c's
-// TestIsAttackedBB needing to call the real mailbox function by name)
-// would macro-substitute this very declaration too, leaving the real
-// name never actually declared anywhere.
-FLAG
-IsAttacked(COOR cTest, POSITION *pos, ULONG uSide);
-
-FLAG
-InCheck(POSITION *pos, ULONG uSide);
FLAG
IsAttackedBB(COOR cTest, POSITION *pos, ULONG uSide);
@@ -3511,13 +3471,8 @@ IsAttackedBB(COOR cTest, POSITION *pos, ULONG uSide);
FLAG FORCEINLINE
InCheckBB(POSITION *pos, ULONG uSide);
-// ISATTACKED_BITBOARD defined -> the BB versions above resolve plain
-// "IsAttacked"/"InCheck" call sites from here on; else the mailbox
-// versions declared just above stay live.
-#if defined(ISATTACKED_BITBOARD)
#define IsAttacked IsAttackedBB
#define InCheck InCheckBB
-#endif
FLAG
SanityCheckMove(POSITION *pos, MOVE mv);
@@ -3675,8 +3630,6 @@ TestMakeUnmakeMove(void);
extern const int g_iQKDeltas[9];
extern const int g_iNDeltas[9];
-extern const int g_iBDeltas[5];
-extern const int g_iRDeltas[5];
void
GenerateMoves(SEARCHER_THREAD_CONTEXT *ctx,
@@ -3703,45 +3656,23 @@ _RookAttacksBB(COOR c, BITBOARD bbOccupied);
BITBOARD
_BishopAttacksBB(COOR c, BITBOARD bbOccupied);
-// generate.c's bitboard replacement for _FindUnblockedSquares, exposed
-// non-static so testgenerate.c's correctness/speed harness can call it
-// directly regardless of whether UNBLOCKED_BITBOARD is defined for
-// this build.
+// generate.c's bitboard build of pStack->bbUnblocked -- the mailbox
+// original (and its DEBUG-build cross-check against this) is retired.
void
_FindUnblockedSquaresBB(MOVE_STACK *pStack,
POSITION *pos);
-// The mailbox original, exposed non-static (compiled whenever
-// !UNBLOCKED_BITBOARD, or under DEBUG/TEST for the cross-check and
-// the test harness above) under the same build conditions generate.c
-// itself uses -- see generate.c.
-#if !defined(UNBLOCKED_BITBOARD) || defined(DEBUG) || defined(TEST)
-void
-_FindUnblockedSquares(MOVE_STACK *pStack,
- POSITION *pos);
-#endif
-
void
_GenerateRookBB(MOVE_STACK *pStack,
POSITION *pos,
COOR cRook);
void
-GenerateRook(MOVE_STACK *pStack,
- POSITION *pos,
- COOR cRook);
-
-void
_GenerateBishopBB(MOVE_STACK *pStack,
POSITION *pos,
COOR cBishop);
void
-GenerateBishop(MOVE_STACK *pStack,
- POSITION *pos,
- COOR cBishop);
-
-void
_GenerateQueenBB(MOVE_STACK *pStack,
POSITION *pos,
COOR cQueen);
@@ -3802,40 +3733,15 @@ _SaveMeAllPawnMovesBB(MOVE_STACK *pStack,
BITBOARD bbTargetMask);
void
-GenerateQueen(MOVE_STACK *pStack,
- POSITION *pos,
- COOR cQueen);
-
-void
_GenerateKnightBB(MOVE_STACK *pStack,
POSITION *pos,
COOR cKnight);
void
-GenerateKnight(MOVE_STACK *pStack,
- POSITION *pos,
- COOR cKnight);
-
-void
-GenerateWhiteKnight(MOVE_STACK *pStack,
- POSITION *pos,
- COOR cKnight);
-
-void
_GenerateKingBB(MOVE_STACK *pStack,
POSITION *pos,
COOR cKing);
-void
-GenerateBlackKing(MOVE_STACK *pStack,
- POSITION *pos,
- COOR cKing);
-
-void
-GenerateWhiteKing(MOVE_STACK *pStack,
- POSITION *pos,
- COOR cKing);
-
FLAG FORCEINLINE
WouldGiveCheck(IN SEARCHER_THREAD_CONTEXT *ctx,
IN MOVE mv);
@@ -3860,21 +3766,6 @@ void
TestNnueAccumulator(void);
void
-TestGenerateKnightSpeed(void);
-
-void
-TestGenerateKingSpeed(void);
-
-void
-TestGenerateRookSpeed(void);
-
-void
-TestGenerateBishopSpeed(void);
-
-void
-TestGenerateQueenSpeed(void);
-
-void
TestGenerateAllMovesSpeed(void);
void
@@ -4903,9 +4794,6 @@ void
TestGetAttacks(void);
void
-TestIsAttackedBB(void);
-
-void
TestSeeFastSign(void);
void
diff --git a/src/data.c b/src/data.c
index c12a9be..8fc72cb 100644
--- a/src/data.c
+++ b/src/data.c
@@ -695,6 +695,12 @@ Return value:
//
BITBOARD g_KnightAttacksBB[128];
+// Knight move deltas used only by InitializeKnightAttackTables below --
+// the mailbox knight generators that used to be its other consumers
+// are retired (see generate.c's MOVEGEN_MIGRATION.md history).
+const INT g_iNDeltas[] = {
+ -33, -31, -18, -14, +14, +18, +31, +33, 0 };
+
void
InitializeKnightAttackTables(void)
/**
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);
}
diff --git a/src/main.c b/src/main.c
index 0b63bec..2f5428e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -733,18 +733,12 @@ Return value:
TestSan();
TestIcs();
TestGetAttacks();
- TestIsAttackedBB();
TestSeeFastSign();
TestSEENoDefenderFastPath();
TestWhoAttacksSquareMagic();
TestMoveGenerator();
TestLegalMoveGenerator();
TestNnueAccumulator();
- TestGenerateKnightSpeed();
- TestGenerateKingSpeed();
- TestGenerateRookSpeed();
- TestGenerateBishopSpeed();
- TestGenerateQueenSpeed();
TestGenerateAllMovesSpeed();
#if defined(CAPTURES_PROMS_BITBOARD_PATH)
TestCapturesAndPromotionsGenerator();
diff --git a/src/movesup.c b/src/movesup.c
index 7266177..ac12f10 100644
--- a/src/movesup.c
+++ b/src/movesup.c
@@ -35,33 +35,6 @@ Revision History:
#define SKIP_SELECT_AFTER_N_MOVES (6)
#endif
-// Unlike GetAttacks (a real asm symbol in a different file, so
-// chess.h's macro-swap never touches its own definition),
-// ExposesCheck/FasterExposesCheck/ExposesCheckEp's mailbox
-// implementations live in *this* file, right below their BB
-// counterparts -- chess.h's #define would otherwise rename these
-// functions' own definitions too, colliding with the real
-// ExposesCheckBB/etc. symbols. #undef restores the real names for
-// this file's own definitions; every other translation unit that
-// includes chess.h still sees the macro-renamed calls.
-#if defined(EXPOSESCHECK_BITBOARD)
-#undef ExposesCheck
-#undef FasterExposesCheck
-#undef ExposesCheckEp
-#endif
-#if defined(ISATTACKED_BITBOARD)
-#undef IsAttacked
-#undef InCheck
-#endif
-
-// See eval.c's identical comment: routes this file's (dead-under-
-// ISATTACKED_BITBOARD) mailbox IsAttacked's bitboard-scan loop to the
-// inlined FastCoorFromBitBoardRank8ToRank1 (chess.h) instead of the
-// real out-of-line extern call.
-#ifndef CROUTINES
-#define CoorFromBitBoardRank8ToRank1 FastCoorFromBitBoardRank8ToRank1
-#endif
-
// board_representation/MOVEGEN_MIGRATION.md section 6b: bitboard
// equivalents of ExposesCheck/FasterExposesCheck/ExposesCheckEp.
// ExposesCheck is called from MakeMove (move.c) on essentially every
@@ -360,265 +333,6 @@ Return value:
return _ValidateExposedBlockerBB(pos, cBlocker, cKing);
}
-COOR
-FasterExposesCheck(POSITION *pos,
- COOR cRemove,
- COOR cLocation)
-/**
-
-Routine description:
-
- This is just like ExposesCheck (see below) but it does not bother
- checking whether its possible to expose check with the piece at
- cRemove because we already know it is.
-
-Parameters:
-
- POSITION *pos,
- COOR cRemove,
- COOR cLocation
-
-Return value:
-
- COOR
-
-**/
-{
- register int iDelta;
- register COOR cBlockIndex;
- int iIndex;
- PIECE xPiece;
- ULONG uColor = GET_COLOR(pos->rgSquare[cLocation].pPiece);
-
- ASSERT(IS_KING(pos->rgSquare[cLocation].pPiece));
- iIndex = (int)cLocation - (int)cRemove;
-
- ASSERT(IS_ON_BOARD(cRemove));
- ASSERT(IS_ON_BOARD(cLocation));
- ASSERT(!IS_EMPTY(pos->rgSquare[cLocation].pPiece));
- ASSERT(0 != (CHECK_VECTOR_WITH_INDEX(iIndex, BLACK) & (1 << QUEEN)));
-
- iDelta = CHECK_DELTA_WITH_INDEX(iIndex);
- ASSERT(iDelta != 0);
-
- for (cBlockIndex = cRemove + iDelta;
- IS_ON_BOARD(cBlockIndex);
- cBlockIndex += iDelta)
- {
- ASSERT(cBlockIndex != cRemove);
- ASSERT(cBlockIndex != cLocation);
- xPiece = pos->rgSquare[cBlockIndex].pPiece;
- if (!IS_EMPTY(xPiece))
- {
- //
- // Is it an enemy?
- //
- if (OPPOSITE_COLORS(xPiece, uColor))
- {
- //
- // Does it move the right way to attack?
- //
- iIndex = (int)cBlockIndex - (int)cLocation;
- if (0 != (CHECK_VECTOR_WITH_INDEX(iIndex, WHITE) &
- (1 << (PIECE_TYPE(xPiece)))))
- {
- return(cBlockIndex);
- }
- }
-
- //
- // Either we found another friendly piece or an enemy piece
- // that was unable to reach us. Either way we are safe.
- //
- return(ILLEGAL_COOR);
- }
- }
-
- //
- // We fell off the board without seeing another piece.
- //
- return(ILLEGAL_COOR);
-}
-
-
-
-COOR
-ExposesCheck(POSITION *pos,
- COOR cRemove,
- COOR cLocation)
-/**
-
-Routine description:
-
- Test if removing the piece at cRemove exposes the piece at
- cLocation to attack by the other side. Note: there must be a
- piece at cLocation because the color of that piece is used to
- determine what side is "checking" and what side is "being
- checked".
-
-Parameters:
-
- POSITION *pos : the board
- COOR cRemove : the square where a piece hypothetically removed from
- COOR cLocation : the square where the attackee is sitting
-
-Return value:
-
- COOR : the location of an attacker piece or 0x88 (!IS_ON_BOARD) if
- the removal of cRemove does not expose check.
-
-**/
-{
- register int iDelta;
- register COOR cBlockIndex;
- int iIndex;
- PIECE xPiece;
-
- ASSERT(IS_ON_BOARD(cRemove));
- ASSERT(IS_ON_BOARD(cLocation));
- ASSERT(!IS_EMPTY(pos->rgSquare[cLocation].pPiece));
-
- iIndex = (int)cLocation - (int)cRemove;
-
- //
- // If there is no way for a queen sitting at the square removed to
- // reach the square we are testing (i.e. the two squares are not
- // on the same rank, file, or diagonal) then there is no way
- // removing it can expose cLocation to check.
- //
- if (0 == (CHECK_VECTOR_WITH_INDEX(iIndex, BLACK) & (1 << QUEEN)))
- {
- return(ILLEGAL_COOR);
- }
- iDelta = CHECK_DELTA_WITH_INDEX(iIndex);
- for (cBlockIndex = cLocation + iDelta;
- IS_ON_BOARD(cBlockIndex);
- cBlockIndex += iDelta)
- {
- if (cBlockIndex == cRemove)
- {
- continue;
- }
- xPiece = pos->rgSquare[cBlockIndex].pPiece;
- if (!IS_EMPTY(xPiece))
- {
- //
- // Is it an enemy?
- //
- if (OPPOSITE_COLORS(xPiece, pos->rgSquare[cLocation].pPiece))
- {
- //
- // Does it move the right way to attack?
- //
- iIndex = (int)cBlockIndex - (int)cLocation;
- if (0 != (CHECK_VECTOR_WITH_INDEX(iIndex, GET_COLOR(xPiece)) &
- (1 << (PIECE_TYPE(xPiece)))))
- {
- return(cBlockIndex);
- }
- }
-
- //
- // Either we found another friendly piece or an enemy piece
- // that was unable to reach us. Either way we are safe.
- //
- return(ILLEGAL_COOR);
- }
- }
-
- //
- // We fell off the board without seeing another piece.
- //
- return(ILLEGAL_COOR);
-}
-
-
-COOR
-ExposesCheckEp(POSITION *pos,
- COOR cTest,
- COOR cIgnore,
- COOR cBlock,
- COOR cKing)
-/**
-
-Routine description:
-
-Parameters:
-
- POSITION *pos,
- COOR cTest : The square from whence the attack comes
- COOR cIgnore : Ignore this square, the pawn moved
- COOR cBlock : This square is where the pawn moved to and now blocks
- COOR cKing : The square under attack
-
-Return value:
-
- COOR
-
-**/
-{
- register int iDelta;
- register COOR cBlockIndex;
- int iIndex;
- PIECE xPiece;
-
- ASSERT(IS_ON_BOARD(cTest));
- ASSERT(IS_ON_BOARD(cIgnore));
- ASSERT(IS_ON_BOARD(cBlock));
- ASSERT(IS_ON_BOARD(cKing));
-
- iIndex = (int)cKing - (int)cTest;
-
- //
- // If there is no way for a queen sitting at the square removed to
- // reach the square we are testing (i.e. the two squares are not
- // on the same rank, file, or diagonal) then no problemo.
- //
- if (0 == (CHECK_VECTOR_WITH_INDEX(iIndex, BLACK) & (1 << QUEEN)))
- {
- return(ILLEGAL_COOR);
- }
-
- iDelta = CHECK_DELTA_WITH_INDEX(iIndex);
- for (cBlockIndex = cKing + iDelta;
- IS_ON_BOARD(cBlockIndex);
- cBlockIndex += iDelta)
- {
- if (cBlockIndex == cTest) continue;
- if (cBlockIndex == cIgnore) continue;
- if (cBlockIndex == cBlock) return(ILLEGAL_COOR);
-
- xPiece = pos->rgSquare[cBlockIndex].pPiece;
- if (!IS_EMPTY(xPiece))
- {
- if (OPPOSITE_COLORS(xPiece, pos->rgSquare[cKing].pPiece))
- {
- //
- // Does it move the right way to attack?
- //
- iIndex = (int)cBlockIndex - (int)cKing;
- if (0 != (CHECK_VECTOR_WITH_INDEX(iIndex, GET_COLOR(xPiece)) &
- (1 << (PIECE_TYPE(xPiece)))))
- {
- return(cBlockIndex);
- }
- }
-
- //
- // Either we found another friendly piece or an enemy piece
- // that was unable to reach us. Either way we are safe.
- //
- return(ILLEGAL_COOR);
- }
- }
-
- //
- // We fell off the board without seeing another piece.
- //
- return(ILLEGAL_COOR);
-}
-
-
//
// board_representation/MOVEGEN_MIGRATION.md section 6b: bitboard
// equivalent of IsAttacked/InCheck. IsAttacked's own direct callers
@@ -697,150 +411,6 @@ Return value:
return IsAttackedBB(cKingLoc, pos, FLIP(uSide));
}
-FLAG
-IsAttacked(COOR cTest, POSITION *pos, ULONG uSide)
-/**
-
-Routine description:
-
- Determine whether the square cTest is attacked by the side uSide.
-
-Parameters:
-
- COOR cTest : the square we want to determine if is under attack
- POSITION *pos : the board
- ULONG uSide : the side we want to see if is attacking cTest
-
-Return value:
-
- FLAG : TRUE if uSide attacks cTest, FALSE otherwise
-
-**/
-{
- PIECE pPiece;
- COOR cLocation;
- COOR cBlockIndex;
- int iIndex;
- int iDelta;
- BITBOARD bbNonPawns;
- static int iPawnLoc[2] = { -17, +15 };
- static PIECE pPawn[2] = { BLACK_PAWN, WHITE_PAWN };
-
- ASSERT(IS_ON_BOARD(cTest));
- ASSERT(IS_VALID_COLOR(uSide));
-
- //
- // Dead in this build (ISATTACKED_BITBOARD routes every caller to
- // IsAttackedBB instead -- see this file's #undef block above), so
- // iteration order here has no measured perf consequence; combining
- // king + non-king pieces into one bitboard scan (instead of the
- // old cNonPawns[uSide][] list, which deliberately visited the king
- // -- always list slot 0 -- last) is simplest and just as correct.
- //
- bbNonPawns = NON_KING_PIECES_BB(pos, uSide) | COOR_TO_BB(KingPosition(pos, uSide));
- while (IS_ON_BOARD(cLocation = CoorFromBitBoardRank8ToRank1(&bbNonPawns)))
- {
- ASSERT(IS_ON_BOARD(cLocation));
- pPiece = pos->rgSquare[cLocation].pPiece;
- ASSERT(!IS_EMPTY(pPiece));
- ASSERT(!IS_PAWN(pPiece));
- ASSERT(GET_COLOR(pPiece) == uSide);
- iIndex = (int)cLocation - (int)cTest;
-
- if (!(CHECK_VECTOR_WITH_INDEX(iIndex, uSide) &
- (1 << (PIECE_TYPE(pPiece)))))
- {
- continue;
- }
-
- //
- // These pieces do not slide, we don't need to look for
- // blockers. If they can get there then there is nothing
- // we can do to stop them.
- //
- if (IS_KNIGHT(pPiece) || IS_KING(pPiece))
- {
- return(TRUE);
- }
-
- //
- // Well, here we have a sliding piece (bishop, rook or queen)
- // that is on the same line (file, rank or diagonal) as the
- // cTest. We now have to see if the attacker (pPiece) is
- // blocked or is free to attack cTest.
- //
- iDelta = NEG_DELTA_WITH_INDEX(iIndex);
- for (cBlockIndex = cTest + iDelta;
- cBlockIndex != cLocation;
- cBlockIndex += iDelta)
- {
- if (!IS_EMPTY(pos->rgSquare[cBlockIndex].pPiece))
- {
- break;
- }
- }
- if (cBlockIndex == cLocation)
- {
- return(TRUE);
- }
- }
-
- //
- // Check the locations a pawn could attack cTest from.
- //
- cLocation = cTest + iPawnLoc[uSide];
- if (IS_ON_BOARD(cLocation) &&
- (pos->rgSquare[cLocation].pPiece == pPawn[uSide]))
- {
- return(TRUE);
- }
-
- cLocation += 2;
- if (IS_ON_BOARD(cLocation) &&
- (pos->rgSquare[cLocation].pPiece == pPawn[uSide]))
- {
- return(TRUE);
- }
- return(FALSE);
-}
-
-
-FLAG
-InCheck(POSITION *pos, ULONG uSide)
-/**
-
-Routine description:
-
- Determine if a side is in check or not.
-
-Parameters:
-
- POSITION *pos : the board
- ULONG uSide : the side we want to determine if is in check
-
-Return value:
-
- FLAG : TRUE if side is in check, FALSE otherwise.
-
-**/
-{
- COOR cKingLoc;
-#ifdef DEBUG
- PIECE pKing;
-#endif
-
- ASSERT(IS_VALID_COLOR(uSide));
-
- cKingLoc = KingPosition(pos, uSide);
-#ifdef DEBUG
- pKing = pos->rgSquare[cKingLoc].pPiece;
- ASSERT(IS_KING(pKing));
- ASSERT(IS_VALID_COLOR(uSide));
- ASSERT(GET_COLOR(pKing) == uSide);
-#endif
- return(IsAttacked(cKingLoc, pos, FLIP(uSide)));
-}
-
static FLAG
_SanityCheckPawnMove(POSITION *pos, MOVE mv)
diff --git a/src/testgenerate.c b/src/testgenerate.c
index 83c187d..30f26e9 100644
--- a/src/testgenerate.c
+++ b/src/testgenerate.c
@@ -245,384 +245,10 @@ TestLegalMoveGenerator(void)
SystemFreeMemory(ctx);
}
-//
-// board_representation/MOVEGEN_MIGRATION.md section 5's isolated
-// cycles/call microbenchmark for the knight generator -- modeled
-// directly on testsee.c's TestGetAttacks speed block (interleaved
-// call-by-call across opening/middlegame/endgame positions, to cancel
-// shared-box noise). Correctness for this piece type is already
-// covered by TestMoveGenerator's perft counts (with
-// GENERATE_KNIGHT_BITBOARD defined) -- this only answers "is it
-// faster," the section 5 gate before a piece type's toggle is
-// considered for default-on.
-//
-void
-TestGenerateKnightSpeed(void)
-{
- static const char *rgszFen[3] =
- {
- "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
- "r1bq1rk1/pp2bppp/2n1pn2/2pp4/3P4/2NBPN2/PP3PPP/R1BQ1RK1 w - - 0 1",
- "8/5k2/8/3KN3/8/8/8/8 w - - 0 1",
- };
- static const char *rgszLabel[3] =
- {
- "opening ", "middlegame", "endgame ",
- };
- static const COOR rgcKnight[3] = { B1, C3, E5 };
- POSITION posBench;
- SEARCHER_THREAD_CONTEXT *ctx;
- UINT64 u64MailboxTotal, u64BBTotal, u64Start;
- ULONG uIter, u;
- ULONG uPly;
- const ULONG uCallsPerPosition = 200000;
-
- Trace("Benchmarking knight move generation: mailbox vs "
- "_GenerateKnightBB (interleaved, %lu calls/position)...\n",
- uCallsPerPosition);
-
- ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
- ASSERT(ctx);
- uPly = ctx->uPly;
-
- for (u = 0; u < 3; u++)
- {
- FenToPosition(&posBench, (char *)rgszFen[u]);
- InitializeSearcherContext(&posBench, ctx);
- ASSERT(IS_KNIGHT(posBench.rgSquare[rgcKnight[u]].pPiece));
- ASSERT(GET_COLOR(posBench.rgSquare[rgcKnight[u]].pPiece) ==
- posBench.uToMove);
-
- // _GenerateKnightBB relies on this being set by its caller
- // (normally _GenerateAllMoves, once per node) -- see
- // MOVE_STACK's bbFriendlyOccupied field comment in chess.h.
- // Computed once per benchmark position, not per call, matching
- // how the real call site amortizes it.
- ctx->sMoveStack.bbFriendlyOccupied =
- _BuildFriendlySideBB(&posBench, posBench.uToMove);
-
- u64MailboxTotal = 0;
- u64BBTotal = 0;
- for (uIter = 0; uIter < uCallsPerPosition; uIter++)
- {
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- GenerateWhiteKnight(&ctx->sMoveStack, &posBench, rgcKnight[u]);
- u64MailboxTotal += (SystemReadTimeStampCounter() - u64Start);
-
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- _GenerateKnightBB(&ctx->sMoveStack, &posBench, rgcKnight[u]);
- u64BBTotal += (SystemReadTimeStampCounter() - u64Start);
- }
- printf(" %s: mailbox %" COMPILER_LONGLONG_UNSIGNED_FORMAT
- " cycles/call, _GenerateKnightBB %"
- COMPILER_LONGLONG_UNSIGNED_FORMAT " cycles/call "
- "(BB is %.2fx mailbox)\n",
- rgszLabel[u],
- u64MailboxTotal / uCallsPerPosition,
- u64BBTotal / uCallsPerPosition,
- (double)u64BBTotal / (double)u64MailboxTotal);
- }
- SystemFreeMemory(ctx);
-}
-
-//
-// Same shape as TestGenerateKnightSpeed, for the king. Opening position
-// has castling rights but blocked by intervening pieces (exercises the
-// emptiness-check branch's cost without ever actually reaching
-// _AddCastle); middlegame is already castled (no rights, cheapest
-// castling-tail exit); endgame is a bare king on an open board (no
-// rights either, but the most normal-move destinations to enumerate).
-//
-void
-TestGenerateKingSpeed(void)
-{
- static const char *rgszFen[3] =
- {
- "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
- "r1bq1rk1/pp2bppp/2n1pn2/2pp4/3P4/2NBPN2/PP3PPP/R1BQ1RK1 w - - 0 1",
- "8/5k2/8/4K3/8/8/8/8 w - - 0 1",
- };
- static const char *rgszLabel[3] =
- {
- "opening ", "middlegame", "endgame ",
- };
- static const COOR rgcKing[3] = { E1, G1, E5 };
- POSITION posBench;
- SEARCHER_THREAD_CONTEXT *ctx;
- UINT64 u64MailboxTotal, u64BBTotal, u64Start;
- ULONG uIter, u;
- ULONG uPly;
- const ULONG uCallsPerPosition = 200000;
-
- Trace("Benchmarking king move generation: mailbox vs "
- "_GenerateKingBB (interleaved, %lu calls/position)...\n",
- uCallsPerPosition);
-
- ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
- ASSERT(ctx);
- uPly = ctx->uPly;
-
- for (u = 0; u < 3; u++)
- {
- FenToPosition(&posBench, (char *)rgszFen[u]);
- InitializeSearcherContext(&posBench, ctx);
- ASSERT(IS_KING(posBench.rgSquare[rgcKing[u]].pPiece));
- ASSERT(GET_COLOR(posBench.rgSquare[rgcKing[u]].pPiece) ==
- posBench.uToMove);
-
- ctx->sMoveStack.bbFriendlyOccupied =
- _BuildFriendlySideBB(&posBench, posBench.uToMove);
-
- u64MailboxTotal = 0;
- u64BBTotal = 0;
- for (uIter = 0; uIter < uCallsPerPosition; uIter++)
- {
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- GenerateWhiteKing(&ctx->sMoveStack, &posBench, rgcKing[u]);
- u64MailboxTotal += (SystemReadTimeStampCounter() - u64Start);
-
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- _GenerateKingBB(&ctx->sMoveStack, &posBench, rgcKing[u]);
- u64BBTotal += (SystemReadTimeStampCounter() - u64Start);
- }
- printf(" %s: mailbox %" COMPILER_LONGLONG_UNSIGNED_FORMAT
- " cycles/call, _GenerateKingBB %"
- COMPILER_LONGLONG_UNSIGNED_FORMAT " cycles/call "
- "(BB is %.2fx mailbox)\n",
- rgszLabel[u],
- u64MailboxTotal / uCallsPerPosition,
- u64BBTotal / uCallsPerPosition,
- (double)u64BBTotal / (double)u64MailboxTotal);
- }
- SystemFreeMemory(ctx);
-}
-
-//
-// Same shape as TestGenerateKnightSpeed/TestGenerateKingSpeed, for the
-// rook -- but unlike those two, this piece type is expected to
-// actually win: rook a1 is fully blocked in the opening (0
-// destinations, cheapest case either way), partially open in the
-// middlegame, and nearly fully open in the endgame (up to 13
-// destinations along an empty file/rank) -- exactly the case a
-// 4-direction ray walk pays for and a magic lookup doesn't.
-//
-void
-TestGenerateRookSpeed(void)
-{
- static const char *rgszFen[3] =
- {
- "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
- "r1bq1rk1/pp2bppp/2n1pn2/2pp4/3P4/2NBPN2/PP3PPP/R1BQ1RK1 w - - 0 1",
- "8/5k2/8/3K4/8/8/8/R7 w - - 0 1",
- };
- static const char *rgszLabel[3] =
- {
- "opening ", "middlegame", "endgame ",
- };
- static const COOR rgcRook[3] = { A1, A1, A1 };
- POSITION posBench;
- SEARCHER_THREAD_CONTEXT *ctx;
- UINT64 u64MailboxTotal, u64BBTotal, u64Start;
- ULONG uIter, u;
- ULONG uPly;
- const ULONG uCallsPerPosition = 200000;
-
- Trace("Benchmarking rook move generation: mailbox vs "
- "_GenerateRookBB (interleaved, %lu calls/position)...\n",
- uCallsPerPosition);
-
- ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
- ASSERT(ctx);
- uPly = ctx->uPly;
-
- for (u = 0; u < 3; u++)
- {
- FenToPosition(&posBench, (char *)rgszFen[u]);
- InitializeSearcherContext(&posBench, ctx);
- ASSERT(IS_ROOK(posBench.rgSquare[rgcRook[u]].pPiece));
- ASSERT(GET_COLOR(posBench.rgSquare[rgcRook[u]].pPiece) ==
- posBench.uToMove);
-
- ctx->sMoveStack.bbFriendlyOccupied =
- _BuildFriendlySideBB(&posBench, posBench.uToMove);
- ctx->sMoveStack.bbOccupied = _BuildFullOccupiedBB(&posBench);
-
- u64MailboxTotal = 0;
- u64BBTotal = 0;
- for (uIter = 0; uIter < uCallsPerPosition; uIter++)
- {
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- GenerateRook(&ctx->sMoveStack, &posBench, rgcRook[u]);
- u64MailboxTotal += (SystemReadTimeStampCounter() - u64Start);
-
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- _GenerateRookBB(&ctx->sMoveStack, &posBench, rgcRook[u]);
- u64BBTotal += (SystemReadTimeStampCounter() - u64Start);
- }
- printf(" %s: mailbox %" COMPILER_LONGLONG_UNSIGNED_FORMAT
- " cycles/call, _GenerateRookBB %"
- COMPILER_LONGLONG_UNSIGNED_FORMAT " cycles/call "
- "(BB is %.2fx mailbox)\n",
- rgszLabel[u],
- u64MailboxTotal / uCallsPerPosition,
- u64BBTotal / uCallsPerPosition,
- (double)u64BBTotal / (double)u64MailboxTotal);
- }
- SystemFreeMemory(ctx);
-}
-
-//
-// Same shape as TestGenerateRookSpeed, for the bishop -- expect the
-// same parity result (see MOVEGEN_MIGRATION.md section 3's rook
-// entry for why), not a different outcome, since the underlying
-// reason applies identically to diagonals.
-//
-void
-TestGenerateBishopSpeed(void)
-{
- static const char *rgszFen[3] =
- {
- "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
- "r1bq1rk1/pp2bppp/2n1pn2/2pp4/3P4/2NBPN2/PP3PPP/R1BQ1RK1 w - - 0 1",
- "8/5k2/8/3K4/8/8/8/B7 w - - 0 1",
- };
- static const char *rgszLabel[3] =
- {
- "opening ", "middlegame", "endgame ",
- };
- static const COOR rgcBishop[3] = { C1, D3, A1 };
- POSITION posBench;
- SEARCHER_THREAD_CONTEXT *ctx;
- UINT64 u64MailboxTotal, u64BBTotal, u64Start;
- ULONG uIter, u;
- ULONG uPly;
- const ULONG uCallsPerPosition = 200000;
-
- Trace("Benchmarking bishop move generation: mailbox vs "
- "_GenerateBishopBB (interleaved, %lu calls/position)...\n",
- uCallsPerPosition);
-
- ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
- ASSERT(ctx);
- uPly = ctx->uPly;
-
- for (u = 0; u < 3; u++)
- {
- FenToPosition(&posBench, (char *)rgszFen[u]);
- InitializeSearcherContext(&posBench, ctx);
- ASSERT(IS_BISHOP(posBench.rgSquare[rgcBishop[u]].pPiece));
- ASSERT(GET_COLOR(posBench.rgSquare[rgcBishop[u]].pPiece) ==
- posBench.uToMove);
-
- ctx->sMoveStack.bbFriendlyOccupied =
- _BuildFriendlySideBB(&posBench, posBench.uToMove);
- ctx->sMoveStack.bbOccupied = _BuildFullOccupiedBB(&posBench);
-
- u64MailboxTotal = 0;
- u64BBTotal = 0;
- for (uIter = 0; uIter < uCallsPerPosition; uIter++)
- {
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- GenerateBishop(&ctx->sMoveStack, &posBench, rgcBishop[u]);
- u64MailboxTotal += (SystemReadTimeStampCounter() - u64Start);
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- _GenerateBishopBB(&ctx->sMoveStack, &posBench, rgcBishop[u]);
- u64BBTotal += (SystemReadTimeStampCounter() - u64Start);
- }
- printf(" %s: mailbox %" COMPILER_LONGLONG_UNSIGNED_FORMAT
- " cycles/call, _GenerateBishopBB %"
- COMPILER_LONGLONG_UNSIGNED_FORMAT " cycles/call "
- "(BB is %.2fx mailbox)\n",
- rgszLabel[u],
- u64MailboxTotal / uCallsPerPosition,
- u64BBTotal / uCallsPerPosition,
- (double)u64BBTotal / (double)u64MailboxTotal);
- }
- SystemFreeMemory(ctx);
-}
-
-//
-// Same shape as TestGenerateRookSpeed/TestGenerateBishopSpeed, for the
-// queen -- expect the same parity-or-slightly-worse result, plus an
-// extra fixed cost this time (two magic lookups instead of one) --
-// see MOVEGEN_MIGRATION.md section 3's rook entry for why a win was
-// never really on the table for this piece type either.
-//
-void
-TestGenerateQueenSpeed(void)
-{
- static const char *rgszFen[3] =
- {
- "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
- "r1b2rk1/pp2bppp/2n1pn2/2pp4/3P4/1QNBPN2/PP3PPP/R3KB1R w - - 0 1",
- "8/5k2/8/3K4/8/8/8/Q7 w - - 0 1",
- };
- static const char *rgszLabel[3] =
- {
- "opening ", "middlegame", "endgame ",
- };
- static const COOR rgcQueen[3] = { D1, B3, A1 };
- POSITION posBench;
- SEARCHER_THREAD_CONTEXT *ctx;
- UINT64 u64MailboxTotal, u64BBTotal, u64Start;
- ULONG uIter, u;
- ULONG uPly;
- const ULONG uCallsPerPosition = 200000;
-
- Trace("Benchmarking queen move generation: mailbox vs "
- "_GenerateQueenBB (interleaved, %lu calls/position)...\n",
- uCallsPerPosition);
-
- ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
- ASSERT(ctx);
- uPly = ctx->uPly;
- for (u = 0; u < 3; u++)
- {
- FenToPosition(&posBench, (char *)rgszFen[u]);
- InitializeSearcherContext(&posBench, ctx);
- ASSERT(IS_QUEEN(posBench.rgSquare[rgcQueen[u]].pPiece));
- ASSERT(GET_COLOR(posBench.rgSquare[rgcQueen[u]].pPiece) ==
- posBench.uToMove);
- ctx->sMoveStack.bbFriendlyOccupied =
- _BuildFriendlySideBB(&posBench, posBench.uToMove);
- ctx->sMoveStack.bbOccupied = _BuildFullOccupiedBB(&posBench);
-
- u64MailboxTotal = 0;
- u64BBTotal = 0;
- for (uIter = 0; uIter < uCallsPerPosition; uIter++)
- {
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- GenerateQueen(&ctx->sMoveStack, &posBench, rgcQueen[u]);
- u64MailboxTotal += (SystemReadTimeStampCounter() - u64Start);
- ctx->sMoveStack.uEnd[uPly] = ctx->sMoveStack.uBegin[uPly];
- u64Start = SystemReadTimeStampCounter();
- _GenerateQueenBB(&ctx->sMoveStack, &posBench, rgcQueen[u]);
- u64BBTotal += (SystemReadTimeStampCounter() - u64Start);
- }
- printf(" %s: mailbox %" COMPILER_LONGLONG_UNSIGNED_FORMAT
- " cycles/call, _GenerateQueenBB %"
- COMPILER_LONGLONG_UNSIGNED_FORMAT " cycles/call "
- "(BB is %.2fx mailbox)\n",
- rgszLabel[u],
- u64MailboxTotal / uCallsPerPosition,
- u64BBTotal / uCallsPerPosition,
- (double)u64BBTotal / (double)u64MailboxTotal);
- }
- SystemFreeMemory(ctx);
-}
//
// Whole-node dispatch benchmark: _GenerateAllMoves (mailbox
@@ -700,21 +326,16 @@ TestGenerateAllMovesSpeed(void)
//
// board_representation/MOVEGEN_MIGRATION.md's never-started
-// _FindUnblockedSquares/WouldGiveCheck candidate. Unlike every other
+// _FindUnblockedSquaresBB/WouldGiveCheck candidate. Unlike every other
// benchmark in this file, this does NOT measure the generator call in
-// isolation: _FindUnblockedSquares writes ~20 square entries that may
+// isolation: _FindUnblockedSquaresBB writes ~20 square entries that may
// never be read, and WouldGiveCheck reads only 1-3 of them per move,
// so a bitboard version that looks like a big win building the table
// can give some of it back at query time. The real per-node cost is
-// the pair -- one _FindUnblockedSquares(BB) call followed by
+// the pair -- one _FindUnblockedSquaresBB call followed by
// WouldGiveCheck over every move actually generated at that node --
// so that's what gets timed here, same interleaved-call methodology
-// as the rest of this file. WouldGiveCheck's own body is selected at
-// compile time by UNBLOCKED_BITBOARD (SQUARE_IS_UNBLOCKED/
-// DIR_FROM_SQ_TO_KING), so unlike TestGenerateAllMovesSpeed this can't
-// compare both implementations by name in one binary -- run this test
-// in two builds (with and without -DUNBLOCKED_BITBOARD) and compare
-// the printed cycles/pair across them.
+// as the rest of this file.
//
void
TestFindUnblockedSquaresSpeed(void)
@@ -737,15 +358,8 @@ TestFindUnblockedSquaresSpeed(void)
MOVE_STACK *pStack;
const ULONG uCallsPerPosition = 50000;
- Trace("Benchmarking _FindUnblockedSquares%s + WouldGiveCheck over "
- "a generated move list (%lu calls/position) -- compare this "
- "build's numbers against a build with the opposite "
- "-DUNBLOCKED_BITBOARD setting...\n",
-#ifdef UNBLOCKED_BITBOARD
- "BB",
-#else
- " (mailbox)",
-#endif
+ Trace("Benchmarking _FindUnblockedSquaresBB + WouldGiveCheck over "
+ "a generated move list (%lu calls/position)...\n",
uCallsPerPosition);
ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
@@ -763,11 +377,7 @@ TestFindUnblockedSquaresSpeed(void)
// what's under test here, not generation itself.
pStack->uEnd[uPly] = pStack->uBegin[uPly];
pStack->sGenFlags[uPly].uAllGenFlags = 0;
-#ifdef UNBLOCKED_BITBOARD
_FindUnblockedSquaresBB(pStack, &posBench);
-#else
- _FindUnblockedSquares(pStack, &posBench);
-#endif
_GenerateAllMoves(pStack, &posBench);
uNumMoves = MOVE_COUNT(ctx, uPly);
ASSERT(uNumMoves > 0);
@@ -794,11 +404,7 @@ TestFindUnblockedSquaresSpeed(void)
for (uIter = 0; uIter < uCallsPerPosition; uIter++)
{
u64Start = SystemReadTimeStampCounter();
-#ifdef UNBLOCKED_BITBOARD
_FindUnblockedSquaresBB(pStack, &posBench);
-#else
- _FindUnblockedSquares(pStack, &posBench);
-#endif
for (uMove = pStack->uBegin[uPly];
uMove < pStack->uEnd[uPly];
uMove++)
diff --git a/src/testsee.c b/src/testsee.c
index 240ac39..4afe60f 100644
--- a/src/testsee.c
+++ b/src/testsee.c
@@ -26,19 +26,6 @@ Revision History:
#include "chess.h"
-// Same reasoning, for IsAttacked/InCheck (board_representation/
-// MOVEGEN_MIGRATION.md section 6b's ISATTACKED_BITBOARD toggle):
-// TestIsAttackedBB below must always be able to call the real mailbox
-// IsAttacked by name and compare it against IsAttackedBB explicitly,
-// regardless of which one chess.h's macro currently routes plain
-// "IsAttacked(...)" calls to elsewhere in the engine.
-#ifdef IsAttacked
-#undef IsAttacked
-#endif
-#ifdef InCheck
-#undef InCheck
-#endif
-
#ifdef TEST_BROKEN
ULONG g_uRootOnMove;
@@ -264,118 +251,6 @@ TestGetAttacks(void)
}
}
-// board_representation/MOVEGEN_MIGRATION.md section 6b: direct
-// comparison harness for IsAttacked/IsAttackedBB, same pattern as
-// TestGetAttacks above -- mailbox vs. bitboard, same inputs, must
-// match exactly. This is the piece ExposesCheckBB didn't get before
-// shipping and had to be debugged the hard way instead (two real bugs
-// found via TestSan/perft/DEBUG-assert failures rather than a direct
-// comparison); doing it properly here from the start.
-void
-TestIsAttackedBB(void)
-{
- POSITION pos;
- ULONG u;
- COOR c;
- ULONG uSide;
- FLAG fMailbox, fBB;
-
- Trace("Testing IsAttacked...\n");
- for (u = 0; u < 20000; u++)
- {
- GenerateRandomLegalPosition(&pos);
- FOREACH_SQUARE(c)
- {
- if (!IS_ON_BOARD(c)) continue;
- for (uSide = BLACK; uSide <= WHITE; uSide++)
- {
- fMailbox = IsAttacked(c, &pos, uSide);
- fBB = IsAttackedBB(c, &pos, uSide);
- if (fMailbox != fBB)
- {
- UtilPanic(TESTCASE_FAILURE,
- &pos,
- "IsAttacked/IsAttackedBB mismatch",
- NULL, NULL,
- __FILE__, __LINE__);
- }
- }
- }
- for (uSide = BLACK; uSide <= WHITE; uSide++)
- {
- fMailbox = InCheck(&pos, uSide);
- fBB = InCheckBB(&pos, uSide);
- if (fMailbox != fBB)
- {
- UtilPanic(TESTCASE_FAILURE,
- &pos,
- "InCheck/InCheckBB mismatch",
- NULL, NULL,
- __FILE__, __LINE__);
- }
- }
- }
-
- //
- // Speed: same isolated cycles/call methodology as TestGetAttacks
- // above, interleaved call-by-call to cancel shared-box noise.
- //
- {
- static const char *rgszFen[3] =
- {
- "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
- "r1bq1rk1/pp2bppp/2n1pn2/2pp4/3P4/2NBPN2/PP3PPP/R1BQ1RK1 w - - 0 1",
- "8/5k2/8/3K4/8/8/8/4R3 w - - 0 1",
- };
- static const char *rgszLabel[3] =
- {
- "opening ", "middlegame", "endgame ",
- };
- POSITION posBench;
- UINT64 u64MailboxTotal, u64BBTotal, u64Start;
- ULONG uIter;
- ULONG uSq;
- COOR cBench;
- ULONG uSideBench;
- const ULONG uCallsPerPosition = 200000;
- FLAG fSink;
-
- Trace("Benchmarking IsAttacked: mailbox vs IsAttackedBB "
- "(interleaved, %lu calls/position)...\n",
- uCallsPerPosition);
- for (u = 0; u < 3; u++)
- {
- FenToPosition(&posBench, (char *)rgszFen[u]);
- u64MailboxTotal = 0;
- u64BBTotal = 0;
- for (uIter = 0; uIter < uCallsPerPosition; uIter++)
- {
- uSq = uIter % 64;
- cBench = BIT_NUMBER_TO_COOR(uSq);
- uSideBench = uIter & 1;
- if (!IS_ON_BOARD(cBench)) continue;
-
- u64Start = SystemReadTimeStampCounter();
- fSink = IsAttacked(cBench, &posBench, uSideBench);
- u64MailboxTotal += (SystemReadTimeStampCounter() - u64Start);
-
- u64Start = SystemReadTimeStampCounter();
- fSink = IsAttackedBB(cBench, &posBench, uSideBench);
- u64BBTotal += (SystemReadTimeStampCounter() - u64Start);
- (void)fSink;
- }
- printf(" %s: mailbox %" COMPILER_LONGLONG_UNSIGNED_FORMAT
- " cycles/call, IsAttackedBB %"
- COMPILER_LONGLONG_UNSIGNED_FORMAT " cycles/call "
- "(BB is %.2fx mailbox)\n",
- rgszLabel[u],
- u64MailboxTotal / uCallsPerPosition,
- u64BBTotal / uCallsPerPosition,
- (double)u64BBTotal / (double)u64MailboxTotal);
- }
- }
-}
-
// SeeFastSign (see.c) is a sign-only shortcut for SEE(pos, mv) >= 0 --
// GetMoveSee's only consumer (ComputeMoveExtension, searchsup.c) never
// reads the magnitude, only the sign, so this skips SEE()'s list-