/* Protector -- a UCI chess engine Copyright (C) 2009-2010 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 . */ #ifndef _bitboard_h_ #define _bitboard_h_ #include "protector.h" #include #ifdef TARGET_WINDOWS #include #endif typedef UINT64 Bitboard; #define EMPTY_BITBOARD ULONG_ZERO #define IMAX_ROOK 4096 #define IMAX_BISHOP 512 typedef struct { int hLane, vLane, uLane, dLane; BYTE hLaneSetMask, vLaneSetMask, uLaneSetMask, dLaneSetMask; BYTE hLaneClearMask, vLaneClearMask, uLaneClearMask, dLaneClearMask; } SquareLaneInfo; typedef struct { int numSetSquares; UINT8 setSquares[16]; } SetSquaresInfo; typedef struct { int hLaneNumber, vLaneNumber, uLaneNumber, dLaneNumber; Bitboard hLane[256], vLane[256], uLane[256], dLane[256]; } ObstacleSquareInfo; typedef struct { Bitboard preMask, magicNumber; Bitboard moves[IMAX_ROOK]; } MagicSquareInfoRook; typedef struct { Bitboard preMask, magicNumber; Bitboard moves[IMAX_BISHOP]; } MagicSquareInfoBishop; #define SLI(square) (squareLaneInfo[(square)]) extern UINT64 minValue[_64_]; extern UINT64 maxValue[_64_]; extern INT8 highestBit[0x10000]; extern Bitboard hlane[_64_][256]; extern Bitboard vlane[_64_][256]; extern Bitboard ulane[_64_][256]; extern Bitboard dlane[_64_][256]; extern ObstacleSquareInfo obsi[_64_]; extern Bitboard castlings[2][16][256]; extern int castlingLane[2]; extern int castlingsOfColor[2]; extern SquareLaneInfo squareLaneInfo[_64_]; extern Bitboard generalMoves[0x0f][_64_]; extern Bitboard squaresOfFile[8]; extern Bitboard squaresOfRank[8]; extern Bitboard squaresOfLateralFiles[8]; extern Bitboard squaresOfFileRange[8][8]; extern Bitboard squaresOfRankRange[8][8]; extern Bitboard pawnMoves[2][_64_][256]; extern Bitboard promotionCandidates[2]; extern SetSquaresInfo setSquares[4][0x10000]; extern INT8 numSetBits[0x10000]; extern UINT8 rankOverlay[0x10000]; extern UINT8 bitshiftGap[8][256]; extern Bitboard squaresBehind[_64_][_64_]; extern Bitboard squaresBetween[_64_][_64_]; extern Bitboard squaresInDistance[8][_64_]; extern Bitboard squaresInTaxiDistance[15][_64_]; extern Bitboard squaresAbove[2][_64_]; extern Bitboard squaresBelow[2][_64_]; extern Bitboard orthoKingAttackers[_64_]; extern Bitboard diaKingAttackers[_64_]; extern Bitboard knightKingAttackers[_64_]; extern Bitboard pawnKingAttackers[2][_64_]; extern Bitboard interestedPawns[2][_64_][256]; extern Bitboard nonA, nonH, border, center, lightSquares, darkSquares, queenSide, kingSide, centerFiles, extendedCenter; extern int hLaneNumber[_64_], vLaneNumber[_64_]; extern int uLaneNumber[_64_], dLaneNumber[_64_]; extern Bitboard preMaskRook[64], preMaskBishop[64]; extern Bitboard magicRookMoves[64][IMAX_ROOK]; extern Bitboard magicBishopMoves[64][IMAX_BISHOP]; extern const Bitboard magicRookNumber[64]; extern const Bitboard magicBishopNumber[64]; extern MagicSquareInfoRook magicSquareInfoRook[64]; extern MagicSquareInfoBishop magicSquareInfoBishop[64]; #define setSquare(bitboard,square) ((bitboard) |= minValue[(square)]); #define clearSquare(bitboard,square) ((bitboard) &= maxValue[(square)]); #define excludeSquares(bitboard,toBeExcluded) ((bitboard) &= ~(toBeExcluded)) INLINE bool testSquare(const Bitboard bitboard, const Square square) { return (bool) (((bitboard) & minValue[(square)]) != EMPTY_BITBOARD); } /** * Get the king moves for the specified square. */ INLINE Bitboard getKingMoves(const Square square) { return generalMoves[KING][square]; } /** * Get castling moves depending from the castling rights and * the current position. */ INLINE Bitboard getCastlingMoves(const Color color, const BYTE castlingRights, const Bitboard obstacles) { if (color == WHITE) { return castlings[WHITE][castlingRights][obstacles & 0xFF]; } else { return castlings[BLACK][castlingRights][obstacles >> 56]; } } /** * Get the queen moves for the specified square. */ /* INLINE Bitboard getQueenMoves(const Square square, const BYTE * obstacles) { const ObstacleSquareInfo *_obsi = &obsi[square]; return _obsi->hLane[obstacles[_obsi->hLaneNumber]] | _obsi->vLane[obstacles[_obsi->vLaneNumber]] | _obsi->uLane[obstacles[_obsi->uLaneNumber]] | _obsi->dLane[obstacles[_obsi->dLaneNumber]]; } */ INLINE int getWidth(const Bitboard set) { if (set == EMPTY_BITBOARD) { return 0; } else { File leftMost = FILE_A, rightMost = FILE_H; while ((set & squaresOfFile[leftMost]) == EMPTY_BITBOARD) { leftMost++; } while ((set & squaresOfFile[rightMost]) == EMPTY_BITBOARD) { rightMost--; } return rightMost - leftMost; } } /** * Get the queen moves for the specified square. */ INLINE Bitboard getMagicQueenMoves(const Square square, const Bitboard obstacles) { MagicSquareInfoRook *msir = &magicSquareInfoRook[square]; MagicSquareInfoBishop *msib = &magicSquareInfoBishop[square]; return msir->moves[((obstacles & msir->preMask) * msir->magicNumber) >> 52] | msib->moves[((obstacles & msib->preMask) * msib->magicNumber) >> 55]; } /** * Get the rook moves for the specified square. */ INLINE Bitboard getRookMoves(const Square square, const BYTE * obstacles) { const ObstacleSquareInfo *_obsi = &obsi[square]; return _obsi->hLane[obstacles[_obsi->hLaneNumber]] | _obsi->vLane[obstacles[_obsi->vLaneNumber]]; } /** * Get the rook moves for the specified square. */ INLINE Bitboard getMagicRookMoves(const Square square, const Bitboard obstacles) { MagicSquareInfoRook *msir = &magicSquareInfoRook[square]; return msir->moves[((obstacles & msir->preMask) * msir->magicNumber) >> 52]; } /** * Get the bishop moves for the specified square. */ INLINE Bitboard getBishopMoves(const Square square, const BYTE * obstacles) { const ObstacleSquareInfo *_obsi = &obsi[square]; return _obsi->uLane[obstacles[_obsi->uLaneNumber]] | _obsi->dLane[obstacles[_obsi->dLaneNumber]]; } /** * Get the bishop moves for the specified square. */ INLINE Bitboard getMagicBishopMoves(const Square square, const Bitboard obstacles) { MagicSquareInfoBishop *msib = &magicSquareInfoBishop[square]; return msib->moves[((obstacles & msib->preMask) * msib->magicNumber) >> 55]; } /** * Get the knight moves for the specified square. */ INLINE Bitboard getKnightMoves(const Square square) { return generalMoves[KNIGHT][square]; } /** * Get the pawn captures for the specified square. */ INLINE Bitboard getPawnCaptures(const Piece piece, const Square square, const Bitboard allPieces) { return generalMoves[piece][square] & allPieces; } /** * Get the pawn advances for the specified square. */ INLINE Bitboard getPawnAdvances(const Color color, const Square square, const Bitboard obstacles) { Bitboard advances; if (color == WHITE) { advances = (minValue[square] << 8) & ~obstacles; if (rank(square) == RANK_2) { advances |= (advances << 8) & ~obstacles; } } else { advances = (minValue[square] >> 8) & ~obstacles; if (rank(square) == RANK_7) { advances |= (advances >> 8) & ~obstacles; } } return advances; } /** * Get the pawns interested in advancing to the specified square. */ INLINE Bitboard getInterestedPawns(const Color color, const Square square, const Bitboard obstacles) { Bitboard interestedPawns; if (color == WHITE) { interestedPawns = minValue[square] >> 8; if (rank(square) == RANK_4 && (interestedPawns & obstacles) == EMPTY_BITBOARD) { interestedPawns = minValue[square] >> 16; } } else { interestedPawns = minValue[square] << 8; if (rank(square) == RANK_5 && (interestedPawns & obstacles) == EMPTY_BITBOARD) { interestedPawns = minValue[square] << 16; } } return interestedPawns; } /** * Get the squares between the two specified squares. */ INLINE Bitboard getSquaresBetween(const Square square1, const Square square2) { return squaresBetween[square1][square2]; } /** * Get the squares behind 'target', as seen from 'viewpoint'. */ INLINE Bitboard getSquaresBehind(const Square target, const Square viewpoint) { return squaresBehind[target][viewpoint]; } /** * Shift all set squares one file to the left. */ INLINE Bitboard shiftLeft(const Bitboard bitboard) { return (bitboard & nonA) >> 1; } /** * Shift all set squares one file to the right. */ INLINE Bitboard shiftRight(const Bitboard bitboard) { return (bitboard & nonH) << 1; } /** * Get all squares lateral to the specified squares. */ INLINE Bitboard getLateralSquares(const Bitboard squares) { return ((squares & nonA) >> 1) | ((squares & nonH) << 1); } /** * Get the squares of the specified file. */ INLINE Bitboard getSquaresOfFile(const File file) { return squaresOfFile[file]; } /** * Get the squares of the specified rank. */ INLINE Bitboard getSquaresOfRank(const Rank rank) { return squaresOfRank[rank]; } #ifdef TARGET_WINDOWS #define UHEX_FFFF 0xFFFFui64 #endif #ifdef TARGET_LINUX #define UHEX_FFFF 0xFFFFllu #endif /** * Get the number of set squares in the specified bitboard. */ INLINE int getNumberOfSetSquares(const Bitboard bitboard) { return numSetBits[bitboard & UHEX_FFFF] + numSetBits[(bitboard >> 16) & UHEX_FFFF] + numSetBits[(bitboard >> 32) & UHEX_FFFF] + numSetBits[(bitboard >> 48) & UHEX_FFFF]; } /** * Get the rank overlay of the specified bitboard. */ INLINE int getRankOverlay(const Bitboard bitboard) { return rankOverlay[(bitboard) & UHEX_FFFF] | rankOverlay[(bitboard >> 16) & UHEX_FFFF] | rankOverlay[(bitboard >> 32) & UHEX_FFFF] | rankOverlay[(bitboard >> 48) & UHEX_FFFF]; } /** * The number of lanes used to hold information * about the state of all files, rows and diagonals */ #define NUM_LANES 46 /** * Get the moves of the the specified piece. */ INLINE Bitboard getMoves(Square square, Piece piece, Bitboard allPieces) { switch (pieceType(piece)) { case PAWN: return getPawnCaptures(piece, square, allPieces) | getPawnAdvances(pieceColor(piece), square, allPieces); case KING: return getKingMoves(square); case KNIGHT: return getKnightMoves(square); case ROOK: return getMagicRookMoves(square, allPieces); case BISHOP: return getMagicBishopMoves(square, allPieces); default: return getMagicQueenMoves(square, allPieces); } } /** * Set a square in the specified vector of obstacles. */ INLINE void setObstacleSquare(Square square, BYTE obstacles[NUM_LANES]) { SquareLaneInfo *sqi = &squareLaneInfo[square]; obstacles[sqi->hLane] |= sqi->hLaneSetMask; obstacles[sqi->vLane] |= sqi->vLaneSetMask; obstacles[sqi->uLane] |= sqi->uLaneSetMask; obstacles[sqi->dLane] |= sqi->dLaneSetMask; } /** * Clear a square in the specified vector of obstacles. */ INLINE void clearObstacleSquare(Square square, BYTE obstacles[NUM_LANES]) { SquareLaneInfo *sqi = &squareLaneInfo[square]; obstacles[sqi->hLane] &= sqi->hLaneClearMask; obstacles[sqi->vLane] &= sqi->vLaneClearMask; obstacles[sqi->uLane] &= sqi->uLaneClearMask; obstacles[sqi->dLane] &= sqi->dLaneClearMask; } /** * Calculate all obstacles according to the specified bitboard. */ INLINE void calculateObstacles(Bitboard board, BYTE obstacles[NUM_LANES]) { Square square; memset(obstacles, 0x00, NUM_LANES); ITERATE(square) { if (board & minValue[square]) { setObstacleSquare(square, obstacles); } } } /** * Initialize this module. * * @return 0 if no errors occurred. */ int initializeModuleBitboard(void); /** * Test this module. * * @return 0 if all tests succeed. */ int testModuleBitboard(void); /** * Get the number of a set square and clear the corresponding bit. * * @return NO_SQUARE if no square was set. */ INLINE Square getNextSquare(Bitboard * vector); /** * Extend all set bits by one square into all directions. */ INLINE void floodBoard(Bitboard * board); /** * Get the targets of all pawns specified by 'whitePawns'. */ INLINE Bitboard getWhitePawnTargets(const Bitboard whitePawns) { return ((whitePawns & nonA) << 7) | ((whitePawns & nonH) << 9); } /** * Get the targets of all pawns specified by 'blackPawns'. */ INLINE Bitboard getBlackPawnTargets(const Bitboard blackPawns) { return ((blackPawns & nonA) >> 9) | ((blackPawns & nonH) >> 7); } /** * Iteration shortcuts */ #define ITERATE_BITBOARD(b,sq) while ( ( sq = getNextSquare(b) ) >= 0 ) INLINE void floodBoard(Bitboard * board) { const Bitboard toLeft = *board & nonA, toRight = *board & nonH; *board = (toLeft >> 1) | (toLeft << 7) | (*board >> 8) | (toLeft >> 9) | (toRight << 1) | (toRight >> 7) | (*board << 8) | (toRight << 9); } #ifdef TARGET_WINDOWS #define UHEX_FFFFffff00000000 0xFFFFffff00000000ui64 #define UHEX_00000000FFFF0000 0x00000000FFFF0000ui64 #define UHEX_FFFF000000000000 0xFFFF000000000000ui64 #define UHEX_00000000FFFFffff 0x00000000FFFFffffui64 #endif #ifdef TARGET_LINUX #define UHEX_FFFFffff00000000 0xFFFFffff00000000llu #define UHEX_00000000FFFF0000 0x00000000FFFF0000llu #define UHEX_FFFF000000000000 0xFFFF000000000000llu #define UHEX_00000000FFFFffff 0x00000000FFFFffffllu #endif #ifdef WIN64 INLINE Square getNextSquare(Bitboard * vector) { unsigned long index; if (_BitScanReverse64(&index, *vector)) { _bittestandreset64((__int64 *) vector, index); return (Square) index; } else { return NO_SQUARE; } } #else #if !defined NDEBUG || defined TARGET_LINUX INLINE Square getNextSquare(Bitboard * vector) { Square nextSquare; if ((*vector & UHEX_FFFFffff00000000) == ULONG_ZERO) { if ((*vector & UHEX_00000000FFFF0000) == ULONG_ZERO) { if ((nextSquare = (Square) highestBit[(int) *vector]) >= 0) { *vector &= maxValue[nextSquare]; } return nextSquare; } else { nextSquare = (Square) (highestBit[(int) (*vector >> 16)] + 16); *vector &= maxValue[nextSquare]; return nextSquare; } } else { if ((*vector & UHEX_FFFF000000000000) == ULONG_ZERO) { nextSquare = (Square) (highestBit[(int) (*vector >> 32)] + 32); *vector &= maxValue[nextSquare]; return nextSquare; } else { nextSquare = (Square) (highestBit[(int) (*vector >> 48)] + 48); *vector &= maxValue[nextSquare]; return nextSquare; } } } #else INLINE Square getNextSquare(Bitboard * vector) { unsigned long index; if (*vector > UHEX_00000000FFFFffff) { unsigned long *uw = ((unsigned long *) (vector)) + 1; _BitScanReverse(&index, *uw); _bittestandreset((long *) uw, index); return (Square) index + 32; } else { if (_BitScanReverse(&index, (unsigned long) *vector)) { _bittestandreset((long *) vector, index); return (Square) index; } else { return NO_SQUARE; } } } #endif #endif INLINE int getSetSquares(const Bitboard board, UINT8 squares[_64_]) { int index; UINT8 *currentSquare = &squares[0]; if ((index = (int) (0xFFFF & board)) != 0) { const SetSquaresInfo *info = &setSquares[0][index]; memcpy(currentSquare, info->setSquares, info->numSetSquares); currentSquare += info->numSetSquares; } if ((index = (int) (0xFFFF & (board >> 16))) != 0) { const SetSquaresInfo *info = &setSquares[1][index]; memcpy(currentSquare, info->setSquares, info->numSetSquares); currentSquare += info->numSetSquares; } if ((index = (int) (0xFFFF & (board >> 32))) != 0) { const SetSquaresInfo *info = &setSquares[2][index]; memcpy(currentSquare, info->setSquares, info->numSetSquares); currentSquare += info->numSetSquares; } if ((index = (int) (board >> 48)) != 0) { const SetSquaresInfo *info = &setSquares[3][index]; memcpy(currentSquare, info->setSquares, info->numSetSquares); currentSquare += info->numSetSquares; } return (int) (currentSquare - &squares[0]); } INLINE Bitboard getMultipleSquaresBetween(const Square origin, Bitboard targets) { Bitboard squares = targets; Square targetSquare; Bitboard *sqb = &(squaresBetween[origin][0]); ITERATE_BITBOARD(&targets, targetSquare) { squares |= sqb[targetSquare]; } return squares; } unsigned int getMinimumDistance(const Bitboard targets, const Square square); unsigned int getMaximumDistance(const Bitboard targets, const Square square); int getFloodValue(const Square origin, const Bitboard targets, const Bitboard permittedSquares); #endif