Remove pointers, add BoardState

This commit is contained in:
2022-12-22 22:54:26 +01:00
parent 71d90918b3
commit 8d028ba087
6 changed files with 146 additions and 73 deletions

View File

@@ -1,4 +1,5 @@
#include "Board.hpp" #include "Board.hpp"
#include "BoardState.hpp"
#include <ostream> #include <ostream>
#include <cassert> #include <cassert>
@@ -7,9 +8,6 @@
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
Board::Board() {
}
void Board::setPiece(const Square &square, const Piece::Optional &piece) { void Board::setPiece(const Square &square, const Piece::Optional &piece) {
if (!piece.has_value()) if (!piece.has_value())
return; return;
@@ -21,12 +19,12 @@ void Board::setPiece(const Square &square, const Piece::Optional &piece) {
mPieceBBs[toIndex(piece->type())].set(index); mPieceBBs[toIndex(piece->type())].set(index);
mPieceBBs[toIndex(piece->color())].set(index); mPieceBBs[toIndex(piece->color())].set(index);
(*mOccupiedBB).set(index); mOccupiedBB.set(index);
} }
Piece::Optional Board::piece(const Square &square) const { Piece::Optional Board::piece(const Square &square) const {
BitBoard mask = BitBoard::fromIndex(square.index()); BitBoard mask = BitBoard::fromIndex(square.index());
if (!(*mOccupiedBB & mask)) { if (!(mOccupiedBB & mask)) {
return std::nullopt; return std::nullopt;
} }
@@ -68,17 +66,17 @@ void Board::makeMove(const Move &move) {
BitBoard changeBB = fromBB ^ toBB; BitBoard changeBB = fromBB ^ toBB;
// If Piece is captured // If Piece is captured
if (*mOccupiedBB & toBB) { if (mOccupiedBB & toBB) {
auto capturedPiece = Piece(!mTurn, pieceType(toBB)); auto capturedPiece = Piece(!mTurn, pieceType(toBB));
mPieceBBs[toIndex(capturedPiece.color())] ^= toBB; mPieceBBs[toIndex(capturedPiece.color())] ^= toBB;
mPieceBBs[toIndex(capturedPiece.type())] ^= toBB; mPieceBBs[toIndex(capturedPiece.type())] ^= toBB;
*mOccupiedBB ^= fromBB; mOccupiedBB ^= fromBB;
if (toBB & CastlingRanks) { // Check castling rights if (toBB & CastlingRanks) { // Check castling rights
handleCastlingRights(capturedPiece, toBB); handleCastlingRights(capturedPiece, toBB);
} }
} else { } else {
*mOccupiedBB ^= changeBB; // update occupied bitboard mOccupiedBB ^= changeBB; // update occupied bitboard
} }
auto movedPiece = Piece(mTurn, pieceType(fromBB)); auto movedPiece = Piece(mTurn, pieceType(fromBB));
@@ -105,7 +103,7 @@ void Board::makeMove(const Move &move) {
mPieceBBs[toIndex(PieceType::Rook)] ^= rookBB; mPieceBBs[toIndex(PieceType::Rook)] ^= rookBB;
mPieceBBs[toIndex(movedPiece.color())] ^= 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.color())] ^= epBB;
mPieceBBs[toIndex(capturedPiece.type())] ^= 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; return;
} }
BoardState bs = BoardState(&mPieceBBs, mOccupiedBB, mTurn, mCR, mEPS);
auto p = Piece(mTurn, pieceType(fromBB)); auto p = Piece(mTurn, pieceType(fromBB));
BitBoard movesBB; BitBoard movesBB;
switch (p.type()) { switch (p.type()) {
case PieceType::Pawn:mMoveGenerator->generatePawnMoves(from, mEPS, mTurn, moves); case PieceType::Pawn: MoveGenerator::generatePawnMoves(bs, from, mEPS, mTurn, moves);
return; return;
case PieceType::Knight: break; case PieceType::Knight: break;
case PieceType::Bishop:movesBB = BitBoard::bishopAttacks(fromBB, ~*mOccupiedBB) & ~mPieceBBs[toIndex(mTurn)]; case PieceType::Bishop: MoveGenerator::generateBishopMoves(bs, from, mTurn, moves);
break; return;
case PieceType::Rook: break; case PieceType::Rook: MoveGenerator::generateRookMoves(bs, from, mTurn, moves);
case PieceType::Queen: break; return;
case PieceType::Queen: MoveGenerator::generateQueenMoves(bs, from, mTurn, moves);
return;
case PieceType::King:movesBB = BitBoard::kingAttacks(fromBB) & ~mPieceBBs[toIndex(mTurn)]; case PieceType::King: MoveGenerator::generateKingMoves(bs, from, mTurn, mCR, moves);
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;
}
}
break; break;
} }
@@ -233,14 +225,6 @@ bool Board::isMoveCastling(const BitBoard &from, const BitBoard &to, const Piece
return from & BitBoard::fromIndex(E8); 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) { std::ostream &operator<<(std::ostream &os, const Board &board) {
// For debugging only, performance isn't important // For debugging only, performance isn't important

View File

@@ -11,7 +11,6 @@
#include <optional> #include <optional>
#include <iosfwd> #include <iosfwd>
#include <vector> #include <vector>
#include <memory>
#define BB_NUM 8 // 6 pieces, 2 colors #define BB_NUM 8 // 6 pieces, 2 colors
@@ -21,7 +20,11 @@ public:
using Optional = std::optional<Board>; using Optional = std::optional<Board>;
using MoveVec = std::vector<Move>; using MoveVec = std::vector<Move>;
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); void setPiece(const Square &square, const Piece::Optional &piece);
Piece::Optional piece(const Square &square) const; Piece::Optional piece(const Square &square) const;
@@ -46,18 +49,15 @@ public:
private: private:
std::shared_ptr<BitBoard[BB_NUM]> mPieceBBs = std::shared_ptr<BitBoard[BB_NUM]>(new BitBoard[BB_NUM]); BitBoard mPieceBBs[BB_NUM] = {};
// BitBoard mPieceBBs[BB_NUM] = {}; BitBoard mOccupiedBB = BitBoard(0);
std::shared_ptr<BitBoard> mOccupiedBB = std::make_shared<BitBoard>(0);
std::shared_ptr<MoveGenerator> mMoveGenerator = std::make_shared<MoveGenerator>(mPieceBBs, mOccupiedBB); PieceColor mTurn = PieceColor(PieceColor::White);
PieceColor mTurn = PieceColor::White;
CastlingRights mCR = CastlingRights::None; CastlingRights mCR = CastlingRights::None;
std::optional<Square> mEPS; std::optional<Square> mEPS;
void handleCastlingRights(const Piece &piece, const BitBoard &bb); void handleCastlingRights(const Piece &piece, const BitBoard &bb);
constexpr bool hasCastlingRights() const;
// Check if the move is castling without checking the rights or validity. // Check if the move is castling without checking the rights or validity.
static bool isMoveCastling(const BitBoard &from, const BitBoard &to, const Piece &piece); 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); std::ostream &operator<<(std::ostream &os, const Board &board);
#endif #endif

