diff --git a/Board.cpp b/Board.cpp index 20467e6..744c6d2 100644 --- a/Board.cpp +++ b/Board.cpp @@ -1,4 +1,5 @@ #include "Board.hpp" +#include "BoardState.hpp" #include #include @@ -7,9 +8,6 @@ #include #include -Board::Board() { -} - void Board::setPiece(const Square &square, const Piece::Optional &piece) { if (!piece.has_value()) return; @@ -21,12 +19,12 @@ void Board::setPiece(const Square &square, const Piece::Optional &piece) { mPieceBBs[toIndex(piece->type())].set(index); mPieceBBs[toIndex(piece->color())].set(index); - (*mOccupiedBB).set(index); + mOccupiedBB.set(index); } Piece::Optional Board::piece(const Square &square) const { BitBoard mask = BitBoard::fromIndex(square.index()); - if (!(*mOccupiedBB & mask)) { + if (!(mOccupiedBB & mask)) { return std::nullopt; } @@ -68,17 +66,17 @@ void Board::makeMove(const Move &move) { BitBoard changeBB = fromBB ^ toBB; // If Piece is captured - if (*mOccupiedBB & toBB) { + if (mOccupiedBB & toBB) { auto capturedPiece = Piece(!mTurn, pieceType(toBB)); mPieceBBs[toIndex(capturedPiece.color())] ^= toBB; mPieceBBs[toIndex(capturedPiece.type())] ^= toBB; - *mOccupiedBB ^= fromBB; + mOccupiedBB ^= fromBB; if (toBB & CastlingRanks) { // Check castling rights handleCastlingRights(capturedPiece, toBB); } } else { - *mOccupiedBB ^= changeBB; // update occupied bitboard + mOccupiedBB ^= changeBB; // update occupied bitboard } auto movedPiece = Piece(mTurn, pieceType(fromBB)); @@ -105,7 +103,7 @@ void Board::makeMove(const Move &move) { mPieceBBs[toIndex(PieceType::Rook)] ^= rookBB; mPieceBBs[toIndex(movedPiece.color())] ^= rookBB; - *mOccupiedBB ^= rookBB; + mOccupiedBB ^= rookBB; } } @@ -124,7 +122,7 @@ void Board::handleEnPassant(const Move &move, const Piece &movedPiece) { mPieceBBs[toIndex(capturedPiece.color())] ^= epBB; mPieceBBs[toIndex(capturedPiece.type())] ^= epBB; - *mOccupiedBB ^= epBB; + mOccupiedBB ^= epBB; } } @@ -156,28 +154,22 @@ void Board::pseudoLegalMovesFrom(const Square &from, Board::MoveVec &moves) cons return; } + BoardState bs = BoardState(&mPieceBBs, mOccupiedBB, mTurn, mCR, mEPS); auto p = Piece(mTurn, pieceType(fromBB)); BitBoard movesBB; switch (p.type()) { - case PieceType::Pawn:mMoveGenerator->generatePawnMoves(from, mEPS, mTurn, moves); + case PieceType::Pawn: MoveGenerator::generatePawnMoves(bs, from, mEPS, mTurn, moves); return; case PieceType::Knight: break; - case PieceType::Bishop:movesBB = BitBoard::bishopAttacks(fromBB, ~*mOccupiedBB) & ~mPieceBBs[toIndex(mTurn)]; - break; - case PieceType::Rook: break; - case PieceType::Queen: break; + case PieceType::Bishop: MoveGenerator::generateBishopMoves(bs, from, mTurn, moves); + return; + case PieceType::Rook: MoveGenerator::generateRookMoves(bs, from, mTurn, moves); + return; + case PieceType::Queen: MoveGenerator::generateQueenMoves(bs, from, mTurn, moves); + return; - case PieceType::King:movesBB = BitBoard::kingAttacks(fromBB) & ~mPieceBBs[toIndex(mTurn)]; - if (hasCastlingRights()) { - if (mTurn == PieceColor::White) { - movesBB |= BitBoard::castlingMoves(fromBB, ~mPieceBBs[toIndex(PieceType::Rook)], ~*mOccupiedBB) - & WhiteCastlingRank; - } else { - movesBB |= BitBoard::castlingMoves(fromBB, ~mPieceBBs[toIndex(PieceType::Rook)], ~*mOccupiedBB) - & BlackCastlingRank; - } - } + case PieceType::King: MoveGenerator::generateKingMoves(bs, from, mTurn, mCR, moves); break; } @@ -233,14 +225,6 @@ bool Board::isMoveCastling(const BitBoard &from, const BitBoard &to, const Piece return from & BitBoard::fromIndex(E8); } -constexpr bool Board::hasCastlingRights() const { - switch (mTurn) { - case PieceColor::White:return (mCR & CastlingRights::White) != CastlingRights::None; - case PieceColor::Black:return (mCR & CastlingRights::Black) != CastlingRights::None; - } - - return false; -} std::ostream &operator<<(std::ostream &os, const Board &board) { // For debugging only, performance isn't important diff --git a/Board.hpp b/Board.hpp index 01715f0..91b0189 100644 --- a/Board.hpp +++ b/Board.hpp @@ -11,7 +11,6 @@ #include #include #include -#include #define BB_NUM 8 // 6 pieces, 2 colors @@ -21,7 +20,11 @@ public: using Optional = std::optional; using MoveVec = std::vector; - Board(); + Board() = default; + Board(const Board &) = default; + Board(Board &&other) = default; + Board &operator=(const Board &) = default; + Board &operator=(Board &&) = default; void setPiece(const Square &square, const Piece::Optional &piece); Piece::Optional piece(const Square &square) const; @@ -46,18 +49,15 @@ public: private: - std::shared_ptr mPieceBBs = std::shared_ptr(new BitBoard[BB_NUM]); -// BitBoard mPieceBBs[BB_NUM] = {}; - std::shared_ptr mOccupiedBB = std::make_shared(0); + BitBoard mPieceBBs[BB_NUM] = {}; + BitBoard mOccupiedBB = BitBoard(0); - std::shared_ptr mMoveGenerator = std::make_shared(mPieceBBs, mOccupiedBB); - - PieceColor mTurn = PieceColor::White; + PieceColor mTurn = PieceColor(PieceColor::White); CastlingRights mCR = CastlingRights::None; std::optional mEPS; void handleCastlingRights(const Piece &piece, const BitBoard &bb); - constexpr bool hasCastlingRights() const; + // Check if the move is castling without checking the rights or validity. static bool isMoveCastling(const BitBoard &from, const BitBoard &to, const Piece &piece); @@ -86,5 +86,4 @@ private: }; std::ostream &operator<<(std::ostream &os, const Board &board); - #endif diff --git a/BoardState.hpp b/BoardState.hpp new file mode 100644 index 0000000..9421fd8 --- /dev/null +++ b/BoardState.hpp @@ -0,0 +1,29 @@ +#ifndef CHESS_ENGINE_BOARDSTATE_HPP +#define CHESS_ENGINE_BOARDSTATE_HPP + +#include "Piece.hpp" +#include "BitBoard.hpp" +#include "Board.hpp" + +struct BoardState { + BoardState(const BitBoard (*const pieceBBs)[8], + const BitBoard occupiedBB, + const PieceColor turn, + const CastlingRights cr, + const std::optional eps) + : pieceBBs(pieceBBs), + occupiedBB(occupiedBB), + turn(turn), + cr(cr), + eps(eps) { + + } + + const BitBoard (*const pieceBBs)[8]; + const BitBoard occupiedBB; + const PieceColor turn; + const CastlingRights cr; + const std::optional eps; +}; + +#endif //CHESS_ENGINE_BOARDSTATE_HPP diff --git a/CMakeLists.txt b/CMakeLists.txt index 491d0c1..f7979ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ add_library(cplchess_lib OBJECT Uci.cpp BitBoard.cpp MoveGenerator.cpp -) + BoardState.hpp) target_include_directories(cplchess_lib PUBLIC .) diff --git a/MoveGenerator.cpp b/MoveGenerator.cpp index 40c0dcc..5fe10ab 100644 --- a/MoveGenerator.cpp +++ b/MoveGenerator.cpp @@ -1,39 +1,34 @@ -#include #include "MoveGenerator.hpp" #include "Board.hpp" +#include "BoardState.hpp" -MoveGenerator::MoveGenerator(const std::shared_ptr &pieceBB, - const std::shared_ptr &occupiedBB) - : mPieceBBs(pieceBB), mOccupiedBB(occupiedBB) { -} - -void MoveGenerator::generatePawnMoves(const Square &from, const std::optional &eps, - PieceColor color, MoveVec &moves) const { +void MoveGenerator::generatePawnMoves(const BoardState &bs, const Square &from, const std::optional &eps, + PieceColor color, MoveVec &moves) { BitBoard targets = 0; if (eps.has_value()) { targets |= BitBoard::fromIndex(eps.value().index()); } - generatePawnMoves(from, targets, color, moves); + generatePawnMoves(bs, from, targets, color, moves); } -void MoveGenerator::generatePawnMoves(const Square &from, PieceColor color, MoveVec &moves) { - generatePawnMoves(from, BitBoard(0), color, moves); +void MoveGenerator::generatePawnMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves) { + generatePawnMoves(bs, from, BitBoard(0), color, moves); } -void MoveGenerator::generatePawnMoves(const Square &from, BitBoard targets, PieceColor color, MoveVec &moves) const { +void MoveGenerator::generatePawnMoves(const BoardState &bs, const Square &from, BitBoard targets, PieceColor color, MoveVec &moves) { auto fromBB = BitBoard::fromIndex(from.index()); - targets |= mPieceBBs[Board::toIndex(!color)]; + targets |= *bs.pieceBBs[Board::toIndex(!color)]; BitBoard movesBB; if (color == PieceColor::White) { - movesBB = BitBoard::pawnNorthAttacks(fromBB, targets) & ~mPieceBBs[Board::toIndex(color)]; - movesBB |= BitBoard::pawnNorthMoves(fromBB, ~*mOccupiedBB); + movesBB = BitBoard::pawnNorthAttacks(fromBB, targets) & ~*bs.pieceBBs[Board::toIndex(color)]; + movesBB |= BitBoard::pawnNorthMoves(fromBB, ~bs.occupiedBB); } else { - movesBB = BitBoard::pawnSouthAttacks(fromBB, targets) & ~mPieceBBs[Board::toIndex(color)]; - movesBB |= BitBoard::pawnSouthMoves(fromBB, ~*mOccupiedBB); + movesBB = BitBoard::pawnSouthAttacks(fromBB, targets) & ~*bs.pieceBBs[Board::toIndex(color)]; + movesBB |= BitBoard::pawnSouthMoves(fromBB, ~bs.occupiedBB); } bool isPromotion = movesBB & (Rank1 | Rank8); @@ -44,14 +39,21 @@ void MoveGenerator::generatePawnMoves(const Square &from, BitBoard targets, Piec } } -void MoveGenerator::generateMoves(const Square &from, BitBoard movesBB, MoveGenerator::MoveVec &moves) { +void MoveGenerator::generateBishopMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves) { + auto fromBB = BitBoard::fromIndex(from.index()); + auto movesBB = BitBoard::bishopAttacks(fromBB, ~bs.occupiedBB) & ~*bs.pieceBBs[Board::toIndex(color)]; + + generateMoves(from, movesBB, moves); +} + +void MoveGenerator::generateMoves(const Square &from, BitBoard movesBB, MoveVec &moves) { while (movesBB) { auto to = Square(movesBB.pop()); moves.emplace_back(from, to, std::nullopt); } } -void MoveGenerator::generateMovesWithPromotion(const Square &from, BitBoard movesBB, MoveGenerator::MoveVec &moves) { +void MoveGenerator::generateMovesWithPromotion(const Square &from, BitBoard movesBB, MoveVec &moves) { while (movesBB) { auto to = Square(movesBB.pop()); for (const auto &kItem : Piece::PromotionTypes) { @@ -59,4 +61,62 @@ void MoveGenerator::generateMovesWithPromotion(const Square &from, BitBoard move } } } +void MoveGenerator::generateKingMoves(const BoardState &bs, const Square &from, + PieceColor color, + CastlingRights cr, + MoveGenerator::MoveVec &moves) { + auto fromBB = BitBoard::fromIndex(from.index()); + auto movesBB = BitBoard::kingAttacks(fromBB) & ~*bs.pieceBBs[Board::toIndex(color)]; + + if ((cr & CastlingRights::All) != CastlingRights::None) { + + auto checkCR = CastlingRights::White; + auto castlingRank = WhiteCastlingRank; + if (color == PieceColor::Black) { + checkCR = CastlingRights::Black; + castlingRank = BlackCastlingRank; + } + + checkCR &= cr; + + if (checkCR != CastlingRights::None) { + // Generate attacked squares + auto opponentBB = *bs.pieceBBs[Board::toIndex(!color)]; + BitBoard target = CastlingRanks | bs.occupiedBB; + // pawns + BitBoard attacked = 0; + if (!color == PieceColor::White) { + attacked |= BitBoard::pawnNorthAttacks(*bs.pieceBBs[Board::toIndex(PieceType::Pawn)] & opponentBB, target); + } else { + attacked |= BitBoard::pawnSouthAttacks(*bs.pieceBBs[Board::toIndex(PieceType::Pawn)] & opponentBB, target); + } + + movesBB |= BitBoard::castlingMoves(fromBB, *bs.pieceBBs[Board::toIndex(PieceType::Rook)], ~bs.occupiedBB) + & castlingRank;// & ~attacked; + + if ((checkCR & CastlingRights::KingSide) == CastlingRights::None) { + movesBB &= ~GFile; + } + if ((checkCR & CastlingRights::QueenSide) == CastlingRights::None) { + movesBB &= ~CFile; + } + } + } + + generateMoves(from, movesBB, moves); +} + +void MoveGenerator::generateRookMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves) { + auto fromBB = BitBoard::fromIndex(from.index()); + auto movesBB = BitBoard::rookAttacks(fromBB, ~bs.occupiedBB) & ~*bs.pieceBBs[Board::toIndex(color)]; + + generateMoves(from, movesBB, moves); +} + +void MoveGenerator::generateQueenMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves) { + auto fromBB = BitBoard::fromIndex(from.index()); + auto movesBB = BitBoard::queenAttacks(fromBB, ~bs.occupiedBB) & ~*bs.pieceBBs[Board::toIndex(color)]; + + generateMoves(from, movesBB, moves); +} diff --git a/MoveGenerator.hpp b/MoveGenerator.hpp index c9ae940..829e63c 100644 --- a/MoveGenerator.hpp +++ b/MoveGenerator.hpp @@ -6,6 +6,7 @@ #include "Move.hpp" #include "CastlingRights.hpp" #include "BitBoard.hpp" +#include "BoardState.hpp" #include #include @@ -16,18 +17,18 @@ class MoveGenerator { public: using MoveVec = std::vector; - MoveGenerator(const std::shared_ptr& pieceBB, const std::shared_ptr& occupiedBB); - MoveGenerator(MoveGenerator &) = delete; - MoveGenerator &operator=(MoveGenerator const &) = delete; - - void generatePawnMoves(const Square &from, const std::optional &eps, PieceColor color, MoveVec &moves) const; - void generatePawnMoves(const Square &from, PieceColor color, MoveVec &moves); + static void generatePawnMoves(const BoardState &bs, const Square &from, + const std::optional &eps, + PieceColor color, + MoveVec &moves); + static void generatePawnMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves); + static void generateBishopMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves); + static void generateKingMoves(const BoardState &bs, const Square &from, PieceColor color, CastlingRights cr, MoveVec &moves); + static void generateRookMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves); + static void generateQueenMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves); private: - const std::shared_ptr mPieceBBs; - const std::shared_ptr mOccupiedBB; - - void generatePawnMoves(const Square &from, BitBoard targets, PieceColor color, MoveVec &moves) const; + static void generatePawnMoves(const BoardState &bs, const Square &from, BitBoard targets, PieceColor color, MoveVec &moves); static void generateMoves(const Square &from, BitBoard movesBB, MoveVec &moves); static void generateMovesWithPromotion(const Square &from, BitBoard movesBB, MoveVec &moves);