Compare commits
2 Commits
256b511569
...
8d028ba087
Author | SHA1 | Date | |
---|---|---|---|
8d028ba087 | |||
71d90918b3 |
50
Board.cpp
50
Board.cpp
@@ -1,4 +1,5 @@
|
||||
#include "Board.hpp"
|
||||
#include "BoardState.hpp"
|
||||
|
||||
#include <ostream>
|
||||
#include <cassert>
|
||||
@@ -7,9 +8,6 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
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
|
||||
|
19
Board.hpp
19
Board.hpp
@@ -11,7 +11,6 @@
|
||||
#include <optional>
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#define BB_NUM 8 // 6 pieces, 2 colors
|
||||
|
||||
@@ -21,7 +20,11 @@ public:
|
||||
using Optional = std::optional<Board>;
|
||||
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);
|
||||
Piece::Optional piece(const Square &square) const;
|
||||
@@ -46,18 +49,15 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<BitBoard[BB_NUM]> mPieceBBs = std::shared_ptr<BitBoard[BB_NUM]>(new BitBoard[BB_NUM]);
|
||||
// BitBoard mPieceBBs[BB_NUM] = {};
|
||||
std::shared_ptr<BitBoard> mOccupiedBB = std::make_shared<BitBoard>(0);
|
||||
BitBoard mPieceBBs[BB_NUM] = {};
|
||||
BitBoard mOccupiedBB = BitBoard(0);
|
||||
|
||||
std::shared_ptr<MoveGenerator> mMoveGenerator = std::make_shared<MoveGenerator>(mPieceBBs, mOccupiedBB);
|
||||
|
||||
PieceColor mTurn = PieceColor::White;
|
||||
PieceColor mTurn = PieceColor(PieceColor::White);
|
||||
CastlingRights mCR = CastlingRights::None;
|
||||
std::optional<Square> 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
|
||||
|
29
BoardState.hpp
Normal file
29
BoardState.hpp
Normal 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
|
@@ -37,7 +37,7 @@ add_library(cplchess_lib OBJECT
|
||||
Uci.cpp
|
||||
BitBoard.cpp
|
||||
MoveGenerator.cpp
|
||||
)
|
||||
BoardState.hpp)
|
||||
|
||||
target_include_directories(cplchess_lib PUBLIC .)
|
||||
|
||||
|
@@ -11,6 +11,8 @@ enum class CastlingRights {
|
||||
BlackQueenside = 1 << 3,
|
||||
White = WhiteKingside | WhiteQueenside,
|
||||
Black = BlackKingside | BlackQueenside,
|
||||
KingSide = BlackKingside | WhiteKingside,
|
||||
QueenSide = BlackQueenside | WhiteQueenside,
|
||||
All = White | Black
|
||||
};
|
||||
|
||||
|
@@ -1,39 +1,34 @@
|
||||
#include <iostream>
|
||||
#include "MoveGenerator.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 Square &from, const std::optional<Square> &eps,
|
||||
PieceColor color, MoveVec &moves) const {
|
||||
void MoveGenerator::generatePawnMoves(const BoardState &bs, const Square &from, const std::optional<Square> &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);
|
||||
}
|
||||
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#include "Move.hpp"
|
||||
#include "CastlingRights.hpp"
|
||||
#include "BitBoard.hpp"
|
||||
#include "BoardState.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <iosfwd>
|
||||
@@ -16,18 +17,18 @@ class MoveGenerator {
|
||||
public:
|
||||
using MoveVec = std::vector<Move>;
|
||||
|
||||
MoveGenerator(const std::shared_ptr<BitBoard[]>& pieceBB, const std::shared_ptr<BitBoard>& occupiedBB);
|
||||
MoveGenerator(MoveGenerator &) = delete;
|
||||
MoveGenerator &operator=(MoveGenerator const &) = delete;
|
||||
|
||||
void generatePawnMoves(const Square &from, const std::optional<Square> &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<Square> &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<const BitBoard[]> mPieceBBs;
|
||||
const std::shared_ptr<const BitBoard> 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);
|
||||
|
Reference in New Issue
Block a user