#include "MoveGenerator.hpp" #include "Board.hpp" #include "BoardState.hpp" void MoveGenerator::generatePawnMoves(const BoardState &bs, const Square &from, MoveVec &moves) { BitBoard targets = 0; if (bs.eps.has_value()) { targets |= BitBoard::fromIndex(bs.eps.value().index()); } generatePawnMoves(bs, from, targets, moves); } void MoveGenerator::generatePawnMoves(const BoardState &bs, const Square &from, BitBoard targets, MoveVec &moves) { auto fromBB = BitBoard::fromIndex(from.index()); targets |= (*bs.pieceBBs)[Board::toIndex(!bs.turn)]; BitBoard movesBB; if (bs.turn == PieceColor::White) { movesBB = BitBoard::pawnNorthAttacks(fromBB, targets) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)]; movesBB |= BitBoard::pawnNorthMoves(fromBB, ~bs.occupiedBB); } else { movesBB = BitBoard::pawnSouthAttacks(fromBB, targets) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)]; movesBB |= BitBoard::pawnSouthMoves(fromBB, ~bs.occupiedBB); } bool isPromotion = movesBB & (Rank1 | Rank8); if (isPromotion) { generateMovesWithPromotion(from, movesBB, moves); } else { generateMoves(from, movesBB, moves); } } void MoveGenerator::generateBishopMoves(const BoardState &bs, const Square &from, MoveVec &moves) { auto fromBB = BitBoard::fromIndex(from.index()); auto movesBB = BitBoard::bishopAttacks(fromBB, ~bs.occupiedBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)]; 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, MoveVec &moves) { while (movesBB) { auto to = Square(movesBB.pop()); for (const auto &kItem : Piece::PromotionTypes) { moves.emplace_back(from, to, static_cast(kItem)); } } } void MoveGenerator::generateKingMoves(const BoardState &bs, const Square &from, MoveGenerator::MoveVec &moves) { auto fromBB = BitBoard::fromIndex(from.index()); auto movesBB = BitBoard::kingMoves(fromBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)]; if ((bs.cr & CastlingRights::All) != CastlingRights::None) { auto checkCR = CastlingRights::White; auto castlingRank = WhiteCastlingRank; if (bs.turn == PieceColor::Black) { checkCR = CastlingRights::Black; castlingRank = BlackCastlingRank; } checkCR &= bs.cr; if (checkCR != CastlingRights::None) { // Generate attacked squares BitBoard target = CastlingRanks | bs.occupiedBB; auto attacked = generateAttackedSquares(bs, target, !bs.turn); movesBB |= BitBoard::castlingMoves(fromBB & ~attacked, (*bs.pieceBBs)[Board::toIndex(PieceType::Rook)], ~bs.occupiedBB) & castlingRank; 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, MoveVec &moves) { auto fromBB = BitBoard::fromIndex(from.index()); auto movesBB = BitBoard::rookAttacks(fromBB, ~bs.occupiedBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)]; generateMoves(from, movesBB, moves); } void MoveGenerator::generateQueenMoves(const BoardState &bs, const Square &from, MoveVec &moves) { auto fromBB = BitBoard::fromIndex(from.index()); auto movesBB = BitBoard::queenAttacks(fromBB, ~bs.occupiedBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)]; generateMoves(from, movesBB, moves); } void MoveGenerator::generateKnightMoves(const BoardState &bs, const Square &from, MoveVec &moves) { auto fromBB = BitBoard::fromIndex(from.index()); auto movesBB = BitBoard::knightMoves(fromBB) & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)]; generateMoves(from, movesBB, moves); } BitBoard MoveGenerator::generateAttackedSquares(const BoardState &bs, BitBoard target, PieceColor opColor) { auto opponentBB = (*bs.pieceBBs)[Board::toIndex(opColor)]; BitBoard attacked = 0; // pawns if (opColor == 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); } // knights attacked |= BitBoard::knightMoves((*bs.pieceBBs)[Board::toIndex(PieceType::Knight)] & opponentBB) & target; // Bishop attacked |= BitBoard::bishopAttacks((*bs.pieceBBs)[Board::toIndex(PieceType::Bishop)] & opponentBB, target); // Rook attacked |= BitBoard::rookAttacks((*bs.pieceBBs)[Board::toIndex(PieceType::Rook)] & opponentBB, target); // Queen attacked |= BitBoard::queenAttacks((*bs.pieceBBs)[Board::toIndex(PieceType::Queen)] & opponentBB, target); // King attacked |= BitBoard::kingMoves((*bs.pieceBBs)[Board::toIndex(PieceType::Queen)] & opponentBB) & target; return attacked; }