/* Protector -- a UCI chess engine Copyright (C) 2008 Raimund Heid (Raimund_Heid@yahoo.com) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* This module contains a bitboard-based chess move generator. */ #include #include #include #include #include "bitboard.h" #include "io.h" #define offset(sq1,sq2) ( ( (sq2)-(sq1) ) / distance(sq1,sq2) ) /** * Macros for internal use. */ #define HLANE(sq) ( rank(sq) ) #define HLANEBIT(sq) ( FILE_H - file(sq) ) #define VLANE(sq) ( file(sq) ) #define VLANEBIT(sq) ( RANK_8 - rank(sq) ) #define ULANE(sq) ( file(sq) - rank(sq) + 7 ) #define ULANEBIT(sq) ( RANK_8 - rank(sq) ) #define DLANE(sq) ( file(sq) + rank(sq) ) #define DLANEBIT(sq) ( rank(sq) ) #define HLANE_SQUARE(lane,bit) ( getSquare ( 7-(bit), (lane) ) ) #define VLANE_SQUARE(lane,bit) ( getSquare ( (lane), 7-(bit) ) ) #define ULANE_SQUARE(lane,bit) ( getSquare ( (lane)-(bit), 7-(bit) ) ) #define DLANE_SQUARE(lane,bit) ( getSquare ( (lane)-(bit), (bit) ) ) static bool isInitialized = FALSE; UINT64 minValue[_64_]; UINT64 maxValue[_64_]; INT8 highestBit[0x10000]; INT8 numSetBits[0x10000]; UINT8 rankOverlay[0x10000]; UINT8 bitshiftGap[8][256]; int hLaneNumber[_64_], vLaneNumber[_64_]; int uLaneNumber[_64_], dLaneNumber[_64_]; Bitboard generalMoves[0x0f][_64_]; Bitboard squaresOfFile[8]; Bitboard squaresOfRank[8]; Bitboard squaresOfLateralFiles[8]; Bitboard squaresOfFileRange[8][8]; Bitboard squaresOfRankRange[8][8]; Bitboard nonA, nonH, border, center, lightSquares, darkSquares, queenSide, kingSide, centerFiles, extendedCenter; Bitboard squaresBehind[_64_][_64_]; Bitboard squaresBetween[_64_][_64_]; Bitboard squaresInDistance[8][_64_]; Bitboard squaresInTaxiDistance[15][_64_]; Bitboard squaresAbove[2][_64_]; Bitboard squaresBelow[2][_64_]; Bitboard orthoKingAttackers[_64_]; Bitboard diaKingAttackers[_64_]; Bitboard knightKingAttackers[_64_]; Bitboard pawnKingAttackers[2][_64_]; SquareLaneInfo squareLaneInfo[_64_]; Bitboard hlane[_64_][256]; Bitboard vlane[_64_][256]; Bitboard ulane[_64_][256]; Bitboard dlane[_64_][256]; ObstacleSquareInfo obsi[_64_]; Bitboard pawnMoves[2][_64_][256]; Bitboard interestedPawns[2][_64_][256]; Bitboard castlings[2][16][256]; int castlingLane[] = { HLANE(E1), HLANE(E8) }; Bitboard promotionCandidates[2]; SetSquaresInfo setSquares[4][0x10000]; Bitboard preMaskRook[64], preMaskBishop[64]; Bitboard magicRookMoves[64][IMAX_ROOK]; Bitboard magicBishopMoves[64][IMAX_BISHOP]; MagicSquareInfoRook magicSquareInfoRook[64]; MagicSquareInfoBishop magicSquareInfoBishop[64]; const Bitboard magicRookNumber[64] = { 2341871876025885824, 5908793080399659264, 2814784401577026, 4755810071654563842, 4683749110191751172, 648520571176420352, 288793875996213508, 36039242390061312, 2233855853176307712, 360296835543278592, 37470368710784, 2261832991510528, 74595267411776576, 4612831726723531008, 17491104022660138, 9015996489662496, 164381455144716288, 4785426803991552, 2603080765009821794, 4504870937840771, 73202185810346241, 2594073935322554944, 577059170398781952, 687199551504, 36029072970620928, 4755818807417635204, 2305854279342097445, 4654506018003485187, 1369095394823243808, 1650609881216, 35189740863840, 17609634498592, 17867407885440, 1307170084179935305, 5224509820511455237, 30399366238175240, 685674177139050632, 4504708001565696, 576777574861506688, 2305843147759948801, 36046664624070657, 2305862800624326656, 35201686183936, 76563943050448912, 4828140284174931982, 93630429790212, 2305862800758624268, 4918212371161546978, 1197987317416064, 4629700452154347536, 144220742299427329, 1152928385211832832, 40132191457288, 9354573578272, 650209674406199320, 36029355649925192, 3470081245843620386, 9208682512641, 586664357648667141, 113161891886927874, 19144700892151826, 594756909391937601, 562958551810122, 1152922124158043138, }; const Bitboard magicBishopNumber[64] = { 2287018567549508, 20833559275112450, 1157535125460746242, 2343279465658384466, 182423557274534246, 91204498130747394, 79165240377360, 18024053647361153, 4756927389883318784, 2377974339296303121, 1529092243969, 18016872700051744, 1153204084472553600, 873698516757668385, 1125942867148800, 26423192526848, 289939073072784384, 10714208241454656, 2306405960274414104, 54114131212519426, 109212291534684230, 2306971108957557248, 288239189760215296, 166643228131737628, 3459894829004630016, 35193180131968, 576478344523031040, 1134696069202368, 298367873364066368, 2882596248975577091, 432437927499531776, 72621163549300482, 468396630660612192, 576812875222894592, 3463272528741531664, 2612123106223325312, 3242874314789487108, 3461016494560002066, 4539883779662384, 5909074606504807464, 4684333518172472324, 306280543752814656, 2345387698176, 293016142258114592, 5073215437209668, 79251277611040, 602532708688384, 20310252071682068, 4467607076866, 648573875995549696, 288232580007339520, 1188986585695191042, 9306611390751752, 5498105049088, 4625205909830770716, 1152994261659095304, 126118725618245632, 2305851875981395204, 351843796394505, 40532672078233696, 9009398294791225, 4611688257515749392, 1152930369572702464, 2306989456245202960, }; int getFloodValue(const Square origin, const Bitboard targets, const Bitboard permittedSquares) { Bitboard floodedSquares = getKingMoves(origin) & permittedSquares; Bitboard oldFloodedSquares = minValue[origin]; int numSteps = 1; while ((targets & floodedSquares) == EMPTY_BITBOARD && floodedSquares != oldFloodedSquares) { oldFloodedSquares = floodedSquares; floodBoard(&floodedSquares); floodedSquares |= oldFloodedSquares; floodedSquares &= permittedSquares; numSteps++; } return numSteps; } static void initializeKingMoves() { int offset[] = { 1, -1, 7, -7, 8, -8, 9, -9 }, direction; Square square; ITERATE(square) { for (direction = 0; direction < 8; direction++) { Square target = (Square) (square + offset[direction]); if (squareIsValid(target) && distance(square, target) == 1) { generalMoves[KING][square] |= minValue[target]; } } } } static void initializeRookMoves() { int offset[] = { 1, -1, 8, -8 }, direction, moveLength; Square square; ITERATE(square) { for (direction = 0; direction < 4; direction++) { for (moveLength = 1; moveLength <= 7; moveLength++) { Square target = (Square) (square + offset[direction] * moveLength); bool sameFile = (bool) (file(square) == file(target)); bool sameRow = (bool) (rank(square) == rank(target)); if (squareIsValid(target) && (sameFile || sameRow)) { generalMoves[ROOK][square] |= minValue[target]; } else { break; } } } } } static void initializeBishopMoves() { int offset[] = { 7, -7, 9, -9 }, direction, moveLength; Square square; ITERATE(square) { for (direction = 0; direction < 4; direction++) { for (moveLength = 1; moveLength <= 7; moveLength++) { Square target = (Square) (square + offset[direction] * moveLength); int hDistance = horizontalDistance(square, target); int vDistance = verticalDistance(square, target); if (squareIsValid(target) && hDistance == vDistance) { generalMoves[BISHOP][square] |= minValue[target]; } else { break; } } } } } static void initializeQueenMoves() { Square square; ITERATE(square) { generalMoves[QUEEN][square] = generalMoves[ROOK][square] | generalMoves[BISHOP][square]; } } static void initializeKnightMoves() { int offset[] = { 6, -6, 10, -10, 15, -15, 17, -17 }, direction; Square square; ITERATE(square) { for (direction = 0; direction < 8; direction++) { Square target = (Square) (square + offset[direction]); if (squareIsValid(target) && distance(square, target) <= 2) { generalMoves[KNIGHT][square] |= minValue[target]; } } } } static void initializePawnMoves() { Square square; ITERATE(square) { if (file(square) != FILE_A) { if (square <= H8 - 7) { generalMoves[WHITE_PAWN][square] |= minValue[square + 7]; } if (square >= A1 + 9) { generalMoves[BLACK_PAWN][square] |= minValue[square - 9]; } } if (file(square) != FILE_H) { if (square <= H8 - 9) { generalMoves[WHITE_PAWN][square] |= minValue[square + 9]; } if (square >= A1 + 7) { generalMoves[BLACK_PAWN][square] |= minValue[square - 7]; } } } } static Bitboard calculateSquaresBehind(Square square, int offset) { Bitboard squares = EMPTY_BITBOARD; for (square = (Square) (square + offset); squareIsValid(square) && distance(square, (Square) (square - offset)) == 1; square = (Square) (square + offset)) { Bitboard mv = minValue[square]; squares |= mv; } return squares; } static void initializeSquaresBehind() { Square sq1, sq2; ITERATE(sq1) { Bitboard squares = generalMoves[QUEEN][sq1]; ITERATE_BITBOARD(&squares, sq2) { int offset = offset(sq1, sq2); squaresBehind[sq2][sq1] = calculateSquaresBehind(sq2, offset); } } } static Bitboard calculateSquaresBetween(Square sq1, Square sq2) { Bitboard squares = EMPTY_BITBOARD; int _offset = offset(sq1, sq2), square; for (square = sq1 + _offset; square != sq2; square += _offset) { squares |= minValue[square]; } return squares; } static void initializeSquaresBetween() { Square sq1, sq2; ITERATE(sq1) { Bitboard squares = generalMoves[QUEEN][sq1]; ITERATE_BITBOARD(&squares, sq2) { squaresBetween[sq1][sq2] = calculateSquaresBetween(sq1, sq2); } } } static void initializeSquareLaneInfo() { Square square; ITERATE(square) { SquareLaneInfo *sqi = &squareLaneInfo[square]; sqi->hLane = hLaneNumber[square] = HLANE(square); sqi->hLaneSetMask = (BYTE) minValue[HLANEBIT(square)]; sqi->hLaneClearMask = (BYTE) ~ sqi->hLaneSetMask; sqi->vLane = vLaneNumber[square] = VLANE(square) + 8; sqi->vLaneSetMask = (BYTE) minValue[VLANEBIT(square)]; sqi->vLaneClearMask = (BYTE) ~ sqi->vLaneSetMask; sqi->uLane = uLaneNumber[square] = ULANE(square) + 16; sqi->uLaneSetMask = (BYTE) minValue[ULANEBIT(square)]; sqi->uLaneClearMask = (BYTE) ~ sqi->uLaneSetMask; sqi->dLane = dLaneNumber[square] = DLANE(square) + 31; sqi->dLaneSetMask = (BYTE) minValue[DLANEBIT(square)]; sqi->dLaneClearMask = (BYTE) ~ sqi->dLaneSetMask; } } static Bitboard getHlaneVector(int lane, BYTE mask) { int i; Bitboard v = EMPTY_BITBOARD; for (i = 0; i < 8; i++) { if (mask & minValue[i]) { v |= minValue[7 - i]; } } v <<= 8 * lane; return v; } static Bitboard getVlaneVector(int lane, BYTE mask) { int i; Bitboard v = EMPTY_BITBOARD; for (i = 0; i < 8; i++) { if (mask & minValue[i]) { v |= minValue[8 * (7 - i)]; } } v <<= lane; return v; } static Bitboard getUlaneVector(int lane, BYTE mask) { int i; Bitboard v = EMPTY_BITBOARD; for (i = 0; i < 8; i++) { v <<= 8; if (mask & minValue[i]) { v |= minValue[7 - i]; } } if (lane < 7) { for (i = lane; i < 7; i++) { v = (v & nonA) >> 1; } } else { for (i = lane; i > 7; i--) { v = (v & nonH) << 1; } } return v; } static Bitboard getDlaneVector(int lane, BYTE mask) { int i; Bitboard v = EMPTY_BITBOARD; for (i = 0; i < 8; i++) { v <<= 8; if (mask & minValue[7 - i]) { v |= minValue[i]; } } if (lane < 7) { for (i = lane; i < 7; i++) { v = (v & nonA) >> 1; } } else { for (i = lane; i > 7; i--) { v = (v & nonH) << 1; } } return v; } static Bitboard getLaneMask(Square square, int offset, Bitboard legalSquares, Bitboard obstacles) { Bitboard laneMask = EMPTY_BITBOARD, mv = EMPTY_BITBOARD; while ((square = (Square) (square + offset)) >= A1 && square <= H8 && ((mv = minValue[square]) & legalSquares)) { laneMask |= mv; if (mv & obstacles) { break; } } return laneMask; } static Bitboard getHLaneMask(Square square, BYTE mask) { int lane = HLANE(square); Bitboard legalSquares = getHlaneVector(lane, 255); Bitboard obstacles = getHlaneVector(lane, mask); Bitboard laneMask = getLaneMask(square, 1, legalSquares, obstacles); laneMask |= getLaneMask(square, -1, legalSquares, obstacles); return laneMask; } static Bitboard getVLaneMask(Square square, BYTE mask) { int lane = VLANE(square); Bitboard legalSquares = getVlaneVector(lane, 255); Bitboard obstacles = getVlaneVector(lane, mask); Bitboard laneMask = getLaneMask(square, 8, legalSquares, obstacles); laneMask |= getLaneMask(square, -8, legalSquares, obstacles); return laneMask; } static Bitboard getULaneMask(Square square, BYTE mask) { int lane = ULANE(square); Bitboard legalSquares = getUlaneVector(lane, 255); Bitboard obstacles = getUlaneVector(lane, mask); Bitboard laneMask = getLaneMask(square, 9, legalSquares, obstacles); laneMask |= getLaneMask(square, -9, legalSquares, obstacles); return laneMask; } static Bitboard getDLaneMask(Square square, BYTE mask) { int lane = DLANE(square); Bitboard legalSquares = getDlaneVector(lane, 255); Bitboard obstacles = getDlaneVector(lane, mask); Bitboard laneMask = getLaneMask(square, 7, legalSquares, obstacles); laneMask |= getLaneMask(square, -7, legalSquares, obstacles); return laneMask; } static Bitboard getWhitePawnMoves(Square square, BYTE laneMask) { int lane = VLANE(square); Bitboard moves = EMPTY_BITBOARD, board = getVlaneVector(lane, laneMask); if (square >= A2 && square <= H7 && (board & minValue[square + 8]) == 0) { moves |= minValue[square + 8]; if (square <= H2 && (board & minValue[square + 16]) == 0) { moves |= minValue[square + 16]; } } return moves; } static Bitboard getInterestedWhitePawns(Square square, BYTE laneMask) { int lane = VLANE(square); Bitboard pawns = EMPTY_BITBOARD, board = getVlaneVector(lane, laneMask); if (square >= A3 && square <= H8 && (board & minValue[square]) == 0) { pawns |= minValue[square - 8]; if (rank(square) == RANK_4 && (board & minValue[square - 8]) == 0) { pawns |= minValue[square - 16]; } } return pawns; } static Bitboard getBlackPawnMoves(Square square, BYTE laneMask) { int lane = VLANE(square); Bitboard moves = EMPTY_BITBOARD, board = getVlaneVector(lane, laneMask); if (square >= A2 && square <= H7 && (board & minValue[square - 8]) == 0) { moves |= minValue[square - 8]; if (square >= A7 && (board & minValue[square - 16]) == 0) { moves |= minValue[square - 16]; } } return moves; } static Bitboard getInterestedBlackPawns(Square square, BYTE laneMask) { int lane = VLANE(square); Bitboard pawns = EMPTY_BITBOARD, board = getVlaneVector(lane, laneMask); if (square >= A1 && square <= H6 && (board & minValue[square]) == 0) { pawns |= minValue[square + 8]; if (rank(square) == RANK_5 && (board & minValue[square + 8]) == 0) { pawns |= minValue[square + 16]; } } return pawns; } static void initializeLaneMasks() { Square square; int i; ITERATE(square) { for (i = 0; i <= 255; i++) { BYTE mask = (BYTE) i; hlane[square][i] = getHLaneMask(square, mask); vlane[square][i] = getVLaneMask(square, mask); ulane[square][i] = getULaneMask(square, mask); dlane[square][i] = getDLaneMask(square, mask); pawnMoves[WHITE][square][i] = getWhitePawnMoves(square, mask); pawnMoves[BLACK][square][i] = getBlackPawnMoves(square, mask); interestedPawns[WHITE][square][i] = getInterestedWhitePawns(square, mask); interestedPawns[BLACK][square][i] = getInterestedBlackPawns(square, mask); } } ITERATE(square) { int i; obsi[square].hLaneNumber = hLaneNumber[square]; obsi[square].vLaneNumber = vLaneNumber[square]; obsi[square].uLaneNumber = uLaneNumber[square]; obsi[square].dLaneNumber = dLaneNumber[square]; for (i = 0; i < 256; i++) { obsi[square].hLane[i] = hlane[square][i]; obsi[square].vLane[i] = vlane[square][i]; obsi[square].uLane[i] = ulane[square][i]; obsi[square].dLane[i] = dlane[square][i]; } } } static Bitboard getCastlings(const Bitboard obstacles) { Bitboard castlings = EMPTY_BITBOARD; if ((obstacles & minValue[F1]) == EMPTY_BITBOARD && (obstacles & minValue[G1]) == EMPTY_BITBOARD) { castlings |= minValue[G1]; } if ((obstacles & minValue[B1]) == EMPTY_BITBOARD && (obstacles & minValue[C1]) == EMPTY_BITBOARD && (obstacles & minValue[D1]) == EMPTY_BITBOARD) { castlings |= minValue[C1]; } return castlings; } static void initializeCastlings() { int i, c; for (i = 0; i <= 255; i++) { BYTE mask = (BYTE) i; Bitboard moves = getCastlings((Bitboard) mask); for (c = 0; c <= 15; c++) { castlings[WHITE][c][mask] = castlings[BLACK][c][mask] = 0; if (moves & minValue[G1]) { if (c & WHITE_00) { castlings[WHITE][c][mask] |= minValue[G1]; } if (c & BLACK_00) { castlings[BLACK][c][mask] |= minValue[G8]; } } if (moves & minValue[C1]) { if (c & WHITE_000) { castlings[WHITE][c][mask] |= minValue[C1]; } if (c & BLACK_000) { castlings[BLACK][c][mask] |= minValue[C8]; } } } } } static INT8 _getNumberOfSetBits(INT32 v) { int count = 0, i; for (i = 0; i < 16; i++) { count += (v >> i) & 1; } return (INT8) count; } static UINT8 _getRankOverlay(INT32 v) { return (UINT8) ((v & 0xff) | ((v >> 8) & 0xff)); } unsigned int getMinimumDistance(const Bitboard targets, const Square square) { unsigned int distance; for (distance = 1; distance <= 7; distance++) { if ((squaresInDistance[distance][square] & targets) != EMPTY_BITBOARD) { return distance; } } return 0; } unsigned int getMaximumDistance(const Bitboard targets, const Square square) { unsigned int distance; for (distance = 7; distance > 0; distance--) { if ((squaresInDistance[distance][square] & targets) != EMPTY_BITBOARD) { return distance; } } return 0; } Bitboard getPremaskExclusions(const Square square) { if (testSquare(border, square)) { Bitboard exclusions = EMPTY_BITBOARD; if (testSquare(squaresOfFile[FILE_A], square) == FALSE) { exclusions |= squaresOfFile[FILE_A]; } if (testSquare(squaresOfFile[FILE_H], square) == FALSE) { exclusions |= squaresOfFile[FILE_H]; } if (testSquare(squaresOfRank[RANK_1], square) == FALSE) { exclusions |= squaresOfRank[RANK_1]; } if (testSquare(squaresOfRank[RANK_8], square) == FALSE) { exclusions |= squaresOfRank[RANK_8]; } return exclusions; } else { return border; } } void initializePremasks() { Square square; ITERATE(square) { preMaskRook[square] = generalMoves[WHITE_ROOK][square] & ~getPremaskExclusions(square); preMaskBishop[square] = generalMoves[WHITE_BISHOP][square] & ~getPremaskExclusions(square); } } void initializeMagicRookMoves(const Square square) { Square squareOfIndex[12]; Bitboard allMoves = preMaskRook[square]; const Bitboard premask = preMaskRook[square]; int i, pieceSetup; Square sq1; BYTE obstacles[NUM_LANES]; const Bitboard magicNumber = magicRookNumber[square]; for (i = 0; i < IMAX_ROOK; i++) { magicRookMoves[square][i] = EMPTY_BITBOARD; } for (i = 0; i < 12; i++) { squareOfIndex[i] = NO_SQUARE; } i = 0; ITERATE_BITBOARD(&allMoves, sq1) { assert(i < 12); squareOfIndex[i++] = sq1; } for (pieceSetup = 0; pieceSetup < 4096; pieceSetup++) { Bitboard currentSetup = EMPTY_BITBOARD, effectiveMoves; int j = 1; Bitboard magicIndex; for (i = 0; i < 12 && squareOfIndex[i] != NO_SQUARE; i++) { if ((pieceSetup & j) != 0) { setSquare(currentSetup, squareOfIndex[i]); } j *= 2; } calculateObstacles(currentSetup, obstacles); effectiveMoves = getRookMoves(square, obstacles); magicIndex = ((currentSetup & premask) * magicNumber) >> 52; magicRookMoves[square][magicIndex] = effectiveMoves; } } void initializeMagicBishopMoves(const Square square) { Square squareOfIndex[12]; Bitboard allMoves = preMaskBishop[square]; const Bitboard premask = preMaskBishop[square]; int i, pieceSetup; Square sq1; BYTE obstacles[NUM_LANES]; const Bitboard magicNumber = magicBishopNumber[square]; for (i = 0; i < IMAX_BISHOP; i++) { magicBishopMoves[square][i] = EMPTY_BITBOARD; } for (i = 0; i < 12; i++) { squareOfIndex[i] = NO_SQUARE; } i = 0; ITERATE_BITBOARD(&allMoves, sq1) { assert(i < 12); squareOfIndex[i++] = sq1; } for (pieceSetup = 0; pieceSetup < 4096; pieceSetup++) { Bitboard currentSetup = EMPTY_BITBOARD, effectiveMoves; int j = 1; Bitboard magicIndex; for (i = 0; i < 12 && squareOfIndex[i] != NO_SQUARE; i++) { if ((pieceSetup & j) != 0) { setSquare(currentSetup, squareOfIndex[i]); } j *= 2; } calculateObstacles(currentSetup, obstacles); effectiveMoves = getBishopMoves(square, obstacles); magicIndex = ((currentSetup & premask) * magicNumber) >> 55; magicBishopMoves[square][magicIndex] = effectiveMoves; } } /* #define GENERATE_MAGIC_NUMBERS */ #ifdef GENERATE_MAGIC_NUMBERS #define IMAX 4096 #define BMAX 12 Bitboard collisions[IMAX]; bool testMagicNumber(const Bitboard magicNumber, const Square square, const bool rookMoves) { Square squareOfIndex[BMAX]; const Bitboard premask = (rookMoves ? preMaskRook[square] : preMaskBishop[square]); Bitboard allMoves = premask; int i, pieceSetup; Square sq1; BYTE obstacles[NUM_LANES]; for (i = 0; i < IMAX; i++) { collisions[i] = EMPTY_BITBOARD; } for (i = 0; i < BMAX; i++) { squareOfIndex[i] = NO_SQUARE; } i = 0; ITERATE_BITBOARD(&allMoves, sq1) { assert(i < BMAX); squareOfIndex[i++] = sq1; } for (pieceSetup = 0; pieceSetup < IMAX; pieceSetup++) { Bitboard currentSetup = EMPTY_BITBOARD, effectiveMoves, calcBase; int j = 1; Bitboard magicIndex; const int shift = (rookMoves ? 64 - 12 : 64 - 9); for (i = 0; i < BMAX && squareOfIndex[i] != NO_SQUARE; i++) { if ((pieceSetup & j) != 0) { setSquare(currentSetup, squareOfIndex[i]); } j *= 2; } calculateObstacles(currentSetup, obstacles); effectiveMoves = (rookMoves ? getRookMoves(square, obstacles) : getBishopMoves(square, obstacles)); calcBase = currentSetup & premask; magicIndex = (calcBase * magicNumber) >> shift; if (collisions[magicIndex] == EMPTY_BITBOARD) { collisions[magicIndex] = effectiveMoves; } else { if (effectiveMoves != collisions[magicIndex]) { return FALSE; /* severe collision -> magic number not suitable */ } } } return TRUE; /* the given magic number is valid */ } UINT64 get64bitRandom() { const UINT64 limit = (RAND_MAX * 13) / 100; UINT64 rn = 0, runningOne = 1; int i; for (i = 0; i < 64; i++) { if (rand() <= limit) { rn |= runningOne; } runningOne *= 2; } return rn; } void calculateMagicNumbers() { Square square; printf("{"); ITERATE(square) { Bitboard magicNumber = get64bitRandom(); while (testMagicNumber(magicNumber, square, TRUE) == FALSE) { magicNumber = get64bitRandom(); } printf("%llu, ", magicNumber); if ((square % 2) == 1) { printf("\n"); } } printf("};\n{"); ITERATE(square) { Bitboard magicNumber = get64bitRandom(); while (testMagicNumber(magicNumber, square, FALSE) == FALSE) { magicNumber = get64bitRandom(); } printf("%llu, ", magicNumber); if ((square % 2) == 1) { printf("\n"); } } printf("};\n"); getKeyStroke(); } #endif /* GENREATE_MAGIC_NUMBERS */ int initializeModuleBitboard() { INT32 i; UINT32 j; INT8 index, k; UINT64 min = 1; Square square; if (isInitialized) { return 0; } else { isInitialized = TRUE; } ITERATE(i) { minValue[i] = min; maxValue[i] = ~min; min *= 2; } highestBit[0] = NO_SQUARE; for (i = 1; i <= 0xffffL; i++) { numSetBits[i] = _getNumberOfSetBits(i); rankOverlay[i] = _getRankOverlay(i); j = i; index = 0; for (k = 0x00; k <= 0x0f; k++) { if ((j & 1) == 1) { index = k; } j >>= 1; } highestBit[i] = index; } for (i = FILE_A; i <= FILE_H; i++) { squaresOfFile[i] = squaresOfRank[i] = squaresOfLateralFiles[i] = EMPTY_BITBOARD; } ITERATE(square) { int distance; squaresOfFile[file(square)] |= minValue[square]; squaresOfRank[rank(square)] |= minValue[square]; if (squareColor(square) == DARK) { setSquare(darkSquares, square); clearSquare(lightSquares, square); } else { clearSquare(darkSquares, square); setSquare(lightSquares, square); } for (distance = 0; distance <= 7; distance++) { Square square2; squaresInDistance[distance][square] = EMPTY_BITBOARD; ITERATE(square2) { if (distance(square, square2) <= distance) { setSquare(squaresInDistance[distance][square], square2); } } } for (distance = 0; distance <= 14; distance++) { Square square2; squaresInTaxiDistance[distance][square] = EMPTY_BITBOARD; ITERATE(square2) { if (taxiDistance(square, square2) <= distance) { setSquare(squaresInTaxiDistance[distance][square], square2); } } } } for (i = FILE_A; i <= FILE_H; i++) { int j; if (i != FILE_A) { squaresOfLateralFiles[i] |= squaresOfFile[i - 1]; } if (i != FILE_H) { squaresOfLateralFiles[i] |= squaresOfFile[i + 1]; } for (j = FILE_A; j <= FILE_H; j++) { int k; squaresOfFileRange[i][j] = squaresOfRankRange[i][j] = EMPTY_BITBOARD; for (k = FILE_A; k <= FILE_H; k++) { if ((k >= i && k <= j) || (k >= j && k <= i)) { squaresOfFileRange[i][j] |= squaresOfFile[k]; squaresOfRankRange[i][j] |= squaresOfRank[k]; } } } } nonA = ~squaresOfFile[FILE_A], nonH = ~squaresOfFile[FILE_H]; center = minValue[D4] | minValue[D5] | minValue[E4] | minValue[E5]; extendedCenter = (squaresOfFile[FILE_C] | squaresOfFile[FILE_D] | squaresOfFile[FILE_E] | squaresOfFile[FILE_F]) & (squaresOfRank[RANK_3] | squaresOfRank[RANK_4] | squaresOfRank[RANK_5] | squaresOfRank[RANK_6]); border = squaresOfFile[FILE_A] | squaresOfFile[FILE_H] | squaresOfRank[RANK_1] | squaresOfRank[RANK_8]; queenSide = squaresOfFile[FILE_A] | squaresOfFile[FILE_B] | squaresOfFile[FILE_C]; kingSide = squaresOfFile[FILE_F] | squaresOfFile[FILE_G] | squaresOfFile[FILE_H]; centerFiles = squaresOfFile[FILE_D] | squaresOfFile[FILE_E]; promotionCandidates[WHITE] = squaresOfRank[RANK_7]; promotionCandidates[BLACK] = squaresOfRank[RANK_2]; initializeKingMoves(); initializeRookMoves(); initializeBishopMoves(); initializeQueenMoves(); initializeKnightMoves(); initializePawnMoves(); initializeSquaresBehind(); initializeSquaresBetween(); initializeSquareLaneInfo(); initializeLaneMasks(); initializeCastlings(); ITERATE(square) { const Bitboard corona = generalMoves[KING][square]; Square square2; orthoKingAttackers[square] = diaKingAttackers[square] = knightKingAttackers[square] = pawnKingAttackers[WHITE][square] = pawnKingAttackers[BLACK][square] = EMPTY_BITBOARD; squaresAbove[WHITE][square] = squaresAbove[BLACK][square] = squaresBelow[WHITE][square] = squaresBelow[BLACK][square] = EMPTY_BITBOARD; ITERATE(square2) { const Bitboard orthoSquares = generalMoves[ROOK][square2]; const Bitboard diaSquares = generalMoves[BISHOP][square2]; const Bitboard knightSquares = generalMoves[KNIGHT][square2]; const Bitboard whitePawnSquares = generalMoves[WHITE_PAWN][square2]; const Bitboard blackPawnSquares = generalMoves[BLACK_PAWN][square2]; if (square != square2 && (corona & orthoSquares) != EMPTY_BITBOARD && taxiDistance(square, square2) > 1) { setSquare(orthoKingAttackers[square], square2); } if (square != square2 && (corona & diaSquares) != EMPTY_BITBOARD && (distance(square, square2) > 1 || taxiDistance(square, square2) != 2)) { setSquare(diaKingAttackers[square], square2); } if (square != square2 && (corona & knightSquares) != EMPTY_BITBOARD && testSquare(knightSquares, square) == EMPTY_BITBOARD) { setSquare(knightKingAttackers[square], square2); } if (square != square2 && (corona & whitePawnSquares) != EMPTY_BITBOARD && testSquare(whitePawnSquares, square) == EMPTY_BITBOARD) { setSquare(pawnKingAttackers[WHITE][square], square2); } if (square != square2 && (corona & blackPawnSquares) != EMPTY_BITBOARD && testSquare(blackPawnSquares, square) == EMPTY_BITBOARD) { setSquare(pawnKingAttackers[BLACK][square], square2); } if (rank(square2) < rank(square)) { setSquare(squaresBelow[WHITE][square], square2); setSquare(squaresAbove[BLACK][square], square2); } if (rank(square2) > rank(square)) { setSquare(squaresAbove[WHITE][square], square2); setSquare(squaresBelow[BLACK][square], square2); } } } for (i = 0; i < 256; i++) { for (j = 0; j < 8; j++) { bitshiftGap[j][i] = (i == 0 ? 0 : 8); for (k = 0; k < 8; k++) { if ((minValue[(int) k] & i) != 0 && abs(j - k) < bitshiftGap[j][i]) { bitshiftGap[j][i] = (UINT8) abs(j - k); } } } } for (i = 0; i < 4; i++) { UINT64 bitMask; for (bitMask = 0; bitMask < 0x10000; bitMask++) { SetSquaresInfo *info = &setSquares[i][bitMask]; Bitboard board = bitMask << (16 * i); Square square; info->numSetSquares = 0; ITERATE_BITBOARD(&board, square) { info->setSquares[info->numSetSquares++] = (UINT8) square; } } } initializePremasks(); ITERATE(square) { initializeMagicRookMoves(square); initializeMagicBishopMoves(square); } ITERATE(square) { int i; magicSquareInfoRook[square].preMask = preMaskRook[square]; magicSquareInfoRook[square].magicNumber = magicRookNumber[square]; for (i = 0; i < IMAX_ROOK; i++) { magicSquareInfoRook[square].moves[i] = magicRookMoves[square][i]; } magicSquareInfoBishop[square].preMask = preMaskBishop[square]; magicSquareInfoBishop[square].magicNumber = magicBishopNumber[square]; for (i = 0; i < IMAX_BISHOP; i++) { magicSquareInfoBishop[square].moves[i] = magicBishopMoves[square][i]; } } #ifdef GENERATE_MAGIC_NUMBERS calculateMagicNumbers(); #endif return 0; } #ifndef NDEBUG static int testBitOperations() { Bitboard b = EMPTY_BITBOARD; assert(testSquare(lightSquares, A1) == 0); assert(testSquare(lightSquares, B1)); assert(testSquare(lightSquares, G8)); assert(testSquare(lightSquares, H8) == 0); assert(testSquare(darkSquares, A1)); assert(testSquare(darkSquares, B1) == 0); assert(testSquare(darkSquares, G8) == 0); assert(testSquare(darkSquares, H8)); assert(highestBit[0x0f] == 3); assert(highestBit[0xffff] == 15); assert(numSetBits[0] == 0); assert(numSetBits[0x5555] == 8); assert(numSetBits[0xaaaa] == 8); assert(numSetBits[0xffff] == 16); assert(testSquare(b, D4) == 0); setSquare(b, D4); assert(testSquare(b, D4) != 0); clearSquare(b, D4); assert(testSquare(b, D4) == 0); assert(testSquare(b, H8) == 0); setSquare(b, H8); assert(testSquare(b, H8) != 0); clearSquare(b, H8); assert(testSquare(b, H8) == 0); assert(getNextSquare(&b) == NO_SQUARE); setSquare(b, H8); assert(getNextSquare(&b) == H8); assert(getNextSquare(&b) == NO_SQUARE); assert(testSquare(squaresBehind[D4][C3], E5)); assert(testSquare(squaresBehind[D4][C3], F6)); assert(testSquare(squaresBehind[D4][C3], G7)); assert(testSquare(squaresBehind[D4][C3], H8)); assert(getNumberOfSetSquares(squaresBehind[D4][C3]) == 4); assert(testSquare(squaresBetween[B3][F7], C4)); assert(testSquare(squaresBetween[B3][F7], D5)); assert(testSquare(squaresBetween[B3][F7], E6)); assert(getNumberOfSetSquares(squaresBetween[B3][F7]) == 3); assert(rankOverlay[0x8143] == 0xC3); b = EMPTY_BITBOARD; setSquare(b, A4); setSquare(b, E1); setSquare(b, E8); setSquare(b, H7); assert(getRankOverlay(b) == 0x91); assert(testSquare(squaresInDistance[1][C3], C4) != FALSE); assert(testSquare(squaresInDistance[1][C3], C5) == FALSE); assert(testSquare(squaresInDistance[3][E5], E2) != FALSE); assert(testSquare(squaresInDistance[3][E5], E1) == FALSE); assert(testSquare(squaresInDistance[5][H8], C3) != FALSE); assert(testSquare(squaresInDistance[5][H8], B2) == FALSE); assert(bitshiftGap[5][0] == 0); assert(bitshiftGap[1][129] == 1); assert(bitshiftGap[4][129] == 3); return 0; } static int testGeneralMoves() { assert(testSquare(generalMoves[KING][C3], C4)); assert(testSquare(generalMoves[KING][C3], D4)); assert(testSquare(generalMoves[KING][C3], D3)); assert(testSquare(generalMoves[KING][C3], D2)); assert(testSquare(generalMoves[KING][C3], C2)); assert(testSquare(generalMoves[KING][C3], B2)); assert(testSquare(generalMoves[KING][C3], B3)); assert(testSquare(generalMoves[KING][C3], B4)); assert(getNumberOfSetSquares(generalMoves[KING][C3]) == 8); assert(testSquare(generalMoves[ROOK][C3], C8)); assert(testSquare(generalMoves[ROOK][C3], H3)); assert(testSquare(generalMoves[ROOK][C3], C1)); assert(testSquare(generalMoves[ROOK][C3], A3)); assert(getNumberOfSetSquares(generalMoves[ROOK][C3]) == 14); assert(testSquare(generalMoves[BISHOP][C3], H8)); assert(testSquare(generalMoves[BISHOP][C3], E1)); assert(testSquare(generalMoves[BISHOP][C3], A1)); assert(testSquare(generalMoves[BISHOP][C3], A5)); assert(getNumberOfSetSquares(generalMoves[BISHOP][C3]) == 11); assert(testSquare(generalMoves[QUEEN][C3], C8)); assert(testSquare(generalMoves[QUEEN][C3], H8)); assert(testSquare(generalMoves[QUEEN][C3], H3)); assert(testSquare(generalMoves[QUEEN][C3], E1)); assert(testSquare(generalMoves[QUEEN][C3], C1)); assert(testSquare(generalMoves[QUEEN][C3], A1)); assert(testSquare(generalMoves[QUEEN][C3], A3)); assert(testSquare(generalMoves[QUEEN][C3], A5)); assert(getNumberOfSetSquares(generalMoves[QUEEN][C3]) == 25); assert(testSquare(generalMoves[KNIGHT][C3], A2)); assert(testSquare(generalMoves[KNIGHT][C3], A4)); assert(testSquare(generalMoves[KNIGHT][C3], B5)); assert(testSquare(generalMoves[KNIGHT][C3], D5)); assert(testSquare(generalMoves[KNIGHT][C3], E4)); assert(testSquare(generalMoves[KNIGHT][C3], E2)); assert(testSquare(generalMoves[KNIGHT][C3], D1)); assert(testSquare(generalMoves[KNIGHT][C3], B1)); assert(getNumberOfSetSquares(generalMoves[KNIGHT][C3]) == 8); assert(getNumberOfSetSquares(generalMoves[KNIGHT][A1]) == 2); assert(getNumberOfSetSquares(generalMoves[KNIGHT][H8]) == 2); assert(testSquare(generalMoves[WHITE_PAWN][A2], B3)); assert(getNumberOfSetSquares(generalMoves[WHITE_PAWN][A2]) == 1); assert(testSquare(generalMoves[WHITE_PAWN][B2], A3)); assert(testSquare(generalMoves[WHITE_PAWN][B2], C3)); assert(getNumberOfSetSquares(generalMoves[WHITE_PAWN][B2]) == 2); assert(testSquare(generalMoves[WHITE_PAWN][H2], G3)); assert(getNumberOfSetSquares(generalMoves[WHITE_PAWN][H2]) == 1); assert(testSquare(generalMoves[BLACK_PAWN][A7], B6)); assert(getNumberOfSetSquares(generalMoves[BLACK_PAWN][A7]) == 1); assert(testSquare(generalMoves[BLACK_PAWN][B7], A6)); assert(testSquare(generalMoves[BLACK_PAWN][B7], C6)); assert(getNumberOfSetSquares(generalMoves[BLACK_PAWN][B7]) == 2); assert(testSquare(generalMoves[BLACK_PAWN][H7], G6)); assert(getNumberOfSetSquares(generalMoves[BLACK_PAWN][H7]) == 1); return 0; } static int testPieces() { Bitboard b = EMPTY_BITBOARD, moves; BYTE obstacles[NUM_LANES]; setSquare(b, C3); setSquare(b, C6); setSquare(b, F6); calculateObstacles(b, obstacles); moves = getMagicRookMoves(C4, b); assert(testSquare(moves, C3)); assert(testSquare(moves, C5)); assert(testSquare(moves, C6)); assert(testSquare(moves, A4)); assert(testSquare(moves, B4)); assert(testSquare(moves, D4)); assert(testSquare(moves, E4)); assert(testSquare(moves, F4)); assert(testSquare(moves, G4)); assert(testSquare(moves, H4)); assert(getNumberOfSetSquares(moves) == 10); moves = getMagicBishopMoves(E5, b); assert(testSquare(moves, D4)); assert(testSquare(moves, C3)); assert(testSquare(moves, D6)); assert(testSquare(moves, C7)); assert(testSquare(moves, B8)); assert(testSquare(moves, F6)); assert(testSquare(moves, F4)); assert(testSquare(moves, G3)); assert(testSquare(moves, H2)); assert(getNumberOfSetSquares(moves) == 9); moves = getMagicQueenMoves(F3, b); assert(testSquare(moves, F2)); assert(testSquare(moves, F1)); assert(testSquare(moves, F4)); assert(testSquare(moves, F5)); assert(testSquare(moves, F6)); assert(testSquare(moves, E3)); assert(testSquare(moves, D3)); assert(testSquare(moves, C3)); assert(testSquare(moves, G3)); assert(testSquare(moves, H3)); assert(testSquare(moves, E4)); assert(testSquare(moves, D5)); assert(testSquare(moves, C6)); assert(testSquare(moves, G4)); assert(testSquare(moves, H5)); assert(testSquare(moves, G2)); assert(testSquare(moves, H1)); assert(testSquare(moves, E2)); assert(testSquare(moves, D1)); assert(getNumberOfSetSquares(moves) == 19); moves = getKnightMoves(A8); assert(testSquare(moves, B6)); assert(testSquare(moves, C7)); assert(getNumberOfSetSquares(moves) == 2); moves = getKnightMoves(E5); assert(testSquare(moves, F7)); assert(testSquare(moves, G6)); assert(testSquare(moves, G4)); assert(testSquare(moves, F3)); assert(testSquare(moves, D3)); assert(testSquare(moves, C4)); assert(testSquare(moves, C6)); assert(testSquare(moves, D7)); assert(getNumberOfSetSquares(moves) == 8); return 0; } static int testPawns() { Bitboard b = EMPTY_BITBOARD, moves, pawns; BYTE obstacles[NUM_LANES]; setSquare(b, B3); setSquare(b, C4); setSquare(b, E4); setSquare(b, F6); setSquare(b, E5); setSquare(b, D6); setSquare(b, G2); setSquare(b, G3); setSquare(b, H2); setSquare(b, H7); calculateObstacles(b, obstacles); moves = getPawnAdvances(WHITE, A2, b); assert(testSquare(moves, A3)); assert(testSquare(moves, A4)); assert(getNumberOfSetSquares(moves) == 2); moves = getPawnAdvances(WHITE, B2, b); assert(getNumberOfSetSquares(moves) == 0); moves = getPawnAdvances(WHITE, C2, b); assert(testSquare(moves, C3)); assert(getNumberOfSetSquares(moves) == 1); moves = getPawnAdvances(BLACK, H7, b); assert(testSquare(moves, H6)); assert(testSquare(moves, H5)); assert(getNumberOfSetSquares(moves) == 2); moves = getPawnAdvances(BLACK, F7, b); assert(getNumberOfSetSquares(moves) == 0); moves = getPawnAdvances(BLACK, E7, b); assert(testSquare(moves, E6)); assert(getNumberOfSetSquares(moves) == 1); moves = getPawnCaptures(WHITE_PAWN, A2, b); assert(testSquare(moves, B3)); assert(getNumberOfSetSquares(moves) == 1); moves = getPawnCaptures(WHITE_PAWN, D3, b); assert(testSquare(moves, C4)); assert(testSquare(moves, E4)); assert(getNumberOfSetSquares(moves) == 2); moves = getPawnCaptures(BLACK_PAWN, G7, b); assert(testSquare(moves, F6)); assert(getNumberOfSetSquares(moves) == 1); moves = getPawnCaptures(BLACK_PAWN, E7, b); assert(testSquare(moves, D6)); assert(testSquare(moves, F6)); assert(getNumberOfSetSquares(moves) == 2); pawns = getInterestedPawns(BLACK, D5, b); assert(testSquare(pawns, D6)); assert(getNumberOfSetSquares(pawns) == 1); pawns = getInterestedPawns(BLACK, H5, b); assert(testSquare(pawns, H7)); assert(testSquare(pawns, H6)); assert(getNumberOfSetSquares(pawns) == 2); pawns = getInterestedPawns(WHITE, H4, b); assert(testSquare(pawns, H2)); assert(testSquare(pawns, H3)); assert(getNumberOfSetSquares(pawns) == 2); pawns = getInterestedPawns(WHITE, G4, b); assert(testSquare(pawns, G3)); assert(getNumberOfSetSquares(pawns) == 1); return 0; } static int testKings() { Bitboard b = EMPTY_BITBOARD, moves; BYTE obstacles[NUM_LANES]; BYTE castlingRights = WHITE_00 | WHITE_000 | BLACK_000 | BLACK_00; moves = getKingMoves(A1); assert(testSquare(moves, B1)); assert(testSquare(moves, B2)); assert(testSquare(moves, A2)); assert(getNumberOfSetSquares(moves) == 3); moves = getKingMoves(D5); assert(testSquare(moves, D6)); assert(testSquare(moves, E6)); assert(testSquare(moves, E5)); assert(testSquare(moves, E4)); assert(testSquare(moves, D4)); assert(testSquare(moves, C4)); assert(testSquare(moves, C5)); assert(testSquare(moves, C6)); assert(getNumberOfSetSquares(moves) == 8); moves = getKingMoves(D5); assert(testSquare(moves, D6)); assert(testSquare(moves, E6)); assert(testSquare(moves, E5)); assert(testSquare(moves, E4)); assert(testSquare(moves, D4)); assert(testSquare(moves, C4)); assert(testSquare(moves, C5)); assert(testSquare(moves, C6)); assert(getNumberOfSetSquares(moves) == 8); calculateObstacles(b, obstacles); moves = getCastlingMoves(WHITE, castlingRights, b); assert(testSquare(moves, G1)); assert(testSquare(moves, C1)); assert(getNumberOfSetSquares(moves) == 2); moves = getCastlingMoves(BLACK, castlingRights, b); assert(testSquare(moves, G8)); assert(testSquare(moves, C8)); assert(getNumberOfSetSquares(moves) == 2); castlingRights = WHITE_00 | BLACK_00; moves = getCastlingMoves(WHITE, castlingRights, b); assert(testSquare(moves, G1)); assert(getNumberOfSetSquares(moves) == 1); moves = getCastlingMoves(BLACK, castlingRights, b); assert(testSquare(moves, G8)); assert(getNumberOfSetSquares(moves) == 1); castlingRights = WHITE_000 | BLACK_000; moves = getCastlingMoves(WHITE, castlingRights, b); assert(testSquare(moves, C1)); assert(getNumberOfSetSquares(moves) == 1); moves = getCastlingMoves(BLACK, castlingRights, b); assert(testSquare(moves, C8)); assert(getNumberOfSetSquares(moves) == 1); castlingRights = WHITE_00 | WHITE_000 | BLACK_000 | BLACK_00; setObstacleSquare(D1, obstacles); setObstacleSquare(D8, obstacles); moves = getCastlingMoves(WHITE, castlingRights, b); assert(testSquare(moves, G1)); assert(getNumberOfSetSquares(moves) == 1); moves = getCastlingMoves(BLACK, castlingRights, b); assert(testSquare(moves, G8)); assert(getNumberOfSetSquares(moves) == 1); clearObstacleSquare(D1, obstacles); clearObstacleSquare(D8, obstacles); moves = getCastlingMoves(WHITE, castlingRights, b); assert(testSquare(moves, G1)); assert(testSquare(moves, C1)); assert(getNumberOfSetSquares(moves) == 2); moves = getCastlingMoves(BLACK, castlingRights, b); assert(testSquare(moves, G8)); assert(testSquare(moves, C8)); assert(getNumberOfSetSquares(moves) == 2); setObstacleSquare(C1, obstacles); setObstacleSquare(C8, obstacles); moves = getCastlingMoves(WHITE, castlingRights, b); assert(testSquare(moves, G1)); assert(getNumberOfSetSquares(moves) == 1); moves = getCastlingMoves(BLACK, castlingRights, b); assert(testSquare(moves, G8)); assert(getNumberOfSetSquares(moves) == 1); clearObstacleSquare(C1, obstacles); clearObstacleSquare(C8, obstacles); setObstacleSquare(F1, obstacles); setObstacleSquare(F8, obstacles); moves = getCastlingMoves(WHITE, castlingRights, b); assert(testSquare(moves, C1)); assert(getNumberOfSetSquares(moves) == 1); moves = getCastlingMoves(BLACK, castlingRights, b); assert(testSquare(moves, C8)); assert(getNumberOfSetSquares(moves) == 1); clearObstacleSquare(F1, obstacles); clearObstacleSquare(F8, obstacles); setObstacleSquare(G1, obstacles); setObstacleSquare(G8, obstacles); moves = getCastlingMoves(WHITE, castlingRights, b); assert(testSquare(moves, C1)); assert(getNumberOfSetSquares(moves) == 1); moves = getCastlingMoves(BLACK, castlingRights, b); assert(testSquare(moves, C8)); assert(getNumberOfSetSquares(moves) == 1); clearObstacleSquare(G1, obstacles); clearObstacleSquare(G8, obstacles); setObstacleSquare(G1, obstacles); setObstacleSquare(G8, obstacles); setObstacleSquare(C1, obstacles); setObstacleSquare(C8, obstacles); moves = getCastlingMoves(WHITE, castlingRights, b); assert(getNumberOfSetSquares(moves) == 0); moves = getCastlingMoves(BLACK, castlingRights, b); assert(getNumberOfSetSquares(moves) == 0); clearObstacleSquare(G1, obstacles); clearObstacleSquare(G8, obstacles); clearObstacleSquare(C1, obstacles); clearObstacleSquare(C8, obstacles); return 0; } static int testFlooding() { Bitboard kingMoves = getKingMoves(D4); Bitboard expected; floodBoard(&kingMoves); expected = squaresBetween[A6][G6] | squaresBetween[A5][G5] | squaresBetween[A4][G4] | squaresBetween[A3][G3] | squaresBetween[A2][G2]; assert(kingMoves == expected); kingMoves = getKingMoves(H1); floodBoard(&kingMoves); expected = squaresBehind[E3][A3] | squaresBehind[E2][A2] | squaresBehind[E1][A1]; assert(kingMoves == expected); kingMoves = getKingMoves(A8); floodBoard(&kingMoves); expected = squaresBehind[D8][H8] | squaresBehind[D7][H7] | squaresBehind[D6][H6]; assert(kingMoves == expected); return 0; } static int testGetSetSquares() { UINT8 moveSquares[_64_]; Bitboard kingMoves = getKingMoves(D4); int numMoves = getSetSquares(kingMoves, moveSquares), i; assert(numMoves == 8); for (i = 0; i < numMoves; i++) { const Square square = (Square) moveSquares[i]; assert(testSquare(kingMoves, square) == TRUE); } return 0; } #endif int testModuleBitboard() { #ifndef NDEBUG int result; if ((result = testBitOperations()) != 0) { return result; } if ((result = testGeneralMoves()) != 0) { return result; } if ((result = testPieces()) != 0) { return result; } if ((result = testPawns()) != 0) { return result; } if ((result = testKings()) != 0) { return result; } if ((result = testFlooding()) != 0) { return result; } if ((result = testGetSetSquares()) != 0) { return result; } #endif return 0; }