29
BoardState.hpp Normal file
View File

@@ -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<Square> 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<Square> eps;
};
#endif //CHESS_ENGINE_BOARDSTATE_HPP

View File

@@ -37,7 +37,7 @@ add_library(cplchess_lib OBJECT
Uci.cpp Uci.cpp
BitBoard.cpp BitBoard.cpp
MoveGenerator.cpp MoveGenerator.cpp
) BoardState.hpp)
target_include_directories(cplchess_lib PUBLIC .) target_include_directories(cplchess_lib PUBLIC .)

View File

@@ -1,39 +1,34 @@
#include <iostream>
#include "MoveGenerator.hpp" #include "MoveGenerator.hpp"
#include "Board.hpp" #include "Board.hpp"
#include "BoardState.hpp"
MoveGenerator::MoveGenerator(const std::shared_ptr<BitBoard[]> &pieceBB,
const std::shared_ptr<BitBoard> &occupiedBB)
: mPieceBBs(pieceBB), mOccupiedBB(occupiedBB) {
} void MoveGenerator::generatePawnMoves(const BoardState &bs, const Square &from, const std::optional<Square> &eps,
PieceColor color, MoveVec &moves) {
void MoveGenerator::generatePawnMoves(const Square &from, const std::optional<Square> &eps,
PieceColor color, MoveVec &moves) const {
BitBoard targets = 0; BitBoard targets = 0;
if (eps.has_value()) { if (eps.has_value()) {
targets |= BitBoard::fromIndex(eps.value().index()); 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) { void MoveGenerator::generatePawnMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves) {
generatePawnMoves(from, BitBoard(0), color, 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()); auto fromBB = BitBoard::fromIndex(from.index());
targets |= mPieceBBs[Board::toIndex(!color)]; targets |= *bs.pieceBBs[Board::toIndex(!color)];
BitBoard movesBB; BitBoard movesBB;
if (color == PieceColor::White) { if (color == PieceColor::White) {
movesBB = BitBoard::pawnNorthAttacks(fromBB, targets) & ~mPieceBBs[Board::toIndex(color)]; movesBB = BitBoard::pawnNorthAttacks(fromBB, targets) & ~*bs.pieceBBs[Board::toIndex(color)];
movesBB |= BitBoard::pawnNorthMoves(fromBB, ~*mOccupiedBB); movesBB |= BitBoard::pawnNorthMoves(fromBB, ~bs.occupiedBB);
} else { } else {
movesBB = BitBoard::pawnSouthAttacks(fromBB, targets) & ~mPieceBBs[Board::toIndex(color)]; movesBB = BitBoard::pawnSouthAttacks(fromBB, targets) & ~*bs.pieceBBs[Board::toIndex(color)];
movesBB |= BitBoard::pawnSouthMoves(fromBB, ~*mOccupiedBB); movesBB |= BitBoard::pawnSouthMoves(fromBB, ~bs.occupiedBB);
} }
bool isPromotion = movesBB & (Rank1 | Rank8); 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) { while (movesBB) {
auto to = Square(movesBB.pop()); auto to = Square(movesBB.pop());
moves.emplace_back(from, to, std::nullopt); 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) { while (movesBB) {
auto to = Square(movesBB.pop()); auto to = Square(movesBB.pop());
for (const auto &kItem : Piece::PromotionTypes) { 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);
}

View File

@@ -6,6 +6,7 @@
#include "Move.hpp" #include "Move.hpp"
#include "CastlingRights.hpp" #include "CastlingRights.hpp"
#include "BitBoard.hpp" #include "BitBoard.hpp"
#include "BoardState.hpp"
#include <optional> #include <optional>
#include <iosfwd> #include <iosfwd>
@@ -16,18 +17,18 @@ class MoveGenerator {
public: public:
using MoveVec = std::vector<Move>; using MoveVec = std::vector<Move>;
MoveGenerator(const std::shared_ptr<BitBoard[]>& pieceBB, const std::shared_ptr<BitBoard>& occupiedBB); static void generatePawnMoves(const BoardState &bs, const Square &from,
MoveGenerator(MoveGenerator &) = delete; const std::optional<Square> &eps,
MoveGenerator &operator=(MoveGenerator const &) = delete; PieceColor color,
MoveVec &moves);
void generatePawnMoves(const Square &from, const std::optional<Square> &eps, PieceColor color, MoveVec &moves) const; static void generatePawnMoves(const BoardState &bs, const Square &from, PieceColor color, MoveVec &moves);
void generatePawnMoves(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: private:
const std::shared_ptr<const BitBoard[]> mPieceBBs; static void generatePawnMoves(const BoardState &bs, const Square &from, BitBoard targets, PieceColor color, MoveVec &moves);
const std::shared_ptr<const BitBoard> mOccupiedBB;
void generatePawnMoves(const Square &from, BitBoard targets, PieceColor color, MoveVec &moves) const;
static void generateMoves(const Square &from, BitBoard movesBB, MoveVec &moves); static void generateMoves(const Square &from, BitBoard movesBB, MoveVec &moves);
static void generateMovesWithPromotion(const Square &from, BitBoard movesBB, MoveVec &moves); static void generateMovesWithPromotion(const Square &from, BitBoard movesBB, MoveVec &moves);