#ifndef CHESSY_BITBOARD_H #define CHESSY_BITBOARD_H #include "BitOperations.h" #include #include #include namespace chessy { enum PieceType : char; struct Index; struct Move; struct Bitboard; using Side = int; const Side WHITE_SIDE = 0; const Side BLACK_SIDE = 1; inline constexpr Side otherSide(Side side) { return !side; } } enum chessy::PieceType : char { EMPTY = -1, PAWN = 0, KNIGHT = 1, BISHOP = 2, ROOK = 3, QUEEN = 4, KING = 5, }; /*! * data structure to index one field on a chess board */ struct chessy::Index { int8_t index; Index(void) = default; inline constexpr Index(int8_t ind) : index{ ind } {} inline Index(const std::string& name) : Index{ name[1] - '1', name[0] - 'a' } {} inline constexpr Index(int row, int column) : index{int8_t(((row & 0x7) << 3) + (column & 0x7))} {} inline operator int8_t (void) const { return index; } inline int getColumn (void) const { return index & 0x7; } inline int getRow (void) const { return (index >> 3) & 0x7; } inline std::string getName(void) const { return { char('a' + getColumn()), char(getRow() + '1') }; } }; /*! * data structure that holds a simple move */ struct chessy::Move { Index origin; Index destination; //! If the move is a promotion move, this field stores //! the type of the resulting piece. //! If this field is equal to PieceType::PAWN, //! it is indicated, that no promotion happened. PieceType promotion; bool isCastling; Move (void) = default; Move (const Move&) = default; Move (Move&&) = default; ~Move (void) = default; Move& operator= (const Move&) = default; Move& operator= (Move&&) = default; inline Move(const std::string& move) : promotion{ PieceType::PAWN }, isCastling{ false } { if (move.length() < 4) return; origin = Index { move.substr(0, 2) }; destination = Index { move.substr(2, 2) }; if (move.length() > 4) { switch (move[4]) { case 'n': promotion = PieceType::KNIGHT; break; case 'b': promotion = PieceType::BISHOP; break; case 'r': promotion = PieceType::ROOK; break; case 'q': promotion = PieceType::QUEEN; break; } } } inline Move(Index origin, Index destination) : origin{ origin }, destination{ destination }, promotion{ PieceType::PAWN }, isCastling{ false } {} inline Move(Index origin, Index destination, PieceType promotion) : origin{ origin }, destination{ destination }, promotion{ promotion }, isCastling{ false } {} inline Move(Index origin, Index destination, bool isCastling) : origin{ origin }, destination{ destination }, promotion{ PieceType::PAWN }, isCastling{ isCastling } {} inline std::string asString(void) const { return origin.getName() + destination.getName() + (promotion == PieceType::KNIGHT ? "n" : "") + (promotion == PieceType::BISHOP ? "b" : "") + (promotion == PieceType::ROOK ? "r" : "") + (promotion == PieceType::QUEEN ? "q" : ""); } }; struct chessy::Bitboard { U64 bits; Bitboard (void) = default; Bitboard (const Bitboard&) = default; Bitboard (Bitboard&&) = default; ~Bitboard (void) = default; Bitboard& operator= (const Bitboard&) = default; Bitboard& operator= (Bitboard&&) = default; inline constexpr Bitboard(U64 bits) : bits{ bits } {} inline static Bitboard fromIndex(Index i) { return U64(1) << i; } inline void setBit (Index i) { bits |= U64(1) << i.index; } inline void unsetBit (Index i) { bits |= ~(U64(1) << i.index); } inline void toggleBit (Index i) { bits ^= U64(1) << i.index; } inline void setBit (int row, int column) { setBit(row * 8 + column); } inline void unsetBit (int row, int column) { unsetBit(row * 8 + column); } static const U64 hColumn = 0x0101010101010101ULL; static const U64 aColumn = 0x8080808080808080ULL; inline void moveNorth (int dist) { bits <<= (8 * dist); } inline Bitboard north (int dist) { return bits << (8 * dist); } inline void moveSouth (int dist) { bits >>= (8 * dist); } inline Bitboard south (int dist) { return bits >> (8 * dist); } inline void moveNorthOne(void) { bits <<= 8; } inline Bitboard northOne (void) { return bits << 8; } inline void moveSouthOne(void) { bits >>= 8; } inline Bitboard southOne (void) { return bits >> 8; } inline void moveEastOne (void) { bits = (bits & ~hColumn) >> 1; } inline Bitboard eastOne (void) { return (bits & ~hColumn) >> 1; } inline void moveWestOne (void) { bits = (bits & ~aColumn) << 1; } inline Bitboard westOne (void) { return (bits & ~aColumn) << 1; } inline void moveNWOne (void) { bits = (bits << 7) & ~aColumn; } inline Bitboard nwOne (void) { return (bits << 7) & ~aColumn; } inline void moveNEOne (void) { bits = (bits << 9) & ~hColumn; } inline Bitboard neOne (void) { return (bits << 9) & ~hColumn; } inline void moveSWOne (void) { bits = (bits >> 9) & ~aColumn; } inline Bitboard swOne (void) { return (bits >> 9) & ~aColumn; } inline void moveSEOne (void) { bits = (bits >> 7) & ~hColumn; } inline Bitboard seOne (void) { return (bits >> 7) & ~hColumn; } inline static Bitboard getColumn(int index) { return hColumn << index; } inline static Bitboard getRow(int index) { return 0xFFULL << (index * 8); } template inline void pushOne(void) { if (side == WHITE_SIDE) moveNorthOne(); else moveSouthOne(); } inline void operator &= (const Bitboard& b) { bits &= b.bits; } inline void operator |= (const Bitboard& b) { bits |= b.bits; } inline void operator ^= (const Bitboard& b) { bits ^= b.bits; } inline Bitboard operator & (const Bitboard& b) const { return bits & b.bits; } inline Bitboard operator | (const Bitboard& b) const { return bits | b.bits; } inline Bitboard operator ^ (const Bitboard& b) const { return bits ^ b.bits; } inline Bitboard operator ~ (void) const { return ~bits; } inline bool operator == (const Bitboard& b) const { return bits == b.bits; } inline bool operator != (const Bitboard& b) const { return bits != b.bits; } inline operator U64(void) const { return bits; } inline explicit operator bool(void) const { return bits != 0; } inline void applyMove(Move move) { bits &= ~fromIndex(move.origin); bits |= fromIndex(move.destination); } inline Bitboard mirror(void) const { return byteswap(bits); } inline Index getLeastSignificantBit (void) const { return trailingZeroes(bits); } inline int popcount (void) const { return chessy::popcount(bits); } static const uint64_t aFile = 0x8080808080808080ULL; static const uint64_t hFile = 0x0101010101010101ULL; }; static_assert(std::is_pod::value, "chessy::Bitboard should be a POD structure."); static_assert(std::is_pod::value, "chessy::Index should be a POD structure."); static_assert(sizeof(chessy::Bitboard) == sizeof(uint64_t), "chessy::Bitboard should be 64 bits in size."); #endif // CHESSY_BITBOARD_H