diff --git a/include/bitbishop/moves/bishop_move_gen.hpp b/include/bitbishop/moves/bishop_move_gen.hpp deleted file mode 100644 index 0bc64f3..0000000 --- a/include/bitbishop/moves/bishop_move_gen.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once -#include -#include -#include -#include - -/** - * @brief Generates bishop moves. - * - * Bishop can move diagonally in the four directions (NE, NW, SE, SW) until a friendly or enemy piece - * is encountered. - * This namespace provides functions for generating both pseudo-legal and legal bishop moves. - */ -namespace BishopMoveGenerator { - -/** - * @brief Generates all pseudo-legal bishop moves for a given side. - * - * Pseudo-legal moves follow piece movement rules but may leave the king in check. - * These moves must be validated separately to ensure legality. - * - * @param moves Vector to append generated moves to - * @param board Current board state - * @param side Color of the side to generate moves for - */ -void generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side); - -}; // namespace BishopMoveGenerator diff --git a/include/bitbishop/moves/king_move_gen.hpp b/include/bitbishop/moves/king_move_gen.hpp deleted file mode 100644 index cb2cab3..0000000 --- a/include/bitbishop/moves/king_move_gen.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -/** - * @brief Generates king moves. - * - * The king can move one square in any direction (horizontally, vertically, or diagonally). - * This namespace provides functions for generating both pseudo-legal and legal king moves, - * including castling moves. - */ -namespace KingMoveGenerator { - -/** - * @brief Generates all pseudo-legal king moves for a given side. - * - * Pseudo-legal moves follow piece movement rules but may leave the king in check. - * These moves must be validated separately to ensure legality. - * - * @param moves Vector to append generated moves to - * @param board Current board state - * @param side Color of the side to generate moves for - */ -void generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side); - -/** - * @brief Generates all legal king moves for a given side. - * - * Legal moves are pseudo-legal moves that have been validated to ensure - * the king is not left in check after the move. - * - * @param moves Vector to append generated moves to - * @param board Current board state - * @param side Color of the side to generate moves for - */ -void generate_legal_moves(std::vector& moves, const Board& board, Color side); - -/** - * @brief Adds castling moves to the move list if conditions are met. - * - * Validates castling legality and adds both kingside and queenside castling - * moves when available. Castling requires that the king and rook haven't moved, - * squares between them are empty, and the king doesn't move through check. - * - * @param moves Vector to append castling moves to - * @param from Square the king is currently on - * @param side Color of the side attempting to castle - * @param board Current board state - * - * @see https://www.chess.com/article/view/how-to-castle-in-chess - */ -void add_king_castling(std::vector& moves, Square from, Color side, const Board& board); - -}; // namespace KingMoveGenerator diff --git a/include/bitbishop/moves/knight_move_gen.hpp b/include/bitbishop/moves/knight_move_gen.hpp deleted file mode 100644 index 968cc74..0000000 --- a/include/bitbishop/moves/knight_move_gen.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include -#include - -/** - * @brief Generates knight moves. - * - * Knights can move in an 'L' shape. - * This namespace provides functions for generating both pseudo-legal and legal knights moves. - */ -namespace KnightMoveGenerator { - -/** - * @brief Generates all pseudo-legal knights moves for a given side. - * - * Pseudo-legal moves follow piece movement rules but may leave the king in check. - * These moves must be validated separately to ensure legality. - * - * @param moves Vector to append generated moves to - * @param board Current board state - * @param side Color of the side to generate moves for - */ -void generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side); - -} // namespace KnightMoveGenerator diff --git a/include/bitbishop/moves/pawn_move_gen.hpp b/include/bitbishop/moves/pawn_move_gen.hpp deleted file mode 100644 index 7f370b9..0000000 --- a/include/bitbishop/moves/pawn_move_gen.hpp +++ /dev/null @@ -1,202 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -/** - * @brief Generates pawn moves including pushes, captures, promotions, and en passant. - * - * Pawns have unique movement rules in chess: - * - Move forward one square (or two squares from starting position) - * - Capture diagonally forward one square - * - Promote to Queen, Rook, Bishop, or Knight when reaching the opposite end - * - Can capture en passant under specific conditions - */ -namespace PawnMoveGenerator { - -constexpr std::array WHITE_PROMOTIONS = {Pieces::WHITE_QUEEN, Pieces::WHITE_ROOK, Pieces::WHITE_BISHOP, - Pieces::WHITE_KNIGHT}; -constexpr std::array BLACK_PROMOTIONS = {Pieces::BLACK_QUEEN, Pieces::BLACK_ROOK, Pieces::BLACK_BISHOP, - Pieces::BLACK_KNIGHT}; - -/** - * @brief Generates all pseudo-legal pawn moves for a given side. - * - * Pseudo-legal moves follow piece movement rules but may leave the king in check. - * These moves must be validated separately to ensure legality. - * - * @param moves Vector to append generated moves to - * @param board Current board state - * @param side Color of the side to generate moves for - */ -void generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side); - -/** - * @brief Generates all legal pawn moves for a given side. - * - * Legal moves are pseudo-legal moves that have been validated to ensure - * the king is not left in check after the move. - * - * @param moves Vector to append generated moves to - * @param board Current board state - * @param side Color of the side to generate moves for - */ -void generate_legal_moves(std::vector& moves, const Board& board, Color side); - -/** - * @brief Adds all four promotion moves (Queen, Rook, Bishop, Knight) to the move list. - * - * When a pawn reaches the opposite end of the board (rank 8 for White, rank 1 for Black), - * it must promote to another piece. This function adds all four possible promotions - * for a single pawn move. - * - * @param moves Vector to append promotion moves to - * @param from Source square of the promoting pawn - * @param to Destination square (must be on the promotion rank) - * @param side Color of the promoting pawn - * @param is_capture Whether the promotion involves capturing an enemy piece - */ -void add_pawn_promotions(std::vector& moves, Square from, Square to, Color side, bool is_capture); - -/** - * @brief Checks if a square is on the pawn's starting rank. - * - * Pawns start on rank 2 (index 1) for White and rank 7 (index 6) for Black. - * This is used to determine if a pawn is eligible to perform a double push. - * - * @param square Square to check - * @param color Color of the pawn - * @return true if the square is on the starting rank for the given color, false otherwise - */ -constexpr bool is_starting_rank(Square square, Color color) { - using namespace Const; - return color == Color::WHITE ? (square.rank() == RANK_2_IND) : (square.rank() == RANK_7_IND); -} - -/** - * @brief Checks if a square is on the pawn's promotion rank. - * - * Pawns promote when reaching rank 8 (index 7) for White or rank 1 (index 0) for Black. - * - * @param square Square to check - * @param color Color of the pawn - * @return true if the square is on the promotion rank for the given color, false otherwise - */ -constexpr bool is_promotion_rank(Square square, Color color) { - using namespace Const; - return color == Color::WHITE ? (square.rank() == RANK_8_IND) : (square.rank() == RANK_1_IND); -} - -/** - * @brief Validates if an en passant capture is geometrically legal. - * - * En passant geometry is valid when: - * - The capturing pawn is on rank 5 for White (index 4) or rank 4 for Black (index 3) - * - The en passant target square is exactly one file adjacent (horizontally) - * - The en passant target square is on rank 6 for White (index 5) or rank 3 for Black (index 2) - * - * Note: This only checks geometric validity. The caller must separately verify that - * en passant is actually available (i.e., an enemy pawn just performed a double push - * to the square behind the target square). - * - * @param from Square of the capturing pawn - * @param epsq Available en passant target square - * @param side Color of the capturing pawn - * @return true if the capture geometry is valid for en passant, false otherwise - */ -constexpr bool can_capture_en_passant(Square from, Square epsq, Color side) noexcept { - using namespace Const; - - // MSVC have not yet made std::abs() constexpr for C++ 23, forcing us to define a generic constexpr one... - // For this, lets apply the abs() function manually. This is sad, but you know, MSVC... - // The code should not adapt to the compiler for the same language, the compiler should... - int dif = from.file() - epsq.file(); - dif = (dif < 0) ? -dif : dif; - - if (dif != 1) { - return false; - } - if (side == Color::WHITE && from.rank() == RANK_5_IND && epsq.rank() == RANK_6_IND) { - return true; - } - if (side == Color::BLACK && from.rank() == RANK_4_IND && epsq.rank() == RANK_3_IND) { - return true; - } - return false; -} - -/** - * @brief Returns pre-computed single push destinations for all squares. - * - * For each of the 64 squares, provides a bitboard with the destination square - * if a pawn of the given color pushes forward one rank (White moves up/+1, Black moves down/-1). - * - * Note: This returns theoretical destinations regardless of board occupancy. - * The caller must verify that the destination square is empty before making the move. - * - * @param side Color of the pawns - * @return Array of 64 bitboards indexed by source square, each containing the single push destination - */ -constexpr std::array single_push(Color side) { - switch (side) { - case Color::WHITE: - return Lookups::WHITE_PAWN_SINGLE_PUSH; - case Color::BLACK: - return Lookups::BLACK_PAWN_SINGLE_PUSH; - } - std::unreachable(); -} - -/** - * @brief Returns pre-computed double push destinations for all squares. - * - * For each of the 64 squares, provides a bitboard with the destination square - * if a pawn of the given color pushes forward two ranks from its starting position - * (White: rank 2 to rank 4, Black: rank 7 to rank 5). - * - * Note: This returns theoretical destinations. The caller must verify: - * - The pawn is on its starting rank - * - Both the intermediate square and the destination square are empty - * - * @param side Color of the pawns - * @return Array of 64 bitboards indexed by source square, each containing the double push destination - */ -constexpr std::array double_push(Color side) { - switch (side) { - case Color::WHITE: - return Lookups::WHITE_PAWN_DOUBLE_PUSH; - case Color::BLACK: - return Lookups::BLACK_PAWN_DOUBLE_PUSH; - } - std::unreachable(); -} - -/** - * @brief Returns pre-computed diagonal capture destinations for all squares. - * - * For each of the 64 squares, provides a bitboard with all squares a pawn of the - * given color could potentially capture to (one square diagonally forward-left and - * forward-right). - * - * Note: This returns theoretical capture squares regardless of board occupancy. - * The caller must verify that an enemy piece or en passant target actually occupies - * the destination square. - * - * @param side Color of the pawns - * @return Array of 64 bitboards indexed by source square, each containing the diagonal capture squares - */ -constexpr std::array captures(Color side) { - switch (side) { - case Color::WHITE: - return Lookups::WHITE_PAWN_ATTACKS; - case Color::BLACK: - return Lookups::BLACK_PAWN_ATTACKS; - } - std::unreachable(); -} - -} // namespace PawnMoveGenerator diff --git a/include/bitbishop/moves/queen_move_gen.hpp b/include/bitbishop/moves/queen_move_gen.hpp deleted file mode 100644 index 7cec501..0000000 --- a/include/bitbishop/moves/queen_move_gen.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include -#include -#include -#include - -/** - * @brief Generates queen moves. - * - * Queen can move: - * - * - diagonally in the four directions (NE, NW, SE, SW) - * - horizontally (E, W) - * - vertically (N, S) - * - * until a friendly or enemy piece is encountered. - * - * This namespace provides functions for generating both pseudo-legal and legal queen moves. - */ -namespace QueenMoveGenerator { - -/** - * @brief Generates all pseudo-legal queen moves for a given side. - * - * Pseudo-legal moves follow piece movement rules but may leave the king in check. - * These moves must be validated separately to ensure legality. - * - * @param moves Vector to append generated moves to - * @param board Current board state - * @param side Color of the side to generate moves for - */ -void generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side); - -}; // namespace QueenMoveGenerator diff --git a/include/bitbishop/moves/readme.md b/include/bitbishop/moves/readme.md deleted file mode 100644 index 53a659d..0000000 --- a/include/bitbishop/moves/readme.md +++ /dev/null @@ -1,70 +0,0 @@ -# About the `moves/` directory (legacy / deprecated) - -## Status - -⚠️ Legacy code — kept intentionally - -This directory contains an older pseudo-legal move generation system, followed by post-filtering for legality. - -It is no longer the primary move generation path, but is preserved for: - -- correctness reference -- debugging -- performance comparison -- educational purposes - -## What this folder represents - -`moves/` implements the classic two-step approach: 1. Generate pseudo-legal moves 2. Filter out illegal moves by: - -- making the move -- checking king safety -- undoing the move - -This approach is simple and correct, but: - -- slower -- harder to optimize -- less suitable for high-performance engines - -## Why this folder still exists - -This code is intentionally kept because it: - -- is known to work -- provides a correctness baseline -- allows perft and move comparison against the new generator -- is useful for profiling and regression testing - -The new optimized legal move generator lives in `movegen/`. - -## What exactly goes into `moves/` - -### Definition - -This folder contains logic that: - -- generates pseudo-legal moves per piece -- filters moves via make/unmake -- does not use pins or check masks -- prioritizes simplicity over performance - -It may: - -- use Board -- generate Move objects -- temporarily allow illegal states - -It must not: - -- be used in the main engine search loop -- be mixed with the optimized movegen -- grow with new features - -## Migration note - -All new development related to move generation must go into: - -`movegen/` - -This folder is frozen unless a bug fix or reference improvement is required. diff --git a/include/bitbishop/moves/rook_move_gen.hpp b/include/bitbishop/moves/rook_move_gen.hpp deleted file mode 100644 index bb53bd3..0000000 --- a/include/bitbishop/moves/rook_move_gen.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -#include -#include -#include -#include - -/** - * @brief Generates rook moves. - * - * Rooks can move horizontally and vertically in the four directions (N, S, E, W) until a friendly - * or enemy piece is encountered. - * This namespace provides functions for generating both pseudo-legal and legal rook moves. - */ -namespace RookMoveGenerator { - -/** - * @brief Generates all pseudo-legal rook moves for a given side. - * - * Pseudo-legal moves follow piece movement rules but may leave the king in check. - * These moves must be validated separately to ensure legality. - * - * @param moves Vector to append generated moves to - * @param board Current board state - * @param side Color of the side to generate moves for - */ -void generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side); - -/** - * @brief Adds castling moves to the move list if conditions are met. - * - * Validates castling legality and adds both kingside and queenside castling - * moves when available. Castling requires that the king and rook haven't moved, - * squares between them are empty, and the king doesn't move through check. - * - * @param moves Vector to append castling moves to - * @param from Square the king is currently on - * @param side Color of the side attempting to castle - * @param board Current board state - * - * @see https://www.chess.com/article/view/how-to-castle-in-chess - */ -void add_rook_castling(std::vector& moves, Square from, Color side, const Board& board); - -}; // namespace RookMoveGenerator \ No newline at end of file diff --git a/src/bitbishop/moves/bishop_move_gen.cpp b/src/bitbishop/moves/bishop_move_gen.cpp deleted file mode 100644 index 1cfe99b..0000000 --- a/src/bitbishop/moves/bishop_move_gen.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include - -void BishopMoveGenerator::generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side) { - Bitboard bishops = board.bishops(side); - Bitboard empty = board.unoccupied(); - Bitboard enemy = board.enemy(side); - Bitboard occupied = board.occupied(); - - // warning: this loop is destructive on Bitboard bishops - while (auto from_opt = bishops.pop_lsb()) { - Square from = from_opt.value(); - - Bitboard attacks = bishop_attacks(from, occupied); - - // Bishop sliding moves - Bitboard bishop_moves = attacks & empty; - for (auto to : bishop_moves) { - moves.emplace_back(from, to, std::nullopt, false, false, false); - } - - // Bishop sliding captures - Bitboard bishop_captures = attacks & enemy; - for (auto to : bishop_captures) { - moves.emplace_back(from, to, std::nullopt, true, false, false); - } - } -} diff --git a/src/bitbishop/moves/king_move_gen.cpp b/src/bitbishop/moves/king_move_gen.cpp deleted file mode 100644 index 2fb6c3f..0000000 --- a/src/bitbishop/moves/king_move_gen.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include - -void KingMoveGenerator::generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side) { - Bitboard king = board.king(side); - const uint8_t nb_kings = king.count(); - - if (nb_kings != 1) { - throw std::runtime_error(std::format( - "Failed to generate king pseudo-legal moves for {} pieces, expected 1 king, got {}", side, nb_kings)); - } - - const std::optional opt_sq = king.pop_lsb(); - if (!opt_sq.has_value()) { - throw std::runtime_error(std::format("Failed to extract king square for {} side", side)); - } - - const Square from = opt_sq.value(); - const Bitboard& king_moves = Lookups::KING_ATTACKS[from.value()]; - const Bitboard empty = board.unoccupied(); - const Bitboard enemy = board.enemy(side); - - // Silent moves (pushes) - Bitboard pushes = king_moves & empty; - for (Square to : pushes) { - moves.emplace_back(from, to, std::nullopt, false, false, false); - } - - // Captures - Bitboard captures = king_moves & enemy; - for (Square to : captures) { - moves.emplace_back(from, to, std::nullopt, true, false, false); - } - - // Castling moves (pseudo-legal only checks piece positions, not attacks) - add_king_castling(moves, from, side, board); -} - -void KingMoveGenerator::generate_legal_moves(std::vector& moves, const Board& board, Color side) { - // Check casting moves and classic moves separately - // Check if the king is under attack - // Check if the square the king passes through are under attack - // TODO -} - -void KingMoveGenerator::add_king_castling(std::vector& moves, Square from, Color side, const Board& board) { - // Kingside castling - if (board.can_castle_kingside(side)) { - Square to = (side == Color::WHITE) ? Squares::G1 : Squares::G8; - moves.emplace_back(from, to, std::nullopt, false, false, true); - } - - // Queenside castling - if (board.can_castle_queenside(side)) { - Square to = (side == Color::WHITE) ? Squares::C1 : Squares::C8; - moves.emplace_back(from, to, std::nullopt, false, false, true); - } -} diff --git a/src/bitbishop/moves/knight_move_gen.cpp b/src/bitbishop/moves/knight_move_gen.cpp deleted file mode 100644 index 925a180..0000000 --- a/src/bitbishop/moves/knight_move_gen.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include - -void KnightMoveGenerator::generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side) { - Bitboard knights = board.knights(side); - Bitboard empty = board.unoccupied(); - Bitboard enemy = board.enemy(side); - - // warning: this loop is destructive on Bitboard knights - while (auto from_opt = knights.pop_lsb()) { - Square from = from_opt.value(); - const Bitboard& knight_lookup = Lookups::KNIGHT_ATTACKS[from.value()]; - - // Classic knight moves - Bitboard knight_moves = knight_lookup & empty; - for (Square to : knight_moves) { - moves.emplace_back(from, to, std::nullopt, false, false, false); - } - - // Knight captures - Bitboard knight_captures = knight_lookup & enemy; - for (Square to : knight_captures) { - moves.emplace_back(from, to, std::nullopt, true, false, false); - } - } -} diff --git a/src/bitbishop/moves/pawn_move_gen.cpp b/src/bitbishop/moves/pawn_move_gen.cpp deleted file mode 100644 index 001a066..0000000 --- a/src/bitbishop/moves/pawn_move_gen.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void PawnMoveGenerator::generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side) { - // NOTE: Possible optimization here: there are faster alternatives to an iterator over the Bitboard object - - Bitboard pawns = board.pawns(side); - Bitboard empty = board.unoccupied(); - Bitboard enemy = board.enemy(side); - - // warning: this loop is destructive on Bitboard pawns - while (auto from_opt = pawns.pop_lsb()) { - Square from = from_opt.value(); - - // Single pushes - Bitboard single_pushes = single_push(side)[from.value()]; - single_pushes &= empty; - for (Square to : single_pushes) { - if (is_promotion_rank(to, side)) { - add_pawn_promotions(moves, from, to, side, false); - } else { - moves.emplace_back(from, to, std::nullopt, false, false, false); - } - } - - // Double push - Bitboard double_pushes = double_push(side)[from.value()]; - double_pushes &= empty; - if (single_pushes.any()) { - for (Square to : double_pushes) { - moves.emplace_back(from, to, std::nullopt, false, false, false); - } - } - - // Classic capture - Bitboard cap = captures(side)[from.value()]; - cap &= enemy; - for (Square to : cap) { - if (is_promotion_rank(to, side)) { - add_pawn_promotions(moves, from, to, side, true); - } else { - moves.emplace_back(from, to, std::nullopt, true, false, false); - } - } - - // En passant capture - if (board.en_passant_square() && can_capture_en_passant(from, *board.en_passant_square(), side)) { - moves.emplace_back(from, *board.en_passant_square(), std::nullopt, true, true, false); - } - } -} - -void PawnMoveGenerator::add_pawn_promotions(std::vector& moves, Square from, Square to, Color side, - bool capture) { - const auto& promotion_pieces = (side == Color::WHITE) ? WHITE_PROMOTIONS : BLACK_PROMOTIONS; - - for (auto piece : promotion_pieces) { - moves.emplace_back(from, to, piece, capture, false, false); - } -} - -void PawnMoveGenerator::generate_legal_moves(std::vector& moves, const Board& board, Color side) { - // TODO -} diff --git a/src/bitbishop/moves/queen_move_gen.cpp b/src/bitbishop/moves/queen_move_gen.cpp deleted file mode 100644 index 8f0b0c9..0000000 --- a/src/bitbishop/moves/queen_move_gen.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -void QueenMoveGenerator::generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side) { - // Multiple queens may be present on the board after pawn promotion - Bitboard queens = board.queens(side); - Bitboard empty = board.unoccupied(); - Bitboard enemy = board.enemy(side); - Bitboard occupied = board.occupied(); - - // warning: this loop is destructive on Bitboard queens - while (auto from_opt = queens.pop_lsb()) { - Square from = from_opt.value(); - - Bitboard attacks = queen_attacks(from, occupied); - - // Queen sliding moves - Bitboard queen_moves = attacks & empty; - for (auto to : queen_moves) { - moves.emplace_back(from, to, std::nullopt, false, false, false); - } - - // Queen captures - Bitboard queen_captures = attacks & enemy; - for (auto to : queen_captures) { - moves.emplace_back(from, to, std::nullopt, true, false, false); - } - } -} diff --git a/src/bitbishop/moves/rook_move_gen.cpp b/src/bitbishop/moves/rook_move_gen.cpp deleted file mode 100644 index dde1f39..0000000 --- a/src/bitbishop/moves/rook_move_gen.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include - -void RookMoveGenerator::generate_pseudo_legal_moves(std::vector& moves, const Board& board, Color side) { - Bitboard rooks = board.rooks(side); - Bitboard empty = board.unoccupied(); - Bitboard enemy = board.enemy(side); - Bitboard occupied = board.occupied(); - - // warning: this loop is destructive on Bitboard rooks - while (auto from_opt = rooks.pop_lsb()) { - Square from = from_opt.value(); - - Bitboard attacks = rook_attacks(from, occupied); - - // Silent moves - Bitboard rook_moves = attacks & empty; - for (auto to : rook_moves) { - moves.emplace_back(from, to, std::nullopt, false, false, false); - } - - // Captures - Bitboard rook_captures = attacks & enemy; - for (auto to : rook_captures) { - moves.emplace_back(from, to, std::nullopt, true, false, false); - } - - // Castling moves (pseudo-legal only checks piece positions, not attacks) - add_rook_castling(moves, from, side, board); - } -} - -void RookMoveGenerator::add_rook_castling(std::vector& moves, Square from, Color side, const Board& board) { - // TODO: These Castling utilities must be moved out of the KingMoveGenerator namespace - // as it is common code with RookMoveGenerator - Square kingside_rook = (side == Color::WHITE) ? Squares::H1 : Squares::H8; - Square queenside_rook = (side == Color::WHITE) ? Squares::A1 : Squares::A8; - - // Kingside castling - const bool can_castle_kingside = board.can_castle_kingside(side) && (from == kingside_rook); - if (can_castle_kingside) { - Square to = (side == Color::WHITE) ? Squares::F1 : Squares::F8; - moves.emplace_back(from, to, std::nullopt, false, false, true); - } - - // Queenside castling - const bool can_castle_queenside = board.can_castle_queenside(side) && (from == queenside_rook); - if (can_castle_queenside) { - Square to = (side == Color::WHITE) ? Squares::D1 : Squares::D8; - moves.emplace_back(from, to, std::nullopt, false, false, true); - } -} diff --git a/tests/bitbishop/attacks/test_bishop_north_east_attacks.cpp b/tests/bitbishop/attacks/test_bishop_north_east_attacks.cpp index 0575039..67adcf6 100644 --- a/tests/bitbishop/attacks/test_bishop_north_east_attacks.cpp +++ b/tests/bitbishop/attacks/test_bishop_north_east_attacks.cpp @@ -3,7 +3,6 @@ #include #include #include -#include /** * @test bishop_north_east_attacks() with no blockers diff --git a/tests/bitbishop/attacks/test_bishop_north_west_attacks.cpp b/tests/bitbishop/attacks/test_bishop_north_west_attacks.cpp index 90eec37..d2e23e3 100644 --- a/tests/bitbishop/attacks/test_bishop_north_west_attacks.cpp +++ b/tests/bitbishop/attacks/test_bishop_north_west_attacks.cpp @@ -3,7 +3,6 @@ #include #include #include -#include /** * @test bishop_north_west_attacks() with no blockers diff --git a/tests/bitbishop/attacks/test_bishop_south_east_attacks.cpp b/tests/bitbishop/attacks/test_bishop_south_east_attacks.cpp index 2fe5be4..0728807 100644 --- a/tests/bitbishop/attacks/test_bishop_south_east_attacks.cpp +++ b/tests/bitbishop/attacks/test_bishop_south_east_attacks.cpp @@ -4,7 +4,6 @@ #include #include #include -#include /** * @test bishop_south_east_attacks() with no blockers diff --git a/tests/bitbishop/attacks/test_bishop_south_west_attacks.cpp b/tests/bitbishop/attacks/test_bishop_south_west_attacks.cpp index ced1811..d7863c3 100644 --- a/tests/bitbishop/attacks/test_bishop_south_west_attacks.cpp +++ b/tests/bitbishop/attacks/test_bishop_south_west_attacks.cpp @@ -3,7 +3,6 @@ #include #include #include -#include /** * @test bishop_south_west_attacks() with no blockers diff --git a/tests/bitbishop/attacks/test_rook_east_attacks.cpp b/tests/bitbishop/attacks/test_rook_east_attacks.cpp index 4977c2e..edf4417 100644 --- a/tests/bitbishop/attacks/test_rook_east_attacks.cpp +++ b/tests/bitbishop/attacks/test_rook_east_attacks.cpp @@ -3,7 +3,6 @@ #include #include #include -#include /** * @test rook_east_attacks() with no blockers diff --git a/tests/bitbishop/attacks/test_rook_north_attacks.cpp b/tests/bitbishop/attacks/test_rook_north_attacks.cpp index a1a33f1..a885287 100644 --- a/tests/bitbishop/attacks/test_rook_north_attacks.cpp +++ b/tests/bitbishop/attacks/test_rook_north_attacks.cpp @@ -3,7 +3,6 @@ #include #include #include -#include /** * @test rook_north_attacks() with no blockers diff --git a/tests/bitbishop/attacks/test_rook_south_attacks.cpp b/tests/bitbishop/attacks/test_rook_south_attacks.cpp index 7a46c07..ec95444 100644 --- a/tests/bitbishop/attacks/test_rook_south_attacks.cpp +++ b/tests/bitbishop/attacks/test_rook_south_attacks.cpp @@ -3,7 +3,6 @@ #include #include #include -#include /** * @test rook_south_attacks() with no blockers diff --git a/tests/bitbishop/attacks/test_rook_west_attacks.cpp b/tests/bitbishop/attacks/test_rook_west_attacks.cpp index 3bd4c49..6165958 100644 --- a/tests/bitbishop/attacks/test_rook_west_attacks.cpp +++ b/tests/bitbishop/attacks/test_rook_west_attacks.cpp @@ -3,7 +3,6 @@ #include #include #include -#include /** * @test rook_west_attacks() with no blockers diff --git a/tests/bitbishop/moves/bishop_move_generator/test_bmg_generate_pseudo_legal_moves.cpp b/tests/bitbishop/moves/bishop_move_generator/test_bmg_generate_pseudo_legal_moves.cpp deleted file mode 100644 index ffd0ec1..0000000 --- a/tests/bitbishop/moves/bishop_move_generator/test_bmg_generate_pseudo_legal_moves.cpp +++ /dev/null @@ -1,330 +0,0 @@ -#include - -#include -#include -#include - -/** - * @brief Test fixture for bishop pseudo-legal move generation. - */ -class BishopPseudoLegalMovesTest : public ::testing::Test { - protected: - std::vector moves; - - void SetUp() override {} - - void TearDown() override {} -}; - -/** - * @test White bishop has no move / capture from starting position - */ -TEST_F(BishopPseudoLegalMovesTest, StartingPositionWhiteHas0Moves) { - Board board; - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Black bishop has no moves / captures from starting position - */ -TEST_F(BishopPseudoLegalMovesTest, StartingPositionBlackHas0Moves) { - Board board; - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test White bishop in the center has 13 regular moves - */ -TEST_F(BishopPseudoLegalMovesTest, WhiteBishopCenterEmptyBoardHas13Moves) { - Board board("8/8/8/8/3B4/8/8/8 w - - 0 1"); // White bishop in D4 - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 13); - EXPECT_EQ(count_captures(moves), 0); - - // North East Ray - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::H8, std::nullopt, false, false, false})); - - // North West Ray - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A7, std::nullopt, false, false, false})); - - // South East Ray - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G1, std::nullopt, false, false, false})); - - // South West Ray - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test Black bishop in the center has 13 regular moves - */ -TEST_F(BishopPseudoLegalMovesTest, BlackBishopCenterEmptyBoardHas13Moves) { - Board board("8/8/8/8/3b4/8/8/8 b - - 0 1"); // Black bishop in D4 - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 13); - EXPECT_EQ(count_captures(moves), 0); - - // North East Ray - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::H8, std::nullopt, false, false, false})); - - // North West Ray - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A7, std::nullopt, false, false, false})); - - // South East Ray - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G1, std::nullopt, false, false, false})); - - // South West Ray - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test White bishop in the top right hand corner has 7 regular moves - */ -TEST_F(BishopPseudoLegalMovesTest, WhiteBishopCornerHas8Moves) { - Board board("7B/8/8/8/8/8/8/8 w - - 0 1"); // White bishop in H8 (top right hand corner) - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 7); - EXPECT_EQ(count_captures(moves), 0); - - // South West Ray - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::G7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::F6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::E5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::D4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::B2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test Black bishop in the bottom left corner has 7 regular moves - */ -TEST_F(BishopPseudoLegalMovesTest, BlackBishopCornerHas7Moves) { - Board board("8/8/8/8/8/8/8/b7 b - - 0 1"); // Black bishop in A1 (bottom left hand corner) - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 7); - EXPECT_EQ(count_captures(moves), 0); - - // North East Ray - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::H8, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::G7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::F6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::E5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::D4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::B2, std::nullopt, false, false, false})); -} - -/** - * @test White bishop on the right side has 7 regular moves - */ -TEST_F(BishopPseudoLegalMovesTest, WhiteBishopEdgeHas7Moves) { - Board board("8/8/8/7B/8/8/8/8 w - - 0 1"); // White bishop in H5 - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 7); - EXPECT_EQ(count_captures(moves), 0); - - // North West Ray - EXPECT_TRUE(contains_move(moves, {Squares::H5, Squares::G6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H5, Squares::F7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H5, Squares::E8, std::nullopt, false, false, false})); - - // South West Ray - EXPECT_TRUE(contains_move(moves, {Squares::H5, Squares::G4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H5, Squares::F3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H5, Squares::E2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H5, Squares::D1, std::nullopt, false, false, false})); -} - -/** - * @test Black bishop on the left edge has 7 regular moves - */ -TEST_F(BishopPseudoLegalMovesTest, BlackBishopEdgeHas7Moves) { - Board board("8/8/8/b7/8/8/8/8 b - - 0 1"); // Black bishop in A5 - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 7); - EXPECT_EQ(count_captures(moves), 0); - - // North East Ray - EXPECT_TRUE(contains_move(moves, {Squares::A5, Squares::B6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A5, Squares::C7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A5, Squares::D8, std::nullopt, false, false, false})); - - // South East Ray - EXPECT_TRUE(contains_move(moves, {Squares::A5, Squares::B4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A5, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A5, Squares::D2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A5, Squares::E1, std::nullopt, false, false, false})); -} - -/** - * @test White bishop can capture enemy pieces and stops at capture - */ -TEST_F(BishopPseudoLegalMovesTest, WhiteBishopCanCaptureEnemyPiece) { - // White bishop on D4 with black pawns on F6 and B2 - Board board("8/8/5p2/8/3B4/8/1p6/8 w - - 0 1"); - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 2); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, true, false, false})); -} - -/** - * @test Black bishop can capture enemy pieces and stops at capture - */ -TEST_F(BishopPseudoLegalMovesTest, BlackBishopCanCaptureEnemyPiece) { - // Black bishop on D4 with white pawns on F6 and B2 - Board board("8/8/5P2/8/3b4/8/1P6/8 b - - 0 1"); - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 2); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, true, false, false})); -} - -/** - * @test White bishop cannot capture own pieces and stops before them - */ -TEST_F(BishopPseudoLegalMovesTest, WhiteBishopCannotCaptureOwnPiece) { - // White bishop on D4 with white pawns on F6 and B2 - Board board("8/8/5P2/8/3B4/8/1P6/8 w - - 0 1"); - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 0); - - // North East Ray - should stop before F6 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::H8, std::nullopt, false, false, false})); - - // South West Ray - should stop before B2 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::A1, std::nullopt, false, false, false})); - - // North West Ray - should continue unblocked - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A7, std::nullopt, false, false, false})); - - // South East Ray - should continue unblocked - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G1, std::nullopt, false, false, false})); -} - -/** - * @test Black bishop cannot capture own pieces and stops before them - */ -TEST_F(BishopPseudoLegalMovesTest, BlackBishopCannotCaptureOwnPiece) { - // Black bishop on D4 with black pawns on F6 and B2 - Board board("8/8/5p2/8/3b4/8/1p6/8 b - - 0 1"); - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 0); - - // North East Ray - should stop before F6 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::H8, std::nullopt, false, false, false})); - - // South West Ray - should stop before B2 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::A1, std::nullopt, false, false, false})); - - // North West Ray - should continue unblocked - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A7, std::nullopt, false, false, false})); - - // South East Ray - should continue unblocked - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G1, std::nullopt, false, false, false})); -} - -/** - * @test White bishop with mixed occupancy (own and enemy pieces on different rays) - */ -TEST_F(BishopPseudoLegalMovesTest, WhiteBishopMixedOccupancy) { - // White bishop on D4 - // White knight on B6 (NW ray), black rook on G7 (NE ray) - // Black queen on E3 (SE ray), white pawn on C3 (SW ray) - Board board("8/6r1/1N6/8/3B4/2P1q3/8/8 w - - 0 1"); - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - // Should have 6 moves total: 2 captures (G7, E3) and 3 quiet moves - EXPECT_EQ(moves.size(), 5); - EXPECT_EQ(count_captures(moves), 2); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, true, false, false})); -} - -/** - * @test Black bishop with mixed occupancy (own and enemy pieces on different rays) - */ -TEST_F(BishopPseudoLegalMovesTest, BlackBishopMixedOccupancy) { - // Black bishop on D4 - // Black knight on B6 (NW ray), white rook on G7 (NE ray) - // White queen on E3 (SE ray), black pawn on C3 (SW ray) - Board board("8/6R1/1n6/8/3b4/2p1Q3/8/8 b - - 0 1"); - - BishopMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - // Should have 5 moves total: 2 captures (G7, E3) and 3 quiet moves - EXPECT_EQ(moves.size(), 5); - EXPECT_EQ(count_captures(moves), 2); - - // North East Ray - can capture white rook on G7 - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, true, false, false})); -} diff --git a/tests/bitbishop/moves/king_move_generator/test_kmg_generate_pseudo_legal_moves.cpp b/tests/bitbishop/moves/king_move_generator/test_kmg_generate_pseudo_legal_moves.cpp deleted file mode 100644 index 632c3d8..0000000 --- a/tests/bitbishop/moves/king_move_generator/test_kmg_generate_pseudo_legal_moves.cpp +++ /dev/null @@ -1,677 +0,0 @@ -#include - -#include -#include -#include - -/** - * @brief Test fixture for king pseudo-legal move generation. - */ -class KingPseudoLegalMovesTest : public ::testing::Test { - protected: - std::vector moves; - - void SetUp() override {} - - void TearDown() override {} -}; - -/** - * @test Verifies White king has 0 moves from starting position (surrounded by own pieces). - */ -TEST_F(KingPseudoLegalMovesTest, StartingPositionWhiteHas0Moves) { - Board board; - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies Black king has 0 moves from starting position (surrounded by own pieces). - */ -TEST_F(KingPseudoLegalMovesTest, StartingPositionBlackHas0Moves) { - Board board; - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies White king has no captures from starting position. - */ -TEST_F(KingPseudoLegalMovesTest, StartingPositionWhiteHasNoCaptures) { - Board board; - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black king has no captures from starting position. - */ -TEST_F(KingPseudoLegalMovesTest, StartingPositionBlackHasNoCaptures) { - Board board; - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White king on empty board generates 8 moves (all directions). - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingCenterEmptyBoardHas8Moves) { - Board board("8/8/8/8/3K4/8/8/8 w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black king on empty board generates 8 moves (all directions). - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingCenterEmptyBoardHas8Moves) { - Board board("8/8/8/8/3k4/8/8/8 b - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White king in corner has only 3 moves. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingInCornerHas3Moves) { - Board board("8/8/8/8/8/8/8/K7 w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 3); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::B1, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::B2, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black king in corner has only 3 moves. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingInCornerHas3Moves) { - Board board("k7/8/8/8/8/8/8/8 b - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 3); - EXPECT_TRUE(contains_move(moves, {Squares::A8, Squares::A7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A8, Squares::B8, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A8, Squares::B7, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White king on edge has 5 moves. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingOnEdgeHas5Moves) { - Board board("8/8/8/8/K7/8/8/8 w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 5); -} - -/** - * @test Verifies Black king on edge has 5 moves. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingOnEdgeHas5Moves) { - Board board("8/8/8/8/k7/8/8/8 b - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 5); -} - -/** - * @test Verifies White king can capture enemy pieces. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingCanCaptureEnemyPieces) { - Board board("8/8/8/8/2ppp3/2pKp3/2ppp3/8 w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 8); -} - -/** - * @test Verifies Black king can capture enemy pieces. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingCanCaptureEnemyPieces) { - Board board("8/8/8/8/2PPP3/2PkP3/2PPP3/8 b - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 8); -} - -/** - * @test Verifies White king cannot capture own pieces. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingCannotCaptureOwnPieces) { - Board board("8/8/8/8/2PPP3/2PKP3/2PPP3/8 w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black king cannot capture own pieces. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingCannotCaptureOwnPieces) { - Board board("8/8/8/8/2ppp3/2pkp3/2ppp3/8 b - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White king with mix of blocked and available squares. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingMixedOccupancy) { - Board board("8/8/8/8/2Ppp3/2pKP3/2PPp3/8 w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 4); - EXPECT_EQ(moves.size(), 4); -} - -/** - * @test Verifies Black king with mix of blocked and available squares. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingMixedOccupancy) { - Board board("8/8/8/8/2pPP3/2PkP3/2ppP3/8 b - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 5); - EXPECT_EQ(moves.size(), 5); -} - -/** - * @test Verifies White kingside castling is available from starting position. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingsideCastlingAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::E1, Squares::G1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White queenside castling is available from starting position. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteQueensideCastlingAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::E1, Squares::C1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black kingside castling is available from starting position. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingsideCastlingAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::E8, Squares::G8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black queenside castling is available from starting position. - */ -TEST_F(KingPseudoLegalMovesTest, BlackQueensideCastlingAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::E8, Squares::C8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White castling unavailable when kingside rook is missing. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingsideCastlingBlockedNoRook) { - Board board("8/8/8/8/8/8/8/R3K3 w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::G1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White castling unavailable when queenside rook is missing. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteQueensideCastlingBlockedNoRook) { - Board board("8/8/8/8/8/8/8/4K2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::C1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black castling unavailable when kingside rook is missing. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingsideCastlingBlockedNoRook) { - Board board("r3k3/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::G8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black castling unavailable when queenside rook is missing. - */ -TEST_F(KingPseudoLegalMovesTest, BlackQueensideCastlingBlockedNoRook) { - Board board("4k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::C8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White kingside castling blocked when F1 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingsideCastlingBlockedByPieceOnF1) { - Board board("8/8/8/8/8/8/8/R3KB1R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::G1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White kingside castling blocked when G1 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingsideCastlingBlockedByPieceOnG1) { - Board board("8/8/8/8/8/8/8/R3K1NR w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::G1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White queenside castling blocked when D1 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteQueensideCastlingBlockedByPieceOnD1) { - Board board("8/8/8/8/8/8/8/R2QK2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::C1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White queenside castling blocked when C1 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteQueensideCastlingBlockedByPieceOnC1) { - Board board("8/8/8/8/8/8/8/R1B1K2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::C1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White queenside castling blocked when B1 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteQueensideCastlingBlockedByPieceOnB1) { - Board board("8/8/8/8/8/8/8/RN2K2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::C1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black kingside castling blocked when F8 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingsideCastlingBlockedByPieceOnF8) { - Board board("r3kb1r/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::G8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black kingside castling blocked when G8 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingsideCastlingBlockedByPieceOnG8) { - Board board("r3k1nr/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::G8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black queenside castling blocked when D8 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, BlackQueensideCastlingBlockedByPieceOnD8) { - Board board("r2qk2r/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::C8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black queenside castling blocked when C8 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, BlackQueensideCastlingBlockedByPieceOnC8) { - Board board("r1b1k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::C8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black queenside castling blocked when B8 is occupied. - */ -TEST_F(KingPseudoLegalMovesTest, BlackQueensideCastlingBlockedByPieceOnB8) { - Board board("rn2k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::C8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White castling unavailable when castling rights are lost. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteCastlingUnavailableWithoutRights) { - Board board("8/8/8/8/8/8/8/R3K2R w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::G1, std::nullopt, false, false, true})); - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::C1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black castling unavailable when castling rights are lost. - */ -TEST_F(KingPseudoLegalMovesTest, BlackCastlingUnavailableWithoutRights) { - Board board("r3k2r/8/8/8/8/8/8/8 b - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::G8, std::nullopt, false, false, true})); - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::C8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White can only castle kingside when queenside rights are lost. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteOnlyKingsideCastlingAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w K - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::E1, Squares::G1, std::nullopt, false, false, true})); - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::C1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White can only castle queenside when kingside rights are lost. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteOnlyQueensideCastlingAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w Q - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::E1, Squares::G1, std::nullopt, false, false, true})); - EXPECT_TRUE(contains_move(moves, {Squares::E1, Squares::C1, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black can only castle kingside when queenside rights are lost. - */ -TEST_F(KingPseudoLegalMovesTest, BlackOnlyKingsideCastlingAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b k - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::E8, Squares::G8, std::nullopt, false, false, true})); - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::C8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies Black can only castle queenside when kingside rights are lost. - */ -TEST_F(KingPseudoLegalMovesTest, BlackOnlyQueensideCastlingAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b q - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::E8, Squares::G8, std::nullopt, false, false, true})); - EXPECT_TRUE(contains_move(moves, {Squares::E8, Squares::C8, std::nullopt, false, false, true})); -} - -/** - * @test Verifies White king not on starting square prevents castling. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingNotOnStartingSquareNoCastling) { - Board board("8/8/8/8/8/4K3/8/R6R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - // King on E3, so no castling moves should be generated - for (const auto& move : moves) { - EXPECT_FALSE(move.is_castling) << "No castling should be possible when king is not on starting square"; - } -} - -/** - * @test Verifies Black king not on starting square prevents castling. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingNotOnStartingSquareNoCastling) { - Board board("r6r/8/4k3/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - // King on E6, so no castling moves should be generated - for (const auto& move : moves) { - EXPECT_FALSE(move.is_castling) << "No castling should be possible when king is not on starting square"; - } -} - -/** - * @test Verifies exception thrown when no king is present. - */ -TEST_F(KingPseudoLegalMovesTest, ThrowsExceptionWhenNoKing) { - Board board("8/8/8/8/8/8/8/8 w - - 0 1"); - - EXPECT_THROW(KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE), std::runtime_error); -} - -/** - * @test Verifies exception thrown when multiple kings are present. - */ -TEST_F(KingPseudoLegalMovesTest, ThrowsExceptionWhenMultipleKings) { - Board board("8/8/8/8/3K4/8/8/3K4 w - - 0 1"); - - EXPECT_THROW(KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE), std::runtime_error); -} - -/** - * @test Verifies all king moves have no promotion flag. - */ -TEST_F(KingPseudoLegalMovesTest, AllMovesHaveNoPromotionFlag) { - Board board("8/8/8/8/3K4/8/8/8 w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - EXPECT_FALSE(move.promotion.has_value()) << "King moves should never have promotion"; - } -} - -/** - * @test Verifies all king moves have no en passant flag. - */ -TEST_F(KingPseudoLegalMovesTest, AllMovesHaveNoEnPassantFlag) { - Board board("8/8/8/8/3K4/8/8/8 w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - EXPECT_FALSE(move.is_en_passant) << "King moves should never be en passant"; - } -} - -/** - * @test Verifies only castling moves have castling flag set. - */ -TEST_F(KingPseudoLegalMovesTest, OnlyCastlingMovesHaveCastlingFlag) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - if (move.is_castling) { - EXPECT_TRUE(move.from == Squares::E1); - EXPECT_TRUE(move.to == Squares::G1 || move.to == Squares::C1); - } - } -} - -/** - * @test Verifies complex position with captures and regular moves. - */ -TEST_F(KingPseudoLegalMovesTest, ComplexPositionMixedMoves) { - Board board("8/8/8/2pPp3/2pKp3/2pPp3/8/8 w - - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 6); - EXPECT_EQ(count_captures(moves), 6); -} - -/** - * @test Verifies both castling moves available simultaneously. - */ -TEST_F(KingPseudoLegalMovesTest, BothCastlingMovesAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - int castling_count = 0; - for (const auto& move : moves) { - if (move.is_castling) castling_count++; - } - - EXPECT_EQ(castling_count, 2); -} - -/** - * @test Verifies castling moves have correct from and to squares for White kingside. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteKingsideCastlingCorrectSquares) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - bool found_kingside = false; - for (const auto& move : moves) { - if (move.is_castling && move.to == Squares::G1) { - EXPECT_EQ(move.from, Squares::E1); - EXPECT_FALSE(move.is_capture); - EXPECT_FALSE(move.is_en_passant); - EXPECT_FALSE(move.promotion.has_value()); - found_kingside = true; - } - } - EXPECT_TRUE(found_kingside) << "White kingside castling move should be present"; -} - -/** - * @test Verifies castling moves have correct from and to squares for White queenside. - */ -TEST_F(KingPseudoLegalMovesTest, WhiteQueensideCastlingCorrectSquares) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - bool found_queenside = false; - for (const auto& move : moves) { - if (move.is_castling && move.to == Squares::C1) { - EXPECT_EQ(move.from, Squares::E1); - EXPECT_FALSE(move.is_capture); - EXPECT_FALSE(move.is_en_passant); - EXPECT_FALSE(move.promotion.has_value()); - found_queenside = true; - } - } - EXPECT_TRUE(found_queenside) << "White queenside castling move should be present"; -} - -/** - * @test Verifies castling moves have correct from and to squares for Black kingside. - */ -TEST_F(KingPseudoLegalMovesTest, BlackKingsideCastlingCorrectSquares) { - Board board("r3k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - bool found_kingside = false; - for (const auto& move : moves) { - if (move.is_castling && move.to == Squares::G8) { - EXPECT_EQ(move.from, Squares::E8); - EXPECT_FALSE(move.is_capture); - EXPECT_FALSE(move.is_en_passant); - EXPECT_FALSE(move.promotion.has_value()); - found_kingside = true; - } - } - EXPECT_TRUE(found_kingside) << "Black kingside castling move should be present"; -} - -/** - * @test Verifies castling moves have correct from and to squares for Black queenside. - */ -TEST_F(KingPseudoLegalMovesTest, BlackQueensideCastlingCorrectSquares) { - Board board("r3k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - KingMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - bool found_queenside = false; - for (const auto& move : moves) { - if (move.is_castling && move.to == Squares::C8) { - EXPECT_EQ(move.from, Squares::E8); - EXPECT_FALSE(move.is_capture); - EXPECT_FALSE(move.is_en_passant); - EXPECT_FALSE(move.promotion.has_value()); - found_queenside = true; - } - } - EXPECT_TRUE(found_queenside) << "Black queenside castling move should be present"; -} diff --git a/tests/bitbishop/moves/knight_move_generator/test_nmg_generate_pseudo_legal_moves.cpp b/tests/bitbishop/moves/knight_move_generator/test_nmg_generate_pseudo_legal_moves.cpp deleted file mode 100644 index a036d1f..0000000 --- a/tests/bitbishop/moves/knight_move_generator/test_nmg_generate_pseudo_legal_moves.cpp +++ /dev/null @@ -1,343 +0,0 @@ -#include - -#include -#include -#include - -/** - * @brief Test fixture for knight pseudo-legal move generation. - */ -class KnightPseudoLegalMovesTest : public ::testing::Test { - protected: - std::vector moves; - - void SetUp() override {} - - void TearDown() override {} -}; - -/** - * @test Verifies White knights have 4 moves from starting position. - */ -TEST_F(KnightPseudoLegalMovesTest, StartingPositionWhiteHas4Moves) { - Board board; - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 4); -} - -/** - * @test Verifies Black knights have 4 moves from starting position. - */ -TEST_F(KnightPseudoLegalMovesTest, StartingPositionBlackHas4Moves) { - Board board; - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 4); -} - -/** - * @test Verifies White knights have no captures from starting position. - */ -TEST_F(KnightPseudoLegalMovesTest, StartingPositionWhiteHasNoCaptures) { - Board board; - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black knights have no captures from starting position. - */ -TEST_F(KnightPseudoLegalMovesTest, StartingPositionBlackHasNoCaptures) { - Board board; - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White knight on empty board generates 8 moves (center position). - */ -TEST_F(KnightPseudoLegalMovesTest, WhiteKnightCenterEmptyBoardHas8Moves) { - Board board("8/8/8/8/3N4/8/8/8 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black knight on empty board generates 8 moves (center position). - */ -TEST_F(KnightPseudoLegalMovesTest, BlackKnightCenterEmptyBoardHas8Moves) { - Board board("8/8/8/8/3n4/8/8/8 b - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White knight in corner has only 2 moves. - */ -TEST_F(KnightPseudoLegalMovesTest, WhiteKnightInCornerHas2Moves) { - Board board("8/8/8/8/8/8/8/N7 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 2); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::B3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::C2, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black knight in corner has only 2 moves. - */ -TEST_F(KnightPseudoLegalMovesTest, BlackKnightInCornerHas2Moves) { - Board board("n7/8/8/8/8/8/8/8 b - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 2); - EXPECT_TRUE(contains_move(moves, {Squares::A8, Squares::B6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A8, Squares::C7, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White knight on edge has 4 moves. - */ -TEST_F(KnightPseudoLegalMovesTest, WhiteKnightOnEdgeHas4Moves) { - Board board("8/8/8/8/N7/8/8/8 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 4); -} - -/** - * @test Verifies Black knight on edge has 4 moves. - */ -TEST_F(KnightPseudoLegalMovesTest, BlackKnightOnEdgeHas4Moves) { - Board board("8/8/8/8/n7/8/8/8 b - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 4); -} - -/** - * @test Verifies White knight can capture enemy pieces. - */ -TEST_F(KnightPseudoLegalMovesTest, WhiteKnightCanCaptureEnemyPieces) { - Board board("8/8/8/2p1p3/1p3p2/3N4/1p3p2/2p1p3 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 8); -} - -/** - * @test Verifies Black knight can capture enemy pieces. - */ -TEST_F(KnightPseudoLegalMovesTest, BlackKnightCanCaptureEnemyPieces) { - Board board("8/8/8/2P1P3/1P3P2/3n4/1P3P2/2P1P3 b - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 8); -} - -/** - * @test Verifies White knight cannot capture own pieces. - */ -TEST_F(KnightPseudoLegalMovesTest, WhiteKnightCannotCaptureOwnPieces) { - Board board("8/8/8/2P1P3/1P3P2/3N4/1P3P2/2P1P3 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black knight cannot capture own pieces. - */ -TEST_F(KnightPseudoLegalMovesTest, BlackKnightCannotCaptureOwnPieces) { - Board board("8/8/8/2p1p3/1p3p2/3n4/1p3p2/2p1p3 b - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White knight with mix of blocked and available squares. - */ -TEST_F(KnightPseudoLegalMovesTest, WhiteKnightMixedOccupancy) { - Board board("8/8/8/2P1p3/1p3P2/3N4/1P3p2/2p1P3 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 4); - EXPECT_EQ(moves.size(), 4); -} - -/** - * @test Verifies Black knight with mix of blocked and available squares. - */ -TEST_F(KnightPseudoLegalMovesTest, BlackKnightMixedOccupancy) { - Board board("8/8/8/2p1P3/1P3p2/3n4/1p3P2/2P1p3 b - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 4); - EXPECT_EQ(moves.size(), 4); -} - -/** - * @test Verifies White knight near edge has 6 moves. - */ -TEST_F(KnightPseudoLegalMovesTest, WhiteKnightNearEdgeHas6Moves) { - Board board("8/8/8/8/8/8/N7/8 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 3); -} - -/** - * @test Verifies Black knight near edge has 6 moves. - */ -TEST_F(KnightPseudoLegalMovesTest, BlackKnightNearEdgeHas6Moves) { - Board board("8/n7/8/8/8/8/8/8 b - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 3); -} - -/** - * @test Verifies multiple White knights generate correct total moves. - */ -TEST_F(KnightPseudoLegalMovesTest, MultipleWhiteKnights) { - Board board("8/8/8/8/3N4/8/8/N7 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 10); // 8 from center knight + 2 from corner knight -} - -/** - * @test Verifies multiple Black knights generate correct total moves. - */ -TEST_F(KnightPseudoLegalMovesTest, MultipleBlackKnights) { - Board board("n7/8/8/8/3n4/8/8/8 b - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 10); // 8 from center knight + 2 from corner knight -} - -/** - * @test Verifies no moves when no knights on board. - */ -TEST_F(KnightPseudoLegalMovesTest, NoKnightsNoMoves) { - Board board("8/8/8/8/8/8/8/8 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies knight moves are not marked as captures when landing on empty squares. - */ -TEST_F(KnightPseudoLegalMovesTest, NonCaptureMovesFlaggedCorrectly) { - Board board("8/8/8/8/3N4/8/8/8 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - EXPECT_FALSE(move.is_capture); - } -} - -/** - * @test Verifies knight captures are marked correctly. - */ -TEST_F(KnightPseudoLegalMovesTest, CaptureMovesFlaggedCorrectly) { - Board board("8/8/8/2p1p3/1p3p2/3N4/1p3p2/2p1p3 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - EXPECT_TRUE(move.is_capture); - } -} - -/** - * @test Verifies specific knight move targets from d4. - */ -TEST_F(KnightPseudoLegalMovesTest, SpecificKnightMovesFromD4) { - Board board("8/8/8/8/3N4/8/8/8 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E6, std::nullopt, false, false, false})); -} - -/** - * @test Verifies knight moves do not include promotion flags. - */ -TEST_F(KnightPseudoLegalMovesTest, KnightMovesHaveNoPromotionFlags) { - Board board("8/8/8/8/3N4/8/8/8 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - EXPECT_FALSE(move.promotion.has_value()); - } -} - -/** - * @test Verifies knight moves do not include castling flags. - */ -TEST_F(KnightPseudoLegalMovesTest, KnightMovesHaveNoCastlingFlags) { - Board board("8/8/8/8/3N4/8/8/8 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - EXPECT_FALSE(move.is_castling); - } -} - -/** - * @test Verifies knight moves do not include en passant flags. - */ -TEST_F(KnightPseudoLegalMovesTest, KnightMovesHaveNoEnPassantFlags) { - Board board("8/8/8/8/3N4/8/8/8 w - - 0 1"); - - KnightMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - EXPECT_FALSE(move.is_en_passant); - } -} diff --git a/tests/bitbishop/moves/pawn_move_generator/test_pmg_captures.cpp b/tests/bitbishop/moves/pawn_move_generator/test_pmg_captures.cpp deleted file mode 100644 index a45eccd..0000000 --- a/tests/bitbishop/moves/pawn_move_generator/test_pmg_captures.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include - -#include - -/** - * @test Verifies captures returns the correct pre-computed array for White pawns. - */ -TEST(PawnMoveGeneratorTest, AttacksWhiteReturnsCorrectArray) { - auto result = PawnMoveGenerator::captures(Color::WHITE); - EXPECT_EQ(result.size(), 64); - EXPECT_EQ(result, Lookups::WHITE_PAWN_ATTACKS); -} - -/** - * @test Verifies captures returns the correct pre-computed array for Black pawns. - */ -TEST(PawnMoveGeneratorTest, AttacksBlackReturnsCorrectArray) { - auto result = PawnMoveGenerator::captures(Color::BLACK); - EXPECT_EQ(result.size(), 64); - EXPECT_EQ(result, Lookups::BLACK_PAWN_ATTACKS); -} - -/** - * @test Confirms White and Black capture arrays are distinct. - */ -TEST(PawnMoveGeneratorTest, AttacksWhiteAndBlackAreDifferent) { - auto white_result = PawnMoveGenerator::captures(Color::WHITE); - auto black_result = PawnMoveGenerator::captures(Color::BLACK); - EXPECT_NE(white_result, black_result); -} diff --git a/tests/bitbishop/moves/pawn_move_generator/test_pmg_double_push.cpp b/tests/bitbishop/moves/pawn_move_generator/test_pmg_double_push.cpp deleted file mode 100644 index 80f5a4f..0000000 --- a/tests/bitbishop/moves/pawn_move_generator/test_pmg_double_push.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include - -#include - -/** - * @test Verifies double_push returns the correct pre-computed array for White pawns. - */ -TEST(PawnMoveGeneratorTest, DoublePushWhiteReturnsCorrectArray) { - auto result = PawnMoveGenerator::double_push(Color::WHITE); - EXPECT_EQ(result.size(), 64); - EXPECT_EQ(result, Lookups::WHITE_PAWN_DOUBLE_PUSH); -} - -/** - * @test Verifies double_push returns the correct pre-computed array for Black pawns. - */ -TEST(PawnMoveGeneratorTest, DoublePushBlackReturnsCorrectArray) { - auto result = PawnMoveGenerator::double_push(Color::BLACK); - EXPECT_EQ(result.size(), 64); - EXPECT_EQ(result, Lookups::BLACK_PAWN_DOUBLE_PUSH); -} - -/** - * @test Confirms White and Black double push arrays are distinct. - */ -TEST(PawnMoveGeneratorTest, DoublePushWhiteAndBlackAreDifferent) { - auto white_result = PawnMoveGenerator::double_push(Color::WHITE); - auto black_result = PawnMoveGenerator::double_push(Color::BLACK); - EXPECT_NE(white_result, black_result); -} diff --git a/tests/bitbishop/moves/pawn_move_generator/test_pmg_generate_pseudo_legal_moves.cpp b/tests/bitbishop/moves/pawn_move_generator/test_pmg_generate_pseudo_legal_moves.cpp deleted file mode 100644 index fe84d56..0000000 --- a/tests/bitbishop/moves/pawn_move_generator/test_pmg_generate_pseudo_legal_moves.cpp +++ /dev/null @@ -1,706 +0,0 @@ -#include - -#include -#include -#include - -/** - * @brief Test fixture for pawn pseudo-legal move generation. - */ -class PawnPseudoLegalMovesTest : public ::testing::Test { - protected: - std::vector moves; - - void SetUp() override {} - - void TearDown() override {} -}; - -/** - * @test Verifies White has 16 pawn moves from starting position (8 pawns × 2 moves). - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionWhiteHas16Moves) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 16); -} - -/** - * @test Verifies Black has 16 pawn moves from starting position (8 pawns × 2 moves). - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionBlackHas16Moves) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 16); -} - -/** - * @test Verifies White has no captures from starting position. - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionWhiteHasNoCaptures) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black has no captures from starting position. - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionBlackHasNoCaptures) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White has no promotions from starting position. - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionWhiteHasNoPromotions) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_promotions(moves), 0); -} - -/** - * @test Verifies Black has no promotions from starting position. - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionBlackHasNoPromotions) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_promotions(moves), 0); -} - -/** - * @test Verifies White generates all 8 single pushes from starting position (rank 2 to rank 3). - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionWhiteHasCorrectSinglePushes) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::A2, Squares::A3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::B2, Squares::B3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::C2, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D2, Squares::D3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::E2, Squares::E3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::F2, Squares::F3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::G2, Squares::G3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H2, Squares::H3, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black generates all 8 single pushes from starting position (rank 7 to rank 6). - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionBlackHasCorrectSinglePushes) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::A7, Squares::A6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::B7, Squares::B6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::C7, Squares::C6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D7, Squares::D6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::E7, Squares::E6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::F7, Squares::F6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::G7, Squares::G6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H7, Squares::H6, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White generates all 8 double pushes from starting position (rank 2 to rank 4). - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionWhiteHasCorrectDoublePushes) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::A2, Squares::A4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::B2, Squares::B4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::C2, Squares::C4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D2, Squares::D4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::E2, Squares::E4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::F2, Squares::F4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::G2, Squares::G4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H2, Squares::H4, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black generates all 8 double pushes from starting position (rank 7 to rank 5). - */ -TEST_F(PawnPseudoLegalMovesTest, StartingPositionBlackHasCorrectDoublePushes) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::A7, Squares::A5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::B7, Squares::B5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::C7, Squares::C5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D7, Squares::D5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::E7, Squares::E5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::F7, Squares::F5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::G7, Squares::G5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H7, Squares::H5, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White single push is blocked when own piece occupies destination. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteSinglePushBlockedByOwnPiece) { - Board board("8/8/8/8/8/P7/P7/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 1); -} - -/** - * @test Verifies Black single push is blocked when own piece occupies destination. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackSinglePushBlockedByOwnPiece) { - Board board("8/p7/p7/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 1); -} - -/** - * @test Verifies White single push is blocked when enemy piece occupies destination. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteSinglePushBlockedByEnemyPiece) { - Board board("8/8/8/8/8/p7/P7/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies Black single push is blocked when enemy piece occupies destination. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackSinglePushBlockedByEnemyPiece) { - Board board("8/p7/P7/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies White pawn can single push to empty square. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteSinglePushToEmptySquare) { - Board board("8/8/8/8/8/8/P7/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::A2, Squares::A3, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black pawn can single push to empty square. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackSinglePushToEmptySquare) { - Board board("8/7p/8/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::H7, Squares::H6, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White pawn can double push from starting rank. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteDoublePushFromStartingRank) { - Board board("8/8/8/8/8/8/P7/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::A2, Squares::A4, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black pawn can double push from starting rank. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackDoublePushFromStartingRank) { - Board board("8/7p/8/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::H7, Squares::H5, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White double push is blocked when intermediate square is occupied. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteDoublePushBlockedByPieceOnThirdRank) { - Board board("8/8/8/8/8/P7/P7/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_FALSE(contains_move(moves, {Squares::A2, Squares::A4, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black double push is blocked when intermediate square is occupied. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackDoublePushBlockedByPieceOnThirdRank) { - Board board("8/7p/7p/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_FALSE(contains_move(moves, {Squares::H7, Squares::H5, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White double push is blocked when destination square is occupied. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteDoublePushBlockedByPieceOnFourthRank) { - Board board("8/8/8/8/P7/8/P7/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::A2, Squares::A3, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::A2, Squares::A4, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black double push is blocked when destination square is occupied. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackDoublePushBlockedByPieceOnFourthRank) { - Board board("8/7p/8/7p/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::H7, Squares::H6, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::H7, Squares::H5, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White double push is unavailable from non-starting rank. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteDoublePushNotAvailableFromThirdRank) { - Board board("8/8/8/8/8/P7/8/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 1); - EXPECT_TRUE(contains_move(moves, {Squares::A3, Squares::A4, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black double push is unavailable from non-starting rank. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackDoublePushNotAvailableFromSixthRank) { - Board board("8/8/7p/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 1); - EXPECT_TRUE(contains_move(moves, {Squares::H6, Squares::H5, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White pawn can capture diagonally. - */ -TEST_F(PawnPseudoLegalMovesTest, WhitePawnCanCaptureDiagonally) { - Board board("8/8/8/8/8/1p6/P7/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::A2, Squares::B3, std::nullopt, true, false, false})); -} - -/** - * @test Verifies Black pawn can capture diagonally. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackPawnCanCaptureDiagonally) { - Board board("8/7p/6P1/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::H7, Squares::G6, std::nullopt, true, false, false})); -} - -/** - * @test Verifies White pawn can capture on both diagonals simultaneously. - */ -TEST_F(PawnPseudoLegalMovesTest, WhitePawnCanCaptureBothDiagonals) { - Board board("8/8/8/8/8/pPp5/1P6/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::B2, Squares::A3, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::B2, Squares::C3, std::nullopt, true, false, false})); -} - -/** - * @test Verifies Black pawn can capture on both diagonals simultaneously. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackPawnCanCaptureBothDiagonals) { - Board board("8/6p1/5PpP/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::G7, Squares::H6, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::G7, Squares::F6, std::nullopt, true, false, false})); -} - -/** - * @test Verifies White pawn cannot capture own pieces. - */ -TEST_F(PawnPseudoLegalMovesTest, WhitePawnCannotCaptureOwnPieces) { - Board board("8/8/8/8/8/PPP5/1P6/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black pawn cannot capture own pieces. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackPawnCannotCaptureOwnPieces) { - Board board("8/5ppp/6p1/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White pawn cannot capture by moving forward. - */ -TEST_F(PawnPseudoLegalMovesTest, WhitePawnCannotCaptureForward) { - Board board("8/8/8/8/8/p7/P7/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies Black pawn cannot capture by moving forward. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackPawnCannotCaptureForward) { - Board board("8/7p/7P/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies White pawn promotes when reaching eighth rank (4 promotion options). - */ -TEST_F(PawnPseudoLegalMovesTest, WhitePawnPromotesOnEighthRank) { - Board board("8/P7/8/8/8/8/8/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 4); - EXPECT_EQ(count_promotions(moves), 4); -} - -/** - * @test Verifies Black pawn promotes when reaching first rank (4 promotion options). - */ -TEST_F(PawnPseudoLegalMovesTest, BlackPawnPromotesOnFirstRank) { - Board board("8/8/8/8/8/8/p7/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 4); - EXPECT_EQ(count_promotions(moves), 4); -} - -/** - * @test Verifies White promotion generates capture and non-capture variants (8 total moves). - */ -TEST_F(PawnPseudoLegalMovesTest, WhitePawnPromotesWithCapture) { - Board board("1p6/P7/8/8/8/8/8/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_promotions(moves), 8); - EXPECT_EQ(count_captures(moves), 4); -} - -/** - * @test Verifies Black promotion generates capture and non-capture variants (8 total moves). - */ -TEST_F(PawnPseudoLegalMovesTest, BlackPawnPromotesWithCapture) { - Board board("8/8/8/8/8/8/p7/1P6 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_promotions(moves), 8); - EXPECT_EQ(count_captures(moves), 4); -} - -/** - * @test Verifies White promotion is blocked when destination is occupied. - */ -TEST_F(PawnPseudoLegalMovesTest, WhitePawnPromotionBlockedByPiece) { - Board board("R7/P7/8/8/8/8/8/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies Black promotion is blocked when destination is occupied. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackPawnPromotionBlockedByPiece) { - Board board("8/8/8/8/8/8/7P/7R b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies White pawn can capture en passant when available. - */ -TEST_F(PawnPseudoLegalMovesTest, WhitePawnCanCaptureEnPassant) { - Board board("8/8/8/3Pp3/8/8/8/8 w - e6 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::D5, Squares::E6, std::nullopt, true, true, false})); - EXPECT_EQ(count_en_passant(moves), 1); -} - -/** - * @test Verifies Black pawn can capture en passant when available. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackPawnCanCaptureEnPassant) { - Board board("8/8/8/8/3pP3/8/8/8 b - e3 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, true, true, false})); - EXPECT_EQ(count_en_passant(moves), 1); -} - -/** - * @test Verifies White en passant is unavailable when no target square is set. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteEnPassantNotAvailableWhenNoTarget) { - Board board("8/8/8/3Pp3/8/8/8/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_en_passant(moves), 0); -} - -/** - * @test Verifies Black en passant is unavailable when no target square is set. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackEnPassantNotAvailableWhenNoTarget) { - Board board("8/8/8/8/3pP3/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_en_passant(moves), 0); -} - -/** - * @test Verifies both White pawns can capture the same en passant target. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteEnPassantBothSidesCanCapture) { - Board board("8/8/8/3PpP2/8/8/8/8 w - e6 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_TRUE(contains_move(moves, {Squares::D5, Squares::E6, std::nullopt, true, true, false})); - EXPECT_TRUE(contains_move(moves, {Squares::F5, Squares::E6, std::nullopt, true, true, false})); - EXPECT_EQ(count_en_passant(moves), 2); -} - -/** - * @test Verifies both Black pawns can capture the same en passant target. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackEnPassantBothSidesCanCapture) { - Board board("8/8/8/8/3pPp2/8/8/8 b - e3 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, true, true, false})); - EXPECT_TRUE(contains_move(moves, {Squares::F4, Squares::E3, std::nullopt, true, true, false})); - EXPECT_EQ(count_en_passant(moves), 2); -} - -/** - * @test Verifies empty board generates no White pawn moves. - */ -TEST_F(PawnPseudoLegalMovesTest, WhiteEmptyBoardGeneratesNoMoves) { - Board board("8/8/8/8/8/8/8/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies empty board generates no Black pawn moves. - */ -TEST_F(PawnPseudoLegalMovesTest, BlackEmptyBoardGeneratesNoMoves) { - Board board("8/8/8/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies no moves when White has no pawns. - */ -TEST_F(PawnPseudoLegalMovesTest, NoWhitePawnsGeneratesNoMoves) { - Board board("rnbqkbnr/8/8/1p6/8/8/8/RNBQKBNR w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies no moves when Black has no pawns. - */ -TEST_F(PawnPseudoLegalMovesTest, NoBlackPawnsGeneratesNoMoves) { - Board board("rnbqkbnr/8/8/1P6/8/8/8/RNBQKBNR b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies complex position generates correct number of White pawn moves. - */ -TEST_F(PawnPseudoLegalMovesTest, ComplexPositionWhitePawns) { - Board board("8/8/8/8/1p1p1p2/P1P1P3/1P1P4/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_GT(moves.size(), 0); - - for (const auto& move : moves) { - EXPECT_FALSE(move.is_castling); - } - - EXPECT_EQ(moves.size(), 10); -} - -/** - * @test Verifies complex position generates correct number of Black pawn moves. - */ -TEST_F(PawnPseudoLegalMovesTest, ComplexPositionBlackPawns) { - Board board("8/8/8/8/1p1p1p2/P1P1P3/1P1P4/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_GT(moves.size(), 0); - - for (const auto& move : moves) { - EXPECT_FALSE(move.is_castling); - } - - EXPECT_EQ(moves.size(), 8); -} - -/** - * @test Verifies 8 White pawns on rank 2 generate 16 moves (single + double push each). - */ -TEST_F(PawnPseudoLegalMovesTest, MultipleWhitePawnsGenerateMultipleMoves) { - Board board("8/8/8/8/8/8/PPPPPPPP/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 16); -} - -/** - * @test Verifies 8 Black pawns on rank 7 generate 16 moves (single + double push each). - */ -TEST_F(PawnPseudoLegalMovesTest, MultipleBlackPawnsGenerateMultipleMoves) { - Board board("8/pppppppp/8/8/8/8/8/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 16); -} - -/** - * @test Verifies 3 White pawns on rank 7 generate 12 promotion moves (3 × 4). - */ -TEST_F(PawnPseudoLegalMovesTest, WhitePawnOnSeventhRankMultiplePromotions) { - Board board("8/PPP5/8/8/8/8/8/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 12); - EXPECT_EQ(count_promotions(moves), 12); -} - -/** - * @test Verifies 3 Black pawns on rank 2 generate 12 promotion moves (3 × 4). - */ -TEST_F(PawnPseudoLegalMovesTest, BlackPawnOnSeventhRankMultiplePromotions) { - Board board("8/8/8/8/8/8/ppp5/8 b - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 12); - EXPECT_EQ(count_promotions(moves), 12); -} - -/** - * @test Verifies White pawn blocked on A-file edge. - */ -TEST_F(PawnPseudoLegalMovesTest, PawnOnEdgeFileAFile) { - Board board("8/8/8/8/8/p7/P7/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies White pawn blocked on H-file edge. - */ -TEST_F(PawnPseudoLegalMovesTest, PawnOnEdgeFileHFile) { - Board board("8/8/8/8/8/7p/7P/8 w - - 0 1"); - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies pawn moves never have castling flag set. - */ -TEST_F(PawnPseudoLegalMovesTest, AllMovesHaveNoCastlingFlag) { - Board board; - - PawnMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - EXPECT_FALSE(move.is_castling) << "Pawn moves should never have castling flag"; - } -} diff --git a/tests/bitbishop/moves/pawn_move_generator/test_pmg_single_push.cpp b/tests/bitbishop/moves/pawn_move_generator/test_pmg_single_push.cpp deleted file mode 100644 index 858142d..0000000 --- a/tests/bitbishop/moves/pawn_move_generator/test_pmg_single_push.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include - -#include - -/** - * @test Verifies single_push returns the correct pre-computed array for White pawns. - */ -TEST(PawnMoveGeneratorTest, SinglePushWhiteReturnsCorrectArray) { - auto result = PawnMoveGenerator::single_push(Color::WHITE); - EXPECT_EQ(result.size(), 64); - EXPECT_EQ(result, Lookups::WHITE_PAWN_SINGLE_PUSH); -} - -/** - * @test Verifies single_push returns the correct pre-computed array for Black pawns. - */ -TEST(PawnMoveGeneratorTest, SinglePushBlackReturnsCorrectArray) { - auto result = PawnMoveGenerator::single_push(Color::BLACK); - EXPECT_EQ(result.size(), 64); - EXPECT_EQ(result, Lookups::BLACK_PAWN_SINGLE_PUSH); -} - -/** - * @test Confirms White and Black single push arrays are distinct. - * - * White pawns move up (+1 rank), Black pawns move down (-1 rank), - * so their move tables must differ. - */ -TEST(PawnMoveGeneratorTest, SinglePushWhiteAndBlackAreDifferent) { - auto white_result = PawnMoveGenerator::single_push(Color::WHITE); - auto black_result = PawnMoveGenerator::single_push(Color::BLACK); - EXPECT_NE(white_result, black_result); -} diff --git a/tests/bitbishop/moves/queen_move_generator/test_qmg_generate_pseudo_legal_moves.cpp b/tests/bitbishop/moves/queen_move_generator/test_qmg_generate_pseudo_legal_moves.cpp deleted file mode 100644 index 5755b43..0000000 --- a/tests/bitbishop/moves/queen_move_generator/test_qmg_generate_pseudo_legal_moves.cpp +++ /dev/null @@ -1,525 +0,0 @@ -#include - -#include -#include -#include - -/** - * @brief Test fixture for queen pseudo-legal move generation. - */ -class QueenPseudoLegalMovesTest : public ::testing::Test { - protected: - std::vector moves; - - void SetUp() override {} - - void TearDown() override {} -}; - -/** - * @test White queen has no moves from starting position - */ -TEST_F(QueenPseudoLegalMovesTest, StartingPositionWhiteHas0Moves) { - Board board; - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Black queen has no moves from starting position - */ -TEST_F(QueenPseudoLegalMovesTest, StartingPositionBlackHas0Moves) { - Board board; - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test White queen in the center has 27 regular moves (8 directions) - */ -TEST_F(QueenPseudoLegalMovesTest, WhiteQueenCenterEmptyBoardHas27Moves) { - Board board("8/8/8/8/3Q4/8/8/8 w - - 0 1"); // White queen on D4 - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 27); - EXPECT_EQ(count_captures(moves), 0); - - // North Ray (rook-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D8, std::nullopt, false, false, false})); - - // South Ray (rook-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D1, std::nullopt, false, false, false})); - - // East Ray (rook-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::H4, std::nullopt, false, false, false})); - - // West Ray (rook-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A4, std::nullopt, false, false, false})); - - // North East Ray (bishop-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::H8, std::nullopt, false, false, false})); - - // North West Ray (bishop-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A7, std::nullopt, false, false, false})); - - // South East Ray (bishop-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G1, std::nullopt, false, false, false})); - - // South West Ray (bishop-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test Black queen in the center has 27 regular moves (8 directions) - */ -TEST_F(QueenPseudoLegalMovesTest, BlackQueenCenterEmptyBoardHas27Moves) { - Board board("8/8/8/8/3q4/8/8/8 b - - 0 1"); // Black queen on D4 - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 27); - EXPECT_EQ(count_captures(moves), 0); - - // North Ray (rook-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D8, std::nullopt, false, false, false})); - - // South Ray (rook-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D1, std::nullopt, false, false, false})); - - // East Ray (rook-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::H4, std::nullopt, false, false, false})); - - // West Ray (rook-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A4, std::nullopt, false, false, false})); - - // North East Ray (bishop-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::H8, std::nullopt, false, false, false})); - - // North West Ray (bishop-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A7, std::nullopt, false, false, false})); - - // South East Ray (bishop-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::G1, std::nullopt, false, false, false})); - - // South West Ray (bishop-like) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test White queen in corner has 21 regular moves - */ -TEST_F(QueenPseudoLegalMovesTest, WhiteQueenCornerHas21Moves) { - Board board("7Q/8/8/8/8/8/8/8 w - - 0 1"); // White queen on H8 - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 21); - EXPECT_EQ(count_captures(moves), 0); - - // South Ray - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::H7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::H6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::H5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::H4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::H3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::H2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::H1, std::nullopt, false, false, false})); - - // West Ray - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::G8, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::F8, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::E8, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::D8, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::C8, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::B8, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::A8, std::nullopt, false, false, false})); - - // South West Ray (diagonal) - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::G7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::F6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::E5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::D4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::B2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::H8, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test Black queen in corner has 21 regular moves - */ -TEST_F(QueenPseudoLegalMovesTest, BlackQueenCornerHas21Moves) { - Board board("8/8/8/8/8/8/8/q7 b - - 0 1"); // Black queen on A1 - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 21); - EXPECT_EQ(count_captures(moves), 0); - - // North Ray - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A8, std::nullopt, false, false, false})); - - // East Ray - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::B1, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::C1, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::D1, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::E1, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::F1, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::G1, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::H1, std::nullopt, false, false, false})); - - // North East Ray (diagonal) - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::B2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::C3, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::D4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::E5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::F6, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::G7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::H8, std::nullopt, false, false, false})); -} - -/** - * @test White queen on edge has 21 regular moves - */ -TEST_F(QueenPseudoLegalMovesTest, WhiteQueenEdgeHas21Moves) { - Board board("8/8/8/8/7Q/8/8/8 w - - 0 1"); // White queen on H4 - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 21); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Black queen on edge has 21 regular moves - */ -TEST_F(QueenPseudoLegalMovesTest, BlackQueenEdgeHas21Moves) { - Board board("8/8/8/8/q7/8/8/8 b - - 0 1"); // Black queen on A4 - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 21); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test White queen can capture enemy pieces and stops at capture - */ -TEST_F(QueenPseudoLegalMovesTest, WhiteQueenCanCaptureEnemyPieces) { - // White queen on D4 with black pawns on D6 (north), F4 (east), F6 (NE), B2 (SW) - Board board("8/8/3p1p2/8/3Q1p2/8/1p6/8 w - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 4); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, true, false, false})); - - // Should not go beyond captures - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::D7, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::G4, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test Black queen can capture enemy pieces and stops at capture - */ -TEST_F(QueenPseudoLegalMovesTest, BlackQueenCanCaptureEnemyPieces) { - // Black queen on D4 with white pawns on D6 (north), F4 (east), F6 (NE), B2 (SW) - Board board("8/8/3P1P2/8/3q1P2/8/1P6/8 b - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 4); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, true, false, false})); -} - -/** - * @test White queen cannot capture own pieces and stops before them - */ -TEST_F(QueenPseudoLegalMovesTest, WhiteQueenCannotCaptureOwnPieces) { - // White queen on D4 with white pawns on D6 (north), F4 (east), F6 (NE), B2 (SW) - Board board("8/8/3P1P2/8/3Q1P2/8/1P6/8 w - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 0); - - // North Ray - should stop before D6 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D5, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::D7, std::nullopt, false, false, false})); - - // East Ray - should stop before F4 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E4, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::G4, std::nullopt, false, false, false})); - - // North East Ray - should stop before F6 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, false, false, false})); - - // South West Ray - should stop before B2 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test Black queen cannot capture own pieces and stops before them - */ -TEST_F(QueenPseudoLegalMovesTest, BlackQueenCannotCaptureOwnPieces) { - // Black queen on D4 with black pawns on D6 (north), F4 (east), F6 (NE), B2 (SW) - Board board("8/8/3p1p2/8/3q1p2/8/1p6/8 b - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 0); - - // North Ray - should stop before D6 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D5, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::D7, std::nullopt, false, false, false})); - - // East Ray - should stop before F4 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E4, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::G4, std::nullopt, false, false, false})); - - // North East Ray - should stop before F6 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::G7, std::nullopt, false, false, false})); - - // South West Ray - should stop before B2 (own piece) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::B2, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test White queen with mixed occupancy (own and enemy pieces on different rays) - */ -TEST_F(QueenPseudoLegalMovesTest, WhiteQueenMixedOccupancy) { - // White queen on D4 - // White knight on D6 (N), black rook on F4 (E) - // White pawn on C3 (SW), black queen on E5 (NE) - Board board("8/8/3N4/4q3/3Q1r2/2P5/8/8 w - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 2); - - // Can capture enemy pieces - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, true, false, false})); - - // Cannot capture own pieces - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); -} - -/** - * @test Black queen with mixed occupancy (own and enemy pieces on different rays) - */ -TEST_F(QueenPseudoLegalMovesTest, BlackQueenMixedOccupancy) { - // Black queen on D4 - // Black knight on D6 (N), white rook on F4 (E) - // Black pawn on C3 (SW), white queen on E5 (NE) - Board board("8/8/3n4/4Q3/3q1R2/2p5/8/8 b - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 2); - - // Can capture enemy pieces - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, true, false, false})); - - // Cannot capture own pieces - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, false, false, false})); -} - -/** - * @test Multiple white queens on the board (after promotion) - */ -TEST_F(QueenPseudoLegalMovesTest, MultipleWhiteQueens) { - // Two white queens on D4 and E5 - Board board("8/8/8/4Q3/3Q4/8/8/8 w - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - // Each queen should have moves, though some rays will be blocked by the other queen - EXPECT_GT(moves.size(), 0); - - // D4 queen can move to C4, B4, A4 (west ray unblocked) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A4, std::nullopt, false, false, false})); - - // E5 queen can move to F5, G5, H5 (east ray unblocked) - EXPECT_TRUE(contains_move(moves, {Squares::E5, Squares::F5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::E5, Squares::G5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::E5, Squares::H5, std::nullopt, false, false, false})); - - // D4 queen cannot move through or capture E5 queen (friendly) - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); -} - -/** - * @test Multiple black queens on the board (after promotion) - */ -TEST_F(QueenPseudoLegalMovesTest, MultipleBlackQueens) { - // Two black queens on D4 and E5 - Board board("8/8/8/4q3/3q4/8/8/8 b - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - // Each queen should have moves, though some rays will be blocked by the other queen - EXPECT_GT(moves.size(), 0); - - // D4 queen can move to C4, B4, A4 (west ray unblocked) - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::A4, std::nullopt, false, false, false})); - - // E5 queen can move to F5, G5, H5 (east ray unblocked) - EXPECT_TRUE(contains_move(moves, {Squares::E5, Squares::F5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::E5, Squares::G5, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::E5, Squares::H5, std::nullopt, false, false, false})); - - // D4 queen cannot move through or capture E5 queen (friendly) - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, false, false, false})); - EXPECT_FALSE(contains_move(moves, {Squares::D4, Squares::F6, std::nullopt, false, false, false})); -} - -/** - * @test White queen fully surrounded by own pieces has no moves - */ -TEST_F(QueenPseudoLegalMovesTest, WhiteQueenFullySurrounded) { - // White queen on D4 completely surrounded by white pawns - Board board("8/8/8/2PPP3/2PQP3/2PPP3/8/8 w - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Black queen fully surrounded by own pieces has no moves - */ -TEST_F(QueenPseudoLegalMovesTest, BlackQueenFullySurrounded) { - // Black queen on D4 completely surrounded by black pawns - Board board("8/8/8/2ppp3/2pqp3/2ppp3/8/8 b - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test White queen can capture all surrounding enemy pieces - */ -TEST_F(QueenPseudoLegalMovesTest, WhiteQueenCanCaptureAllSurrounding) { - // White queen on D4 completely surrounded by black pawns - Board board("8/8/8/2ppp3/2pQp3/2ppp3/8/8 w - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 8); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D5, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D3, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C5, std::nullopt, true, false, false})); -} - -/** - * @test Black queen can capture all surrounding enemy pieces - */ -TEST_F(QueenPseudoLegalMovesTest, BlackQueenCanCaptureAllSurrounding) { - // Black queen on D4 completely surrounded by white pawns - Board board("8/8/8/2PPP3/2PqP3/2PPP3/8/8 b - - 0 1"); - - QueenMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 8); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D5, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E5, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::E3, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D3, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C3, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::C5, std::nullopt, true, false, false})); -} diff --git a/tests/bitbishop/moves/rook_move_generator/test_rmg_add_rook_castling.cpp b/tests/bitbishop/moves/rook_move_generator/test_rmg_add_rook_castling.cpp deleted file mode 100644 index 620a916..0000000 --- a/tests/bitbishop/moves/rook_move_generator/test_rmg_add_rook_castling.cpp +++ /dev/null @@ -1,247 +0,0 @@ -#include - -#include -#include -#include -#include -#include - -/** - * @test RookMoveGenerator::add_rook_castling() with no castling rights - * @brief Verifies that no castling moves are added when castling rights are not available. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingWhiteNoCastlingRights) { - Board board("8/8/8/8/8/8/8/R3K2R w - - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 0); - - RookMoveGenerator::add_rook_castling(moves, Squares::H1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test RookMoveGenerator::add_rook_castling() with no castling rights - * @brief Verifies that no castling moves are added when castling rights are not available. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingBlackNoCastlingRights) { - Board board("r3k2r/8/8/8/8/8/8/8 w - - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 0); - - RookMoveGenerator::add_rook_castling(moves, Squares::H8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test RookMoveGenerator::add_rook_castling() with both castling rights available - * @brief Verifies that both kingside and queenside castling moves are added when both are legal. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingWhiteBothSidesAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 1); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::WHITE), 1); - - RookMoveGenerator::add_rook_castling(moves, Squares::H1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 2); - EXPECT_EQ(count_rook_kingside_castling(moves, Color::WHITE), 1); -} - -/** - * @test RookMoveGenerator::add_rook_castling() with only kingside castling available - * @brief Verifies that only kingside castling move is added when queenside is not legal. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingWhiteOnlyKingsideAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w K - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::WHITE), 0); - - RookMoveGenerator::add_rook_castling(moves, Squares::H1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 1); - EXPECT_EQ(count_rook_kingside_castling(moves, Color::WHITE), 1); -} - -/** - * @test RookMoveGenerator::add_rook_castling() with only queenside castling available - * @brief Verifies that only queenside castling move is added when kingside is not legal. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingWhiteOnlyQueensideAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w Q - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 1); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::WHITE), 1); - - RookMoveGenerator::add_rook_castling(moves, Squares::H1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 1); - EXPECT_EQ(count_rook_kingside_castling(moves, Color::WHITE), 0); -} - -/** - * @test RookMoveGenerator::add_rook_castling() for black with both sides available - * @brief Verifies that castling moves are correctly generated for black pieces. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingBlackBothSidesAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 1); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::BLACK), 1); - - RookMoveGenerator::add_rook_castling(moves, Squares::H8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 2); - EXPECT_EQ(count_rook_kingside_castling(moves, Color::BLACK), 1); -} - -/** - * @test RookMoveGenerator::add_rook_castling() for black with only kingside available - * @brief Verifies that only kingside castling is added for black when queenside is blocked. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingBlackOnlyKingsideAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b k - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::BLACK), 0); - - RookMoveGenerator::add_rook_castling(moves, Squares::H8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 1); - EXPECT_EQ(count_rook_kingside_castling(moves, Color::BLACK), 1); -} - -/** - * @test RookMoveGenerator::add_rook_castling() for black with only queenside available - * @brief Verifies that only queenside castling is added for black when kingside is blocked. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingBlackOnlyQueensideAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b q - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 1); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::BLACK), 1); - - RookMoveGenerator::add_rook_castling(moves, Squares::H8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 1); - EXPECT_EQ(count_rook_kingside_castling(moves, Color::BLACK), 0); -} - -/** - * @test RookMoveGenerator::add_rook_castling() with pieces blocking castling - * @brief Verifies that castling moves are not added when pieces block the path. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingWhiteBlockedByPieces) { - Board board("8/8/8/8/8/8/8/R1B1KN1R w KQ - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 0); - - RookMoveGenerator::add_rook_castling(moves, Squares::H1, Color::WHITE, board); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test RookMoveGenerator::add_rook_castling() with pieces blocking castling - * @brief Verifies that castling moves are not added when pieces block the path. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingBlackBlockedByPieces) { - Board board("r1b1kn1r/8/8/8/8/8/8/8 w kq - 0 1"); - - std::vector moves; - - RookMoveGenerator::add_rook_castling(moves, Squares::A8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 0); - - RookMoveGenerator::add_rook_castling(moves, Squares::H8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test RookMoveGenerator::add_rook_castling() with invalid starting square for a black rook - * @brief Verifies that castling moves are not added when black rook's starting position is invalid. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingWhiteInvalidFromSquare) { - Board board("8/8/8/8/8/8/8/R1B1KN1R w KQ - 0 1"); - - std::vector moves; - - // Should start from square A1 for white pieces - RookMoveGenerator::add_rook_castling(moves, Squares::A8, Color::BLACK, board); - RookMoveGenerator::add_rook_castling(moves, Squares::D4, Color::BLACK, board); - RookMoveGenerator::add_rook_castling(moves, Squares::E1, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 0); - - // Should start from square H1 for white pieces - RookMoveGenerator::add_rook_castling(moves, Squares::H8, Color::BLACK, board); - RookMoveGenerator::add_rook_castling(moves, Squares::D5, Color::BLACK, board); - RookMoveGenerator::add_rook_castling(moves, Squares::E1, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test RookMoveGenerator::add_rook_castling() with invalid starting square for a white rook - * @brief Verifies that castling moves are not added when white rook's starting position is invalid. - */ -TEST(RookMoveGeneratorTest, AddRookCastlingBlackInvalidFromSquare) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - std::vector moves; - - // Should start from square A8 for white pieces - RookMoveGenerator::add_rook_castling(moves, Squares::A1, Color::BLACK, board); - RookMoveGenerator::add_rook_castling(moves, Squares::D4, Color::BLACK, board); - RookMoveGenerator::add_rook_castling(moves, Squares::E8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 0); - - // Should start from square H8 for white pieces - RookMoveGenerator::add_rook_castling(moves, Squares::H1, Color::BLACK, board); - RookMoveGenerator::add_rook_castling(moves, Squares::D5, Color::BLACK, board); - RookMoveGenerator::add_rook_castling(moves, Squares::E8, Color::BLACK, board); - - EXPECT_EQ(moves.size(), 0); -} diff --git a/tests/bitbishop/moves/rook_move_generator/test_rmg_generate_pseudo_legal_moves.cpp b/tests/bitbishop/moves/rook_move_generator/test_rmg_generate_pseudo_legal_moves.cpp deleted file mode 100644 index ca1e8d9..0000000 --- a/tests/bitbishop/moves/rook_move_generator/test_rmg_generate_pseudo_legal_moves.cpp +++ /dev/null @@ -1,573 +0,0 @@ -#include - -#include -#include -#include - -/** - * @brief Test fixture for rook pseudo-legal move generation. - */ -class RookPseudoLegalMovesTest : public ::testing::Test { - protected: - std::vector moves; - - void SetUp() override {} - - void TearDown() override {} -}; - -/** - * @test Verifies White rooks have 0 moves from starting position (blocked by own pieces). - */ -TEST_F(RookPseudoLegalMovesTest, StartingPositionWhiteHas0Moves) { - Board board; - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies Black rooks have 0 moves from starting position (blocked by own pieces). - */ -TEST_F(RookPseudoLegalMovesTest, StartingPositionBlackHas0Moves) { - Board board; - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies White rooks have no captures from starting position. - */ -TEST_F(RookPseudoLegalMovesTest, StartingPositionWhiteHasNoCaptures) { - Board board; - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black rooks have no captures from starting position. - */ -TEST_F(RookPseudoLegalMovesTest, StartingPositionBlackHasNoCaptures) { - Board board; - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White rook on empty board generates 14 moves (7 in each direction). - */ -TEST_F(RookPseudoLegalMovesTest, WhiteRookCenterEmptyBoardHas14Moves) { - Board board("8/8/8/8/3R4/8/8/8 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 14); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black rook on empty board generates 14 moves (7 in each direction). - */ -TEST_F(RookPseudoLegalMovesTest, BlackRookCenterEmptyBoardHas14Moves) { - Board board("8/8/8/8/3r4/8/8/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 14); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White rook in corner has 14 moves on empty board. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteRookInCornerHas14Moves) { - Board board("8/8/8/8/8/8/8/R7 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 14); - // Should have 7 moves north and 7 moves east - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black rook in corner has 14 moves on empty board. - */ -TEST_F(RookPseudoLegalMovesTest, BlackRookInCornerHas14Moves) { - Board board("r7/8/8/8/8/8/8/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 14); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White rook can capture enemy pieces in all four directions. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteRookCanCaptureEnemyPieces) { - Board board("8/8/8/3p4/2pRp3/3p4/8/8 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 4); - EXPECT_EQ(count_captures(moves), 4); -} - -/** - * @test Verifies Black rook can capture enemy pieces in all four directions. - */ -TEST_F(RookPseudoLegalMovesTest, BlackRookCanCaptureEnemyPieces) { - Board board("8/8/8/3P4/2PrP3/3P4/8/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 4); - EXPECT_EQ(count_captures(moves), 4); -} - -/** - * @test Verifies White rook cannot capture own pieces. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteRookCannotCaptureOwnPieces) { - Board board("8/8/8/3P4/2PRP3/3P4/8/8 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies Black rook cannot capture own pieces. - */ -TEST_F(RookPseudoLegalMovesTest, BlackRookCannotCaptureOwnPieces) { - Board board("8/8/8/3p4/2prp3/3p4/8/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 0); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White rook with mix of blocked and available squares. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteRookMixedOccupancy) { - Board board("8/8/8/3p4/2PRp3/3P4/8/8 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_captures(moves), 2); - EXPECT_EQ(moves.size(), 2); -} - -/** - * @test Verifies Black rook with mix of blocked and available squares. - */ -TEST_F(RookPseudoLegalMovesTest, BlackRookMixedOccupancy) { - Board board("8/8/8/3P4/2prP3/3p4/8/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_captures(moves), 2); - EXPECT_EQ(moves.size(), 2); -} - -/** - * @test Verifies White rook moves along rank are generated correctly. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteRookMovesAlongRank) { - Board board("8/8/8/8/R7/8/8/8 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 14); - - EXPECT_TRUE(contains_move(moves, {Squares::A4, Squares::B4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A4, Squares::H4, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black rook moves along rank are generated correctly. - */ -TEST_F(RookPseudoLegalMovesTest, BlackRookMovesAlongRank) { - Board board("8/8/8/8/r7/8/8/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 14); - EXPECT_TRUE(contains_move(moves, {Squares::A4, Squares::B4, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A4, Squares::H4, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White rook moves along file are generated correctly. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteRookMovesAlongFile) { - Board board("8/8/8/8/8/8/8/R7 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 14); - - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A2, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A1, Squares::A8, std::nullopt, false, false, false})); -} - -/** - * @test Verifies Black rook moves along file are generated correctly. - */ -TEST_F(RookPseudoLegalMovesTest, BlackRookMovesAlongFile) { - Board board("r7/8/8/8/8/8/8/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 14); - EXPECT_TRUE(contains_move(moves, {Squares::A8, Squares::A7, std::nullopt, false, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::A8, Squares::A1, std::nullopt, false, false, false})); -} - -/** - * @test Verifies White rook stops at first blocker in each direction. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteRookStopsAtBlocker) { - Board board("3p4/3p4/3p4/8/pp1R1ppp/8/3p4/3p4 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 4); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D2, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, true, false, false})); -} - -/** - * @test Verifies Black rook stops at first blocker in each direction. - */ -TEST_F(RookPseudoLegalMovesTest, BlackRookStopsAtBlocker) { - Board board("8/8/3P4/8/PP1r1PPP/8/3P4/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(moves.size(), 8); - EXPECT_EQ(count_captures(moves), 4); - - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D6, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::D2, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::B4, std::nullopt, true, false, false})); - EXPECT_TRUE(contains_move(moves, {Squares::D4, Squares::F4, std::nullopt, true, false, false})); -} - -/** - * @test Verifies multiple White rooks generate moves independently. - */ -TEST_F(RookPseudoLegalMovesTest, MultipleWhiteRooksGenerateMoves) { - Board board("8/8/8/8/R6R/8/8/8 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - // Each rook has 13 moves, total 26 - EXPECT_EQ(moves.size(), 26); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies multiple Black rooks generate moves independently. - */ -TEST_F(RookPseudoLegalMovesTest, MultipleBlackRooksGenerateMoves) { - Board board("8/8/8/8/r6r/8/8/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - // Each rook has 13 moves, total 26 - EXPECT_EQ(moves.size(), 26); - EXPECT_EQ(count_captures(moves), 0); -} - -/** - * @test Verifies White kingside castling is available from starting position. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteBothCastlingAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::WHITE), 1); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::WHITE), 1); -} - -/** - * @test Verifies Black kingside castling is available from starting position. - */ -TEST_F(RookPseudoLegalMovesTest, BlackBothCastlingAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::BLACK), 1); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::BLACK), 1); -} - -/** - * @test Verifies White castling unavailable when castling rights are lost. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteCastlingUnavailableWithoutRights) { - Board board("8/8/8/8/8/8/8/R3K2R w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::WHITE), 0); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::WHITE), 0); -} - -/** - * @test Verifies Black castling unavailable when castling rights are lost. - */ -TEST_F(RookPseudoLegalMovesTest, BlackCastlingUnavailableWithoutRights) { - Board board("r3k2r/8/8/8/8/8/8/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::BLACK), 0); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::BLACK), 0); -} - -/** - * @test Verifies White can only castle kingside when queenside rights are lost. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteOnlyKingsideCastlingAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w K - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::WHITE), 1); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::WHITE), 0); -} - -/** - * @test Verifies White can only castle queenside when kingside rights are lost. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteOnlyQueensideCastlingAvailable) { - Board board("8/8/8/8/8/8/8/R3K2R w Q - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::WHITE), 0); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::WHITE), 1); -} - -/** - * @test Verifies Black can only castle kingside when queenside rights are lost. - */ -TEST_F(RookPseudoLegalMovesTest, BlackOnlyKingsideCastlingAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b k - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::BLACK), 1); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::BLACK), 0); -} - -/** - * @test Verifies Black can only castle queenside when kingside rights are lost. - */ -TEST_F(RookPseudoLegalMovesTest, BlackOnlyQueensideCastlingAvailable) { - Board board("r3k2r/8/8/8/8/8/8/8 b q - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::BLACK), 0); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::BLACK), 1); -} - -/** - * @test Verifies White castling blocked when pieces obstruct the path. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteCastlingBlockedByPieces) { - Board board("8/8/8/8/8/8/8/R1B1KN1R w KQ - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::WHITE), 0); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::WHITE), 0); -} - -/** - * @test Verifies Black castling blocked when pieces obstruct the path. - */ -TEST_F(RookPseudoLegalMovesTest, BlackCastlingBlockedByPieces) { - Board board("r1b1kn1r/8/8/8/8/8/8/8 b kq - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - EXPECT_EQ(count_rook_kingside_castling(moves, Color::BLACK), 0); - EXPECT_EQ(count_rook_queenside_castling(moves, Color::BLACK), 0); -} - -/** - * @test Verifies all rook moves have no promotion flag. - */ -TEST_F(RookPseudoLegalMovesTest, AllMovesHaveNoPromotionFlag) { - Board board("8/8/8/8/3R4/8/8/8 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(count_promotions(moves), 0); -} - -/** - * @test Verifies all rook moves have no en passant flag. - */ -TEST_F(RookPseudoLegalMovesTest, AllMovesHaveNoEnPassantFlag) { - Board board("8/8/8/8/3R4/8/8/8 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - EXPECT_FALSE(move.is_en_passant) << "Rook moves should never be en passant"; - } -} - -/** - * @test Verifies only castling moves have castling flag set. - */ -TEST_F(RookPseudoLegalMovesTest, OnlyCastlingMovesHaveCastlingFlag) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - for (const auto& move : moves) { - if (move.is_castling) { - EXPECT_TRUE(move.is_castling); - } else { - EXPECT_FALSE(move.is_castling); - } - } -} - -/** - * @test Verifies complex position with captures, regular moves, and castling. - */ -TEST_F(RookPseudoLegalMovesTest, ComplexPositionMixedMoves) { - Board board("8/8/3p4/8/ppppRppp/8/4P3/8 b - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 7); - EXPECT_EQ(count_captures(moves), 2); - EXPECT_EQ(count_quiet_moves(moves), 5); -} - -/** - * @test Verifies rook with long-range captures. - */ -TEST_F(RookPseudoLegalMovesTest, RookLongRangeCapture) { - Board board("8/8/8/8/R6p/8/8/8 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - // Should be able to capture on H4 - EXPECT_TRUE(contains_move(moves, {Squares::A4, Squares::H4, std::nullopt, true, false, false})); -} - -/** - * @test Verifies no moves generated when no rooks present. - */ -TEST_F(RookPseudoLegalMovesTest, NoMovesWhenNoRooks) { - Board board("8/8/8/8/8/8/8/4K3 w - - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - EXPECT_EQ(moves.size(), 0); -} - -/** - * @test Verifies castling moves have correct properties for White kingside. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteKingsideCastlingCorrectProperties) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - bool found_kingside = false; - for (const auto& move : moves) { - if (move.is_castling && move.from == Squares::H1 && move.to == Squares::F1) { - EXPECT_FALSE(move.is_capture); - EXPECT_FALSE(move.is_en_passant); - EXPECT_FALSE(move.promotion.has_value()); - found_kingside = true; - } - } - EXPECT_TRUE(found_kingside) << "White kingside castling move should be present"; -} - -/** - * @test Verifies castling moves have correct properties for White queenside. - */ -TEST_F(RookPseudoLegalMovesTest, WhiteQueensideCastlingCorrectProperties) { - Board board("8/8/8/8/8/8/8/R3K2R w KQ - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::WHITE); - - bool found_queenside = false; - for (const auto& move : moves) { - if (move.is_castling && move.from == Squares::A1 && move.to == Squares::D1) { - EXPECT_FALSE(move.is_capture); - EXPECT_FALSE(move.is_en_passant); - EXPECT_FALSE(move.promotion.has_value()); - found_queenside = true; - } - } - EXPECT_TRUE(found_queenside) << "White queenside castling move should be present"; -} - -/** - * @test Verifies castling moves have correct properties for Black kingside. - */ -TEST_F(RookPseudoLegalMovesTest, BlackKingsideCastlingCorrectProperties) { - Board board("r3k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - bool found_kingside = false; - for (const auto& move : moves) { - if (move.is_castling && move.from == Squares::H8 && move.to == Squares::F8) { - EXPECT_FALSE(move.is_capture); - EXPECT_FALSE(move.is_en_passant); - EXPECT_FALSE(move.promotion.has_value()); - found_kingside = true; - } - } - EXPECT_TRUE(found_kingside) << "Black kingside castling move should be present"; -} - -/** - * @test Verifies castling moves have correct properties for Black queenside. - */ -TEST_F(RookPseudoLegalMovesTest, BlackQueensideCastlingCorrectProperties) { - Board board("r3k2r/8/8/8/8/8/8/8 b kq - 0 1"); - - RookMoveGenerator::generate_pseudo_legal_moves(moves, board, Color::BLACK); - - bool found_queenside = false; - for (const auto& move : moves) { - if (move.is_castling && move.from == Squares::A8 && move.to == Squares::D8) { - EXPECT_FALSE(move.is_capture); - EXPECT_FALSE(move.is_en_passant); - EXPECT_FALSE(move.promotion.has_value()); - found_queenside = true; - } - } - EXPECT_TRUE(found_queenside) << "Black queenside castling move should be present"; -}