Files
cpl_cpp-project/MoveGenerator.cpp
2022-12-23 23:57:29 +01:00

233 lines
8.6 KiB
C++

#include <iostream>
#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(bs, from, movesBB, moves);
} else {
generateMoves(bs, from, movesBB, PieceType::Pawn, 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(bs, from, movesBB, PieceType::Bishop, moves);
}
void
MoveGenerator::generateMoves(const BoardState &bs, const Square &from, BitBoard movesBB, PieceType pt, MoveVec &moves) {
auto fromBB = BitBoard::fromIndex(from.index());
while (movesBB) {
auto to = Square(movesBB.pop());
auto toBB = BitBoard::fromIndex(to.index());
if (isCheck(bs, fromBB, toBB)) {
continue;
}
moves.emplace_back(from, to, score(bs, toBB, pt));
}
}
void
MoveGenerator::generateMovesWithPromotion(const BoardState &bs, const Square &from, BitBoard movesBB, MoveVec &moves) {
auto fromBB = BitBoard::fromIndex(from.index());
while (movesBB) {
auto to = Square(movesBB.pop());
auto toBB = BitBoard::fromIndex(to.index());
if (isCheck(bs, fromBB, toBB)) {
continue;
}
for (const auto &kItem: Piece::PromotionTypes) {
unsigned s = Piece::PromotionScore[Board::toIndex(kItem) - 2] + score(bs, toBB, PieceType::Pawn);
moves.emplace_back(from, to, static_cast<PieceType>(kItem), s);
}
}
}
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(bs, from, movesBB, PieceType::King, 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(bs, from, movesBB, PieceType::Rook, 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(bs, from, movesBB, PieceType::Queen, 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(bs, from, movesBB, PieceType::Knight, 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;
}
inline bool MoveGenerator::isCheck(const BoardState &bs, const BitBoard &fromBB, const BitBoard &toBB) {
auto kingBB = (*bs.pieceBBs)[Board::toIndex(bs.turn)] & (*bs.pieceBBs)[Board::toIndex(PieceType::King)];
auto changeBB = (fromBB ^ toBB);
auto target = bs.occupiedBB ^ changeBB;
if (kingBB & fromBB) {
if (toBB & bs.occupiedBB) {
target ^= toBB;
}
if ((toBB & ~bs.occupiedBB)) {
kingBB ^= changeBB;
}
}
auto attacked = generateAttackedSquares(bs, ~target, !bs.turn);
return attacked & kingBB;
}
inline unsigned MoveGenerator::score(const BoardState &bs, const BitBoard &toBB, const PieceType moved) {
unsigned score = 0;
auto opponentBB = bs.occupiedBB & ~(*bs.pieceBBs)[Board::toIndex(bs.turn)];
// Check Capture
auto captureBB = toBB & opponentBB;
if (captureBB) {
auto captured = bs.pieceType(captureBB);
score = Piece::MVV_LVA[Board::toIndex(captured)][Board::toIndex(moved)];
}
return score;
}
unsigned MoveGenerator::Mobility(const BoardState &bs, PieceColor color) {
unsigned count = 0;
auto colorMask = (*bs.pieceBBs)[Board::toIndex(color)];
auto targets = (*bs.pieceBBs)[Board::toIndex(!color)];
// Pawns
auto pawnsBB = (*bs.pieceBBs)[Board::toIndex(PieceType::Pawn)] & colorMask;
if (color == PieceColor::White) {
auto movesBB = BitBoard::pawnNorthAttacks(pawnsBB, targets) & ~colorMask;
movesBB |= BitBoard::pawnNorthMoves(pawnsBB, ~bs.occupiedBB);
count += movesBB.count();
} else {
auto movesBB = BitBoard::pawnSouthAttacks(pawnsBB, targets) & ~colorMask;
movesBB |= BitBoard::pawnSouthMoves(pawnsBB, ~bs.occupiedBB);
count += movesBB.count();
}
// Bishops
count += (BitBoard::bishopAttacks((*bs.pieceBBs)[Board::toIndex(PieceType::Bishop)] & colorMask, ~bs.occupiedBB) &
~colorMask).count();
// Knights
count += (BitBoard::knightMoves((*bs.pieceBBs)[Board::toIndex(PieceType::Knight)] & colorMask) &
~colorMask).count();
// Rook
count += (BitBoard::rookAttacks((*bs.pieceBBs)[Board::toIndex(PieceType::Rook)] & colorMask, ~bs.occupiedBB) &
~colorMask).count();
// Queen
count += (BitBoard::queenAttacks((*bs.pieceBBs)[Board::toIndex(PieceType::Queen)] & colorMask, ~bs.occupiedBB) &
~colorMask).count();
// King
count += (BitBoard::kingMoves((*bs.pieceBBs)[Board::toIndex(PieceType::King)] & colorMask) & ~colorMask).count();
return count;
}