Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions include/bitbishop/move.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,67 @@ struct Move {
bool is_capture; ///< True if the move captures an opponent's piece.
bool is_en_passant; ///< True if the move is an en passant capture.
bool is_castling; ///< True if the move is a castling move (kingside or queenside).

/**
* @brief Creates a normal (non-special) move.
* @param from The starting square of the move.
* @param to The target square of the move.
* @param is_capture True if the move captures an opponent's piece; false otherwise.
* @return A Move instance representing the normal move.
*/
static Move make(Square from, Square to, bool is_capture = false) {
return {.from = from,
.to = to,
.promotion = std::nullopt,
.is_capture = is_capture,
.is_en_passant = false,
.is_castling = false};
}

/**
* @brief Creates a pawn promotion move.
* @param from The starting square of the pawn.
* @param to The target square where the promotion occurs.
* @param piece The piece type to promote the pawn into.
* @param is_capture True if the move captures an opponent's piece; false otherwise.
* @return A Move instance representing the promotion move.
*/
static Move make_promotion(Square from, Square to, Piece piece, bool is_capture = false) {
return {.from = from,
.to = to,
.promotion = piece,
.is_capture = is_capture,
.is_en_passant = false,
.is_castling = false};
}

/**
* @brief Creates an en passant capture move.
* @param from The starting square of the capturing pawn.
* @param to The target square where the capturing pawn lands.
* @return A Move instance representing the en passant capture.
*/
static Move make_en_passant(Square from, Square to) {
return {.from = from,
.to = to,
.promotion = std::nullopt,
.is_capture = true,
.is_en_passant = true,
.is_castling = false};
}

/**
* @brief Creates a castling move.
* @param from The starting square of the king.
* @param to The target square of the king during castling.
* @return A Move instance representing the castling move.
*/
static Move make_castling(Square from, Square to) {
return {.from = from,
.to = to,
.promotion = std::nullopt,
.is_capture = false,
.is_en_passant = false,
.is_castling = true};
}
};
2 changes: 1 addition & 1 deletion include/bitbishop/movegen/bishop_moves.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void generate_bishop_legal_moves(std::vector<Move>& moves, const Board& board, C

for (Square to : candidates) {
const bool is_capture = enemy.test(to);
moves.emplace_back(from, to, std::nullopt, is_capture, false, false);
moves.emplace_back(Move::make(from, to, is_capture));
}
}
}
4 changes: 2 additions & 2 deletions include/bitbishop/movegen/castling_moves.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void generate_castling_moves(std::vector<Move>& moves, const Board& board, Color
Square g_square = (us == Color::WHITE) ? G1 : G8;

if (!enemy_attacks.test(f_square) && !enemy_attacks.test(g_square)) {
moves.emplace_back(king_from, g_square, std::nullopt, false, false, true);
moves.emplace_back(Move::make_castling(king_from, g_square));
}
}

Expand All @@ -51,7 +51,7 @@ void generate_castling_moves(std::vector<Move>& moves, const Board& board, Color
Square c_square = (us == Color::WHITE) ? C1 : C8;

if (!enemy_attacks.test(d_square) && !enemy_attacks.test(c_square)) {
moves.emplace_back(king_from, c_square, std::nullopt, false, false, true);
moves.emplace_back(Move::make_castling(king_from, c_square));
}
}
}
2 changes: 1 addition & 1 deletion include/bitbishop/movegen/king_moves.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ void generate_legal_king_moves(std::vector<Move>& moves, const Board& board, Col

for (Square to : candidates) {
const bool is_capture = enemy.test(to);
moves.emplace_back(king_sq, to, std::nullopt, is_capture, false, false);
moves.emplace_back(Move::make(king_sq, to, is_capture));
}
}
2 changes: 1 addition & 1 deletion include/bitbishop/movegen/knight_moves.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void generate_knight_legal_moves(std::vector<Move>& moves, const Board& board, C

for (Square to : candidates) {
const bool is_capture = enemy.test(to);
moves.emplace_back(from, to, std::nullopt, is_capture, false, false);
moves.emplace_back(Move::make(from, to, is_capture));
}
}
}
13 changes: 7 additions & 6 deletions include/bitbishop/movegen/pawn_moves.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ void add_pawn_promotions(std::vector<Move>& moves, Square from, Square to, Color
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);
moves.emplace_back(Move::make_promotion(from, to, piece, capture));
}
}

Expand Down Expand Up @@ -129,7 +129,7 @@ inline void generate_single_push(std::vector<Move>& moves, Square from, Color us
if (is_promotion_rank(to, us)) {
add_pawn_promotions(moves, from, to, us, false);
} else {
moves.emplace_back(from, to, std::nullopt, false, false, false);
moves.emplace_back(Move::make(from, to));
}
}
}
Expand Down Expand Up @@ -164,7 +164,7 @@ inline void generate_double_push(std::vector<Move>& moves, Square from, Color us
Bitboard single_bb = single_push[from.flat_index()] & occupied;
if (single_bb.empty() && bb) {
Square to = bb.pop_lsb().value();
moves.emplace_back(from, to, std::nullopt, false, false, false);
moves.emplace_back(Move::make(from, to));
}
}

Expand All @@ -190,11 +190,12 @@ inline void generate_captures(std::vector<Move>& moves, Square from, Color us, c
bb &= check_mask;
bb &= pin_mask;

constexpr bool is_capture = true;
for (Square to : bb) {
if (is_promotion_rank(to, us)) {
add_pawn_promotions(moves, from, to, us, true);
add_pawn_promotions(moves, from, to, us, is_capture);
} else {
moves.emplace_back(from, to, std::nullopt, true, false, false);
moves.emplace_back(Move::make(from, to, is_capture));
}
}
}
Expand Down Expand Up @@ -241,7 +242,7 @@ inline void generate_en_passant(std::vector<Move>& moves, Square from, Color us,
Bitboard attackers = generate_attacks(tmp, them);

if (!attackers.test(king_sq)) {
moves.emplace_back(from, epsq, std::nullopt, true, true, false);
moves.emplace_back(Move::make_en_passant(from, epsq));
}
}

Expand Down
2 changes: 1 addition & 1 deletion include/bitbishop/movegen/queen_moves.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void generate_queen_legal_moves(std::vector<Move>& moves, const Board& board, Co

for (Square to : candidates) {
const bool is_capture = enemy.test(to);
moves.emplace_back(from, to, std::nullopt, is_capture, false, false);
moves.emplace_back(Move::make(from, to, is_capture));
}
}
}
2 changes: 1 addition & 1 deletion include/bitbishop/movegen/rook_moves.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ void generate_rook_legal_moves(std::vector<Move>& moves, const Board& board, Col

for (Square to : candidates) {
const bool is_capture = enemy.test(to);
moves.emplace_back(from, to, std::nullopt, is_capture, false, false);
moves.emplace_back(Move::make(from, to, is_capture));
}
}
}
2 changes: 1 addition & 1 deletion tests/bitbishop/movegen/test_bishop_moves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ TEST(GenerateBishopLegalMovesTest, MovesVectorAccumulates) {

std::vector<Move> moves;
// Add a dummy move first
moves.emplace_back(A1, A2, std::nullopt, false, false, false);
moves.emplace_back(Move::make(A1, A2));

Bitboard check_mask = Bitboard::Ones();
PinResult pins;
Expand Down
2 changes: 1 addition & 1 deletion tests/bitbishop/movegen/test_castling_moves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ TEST(GenerateCastlingMovesTest, MovesVectorAccumulates) {
Board board("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1");

std::vector<Move> moves;
moves.emplace_back(A1, A2, std::nullopt, false, false, false);
moves.emplace_back(Move::make(A1, A2));

Bitboard checkers = Bitboard::Zeros();
Bitboard enemy_attacks = Bitboard::Zeros();
Expand Down
10 changes: 5 additions & 5 deletions tests/bitbishop/movegen/test_king_moves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ TEST(GenerateLegalKingMovesTest, CornerKingLimitedMoves) {
EXPECT_EQ(moves.size(), 3);

// Corner king can only move to 3 squares
EXPECT_TRUE(contains_move(moves, {A1, A2, std::nullopt, false, false, false}));
EXPECT_TRUE(contains_move(moves, {A1, B1, std::nullopt, false, false, false}));
EXPECT_TRUE(contains_move(moves, {A1, B2, std::nullopt, false, false, false}));
EXPECT_TRUE(contains_move(moves, Move::make(A1, A2)));
EXPECT_TRUE(contains_move(moves, Move::make(A1, B1)));
EXPECT_TRUE(contains_move(moves, Move::make(A1, B2)));
}

/**
Expand Down Expand Up @@ -352,15 +352,15 @@ TEST(GenerateLegalKingMovesTest, MovesVectorAccumulates) {

std::vector<Move> moves;
// Add a dummy move first
moves.emplace_back(A1, A2, std::nullopt, false, false, false);
moves.emplace_back(Move::make(A1, A2));

Bitboard enemy_attacks = Bitboard::Zeros();

generate_legal_king_moves(moves, board, Color::WHITE, E4, enemy_attacks);

// Should have 1 dummy + 8 king moves = 9 total
EXPECT_EQ(moves.size(), 9);
EXPECT_TRUE(contains_move(moves, {A1, A2, std::nullopt, false, false, false}));
EXPECT_TRUE(contains_move(moves, Move::make(A1, A2)));
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/bitbishop/movegen/test_knight_moves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ TEST(GenerateKnightLegalMovesTest, MovesVectorAccumulates) {

std::vector<Move> moves;
// Add a dummy move first
moves.emplace_back(A1, A2, std::nullopt, false, false, false);
moves.emplace_back(Move::make(A1, A2));

Bitboard check_mask = Bitboard::Ones();
PinResult pins;
Expand Down
4 changes: 2 additions & 2 deletions tests/bitbishop/movegen/test_legal_moves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,13 +271,13 @@ TEST(GenerateLegalMovesTest, MovesVectorNotCleared) {
board.set_piece(E8, BLACK_KING);

std::vector<Move> moves;
moves.emplace_back(A1, A2, std::nullopt, false, false, false);
moves.emplace_back(Move::make(A1, A2));

size_t initial_size = moves.size();
generate_legal_moves(moves, board, Color::WHITE);

EXPECT_GT(moves.size(), initial_size);
EXPECT_TRUE(contains_move(moves, {A1, A2, std::nullopt, false, false, false}));
EXPECT_TRUE(contains_move(moves, Move::make(A1, A2)));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -471,15 +471,15 @@ TEST(GeneratePawnLegalMovesTest, MovesVectorAccumulates) {
board.set_piece(E2, WHITE_PAWN);

std::vector<Move> moves;
moves.emplace_back(A1, A2, std::nullopt, false, false, false);
moves.emplace_back(Move::make(A1, A2));

Bitboard check_mask = Bitboard::Ones();
PinResult pins;

generate_pawn_legal_moves(moves, board, Color::WHITE, E1, check_mask, pins);

EXPECT_EQ(moves.size(), 3);
EXPECT_TRUE(contains_move(moves, {A1, A2, std::nullopt, false, false, false}));
EXPECT_TRUE(contains_move(moves, Move::make(A1, A2)));
}

/**
Expand Down
4 changes: 2 additions & 2 deletions tests/bitbishop/movegen/test_queen_moves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ TEST(GenerateQueenLegalMovesTest, MovesVectorAccumulates) {

std::vector<Move> moves;
// Add a dummy move first
moves.emplace_back(A1, A2, std::nullopt, false, false, false);
moves.emplace_back(Move::make(A1, A2));

Bitboard check_mask = Bitboard::Ones();
PinResult pins;
Expand All @@ -399,7 +399,7 @@ TEST(GenerateQueenLegalMovesTest, MovesVectorAccumulates) {

// Should have 1 dummy + 27 queen moves = 28 total
EXPECT_EQ(moves.size(), 28);
EXPECT_TRUE(contains_move(moves, {A1, A2, std::nullopt, false, false, false}));
EXPECT_TRUE(contains_move(moves, Move::make(A1, A2)));
}

/**
Expand Down
4 changes: 2 additions & 2 deletions tests/bitbishop/movegen/test_rook_moves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ TEST(GenerateRookLegalMovesTest, MovesVectorAccumulates) {

std::vector<Move> moves;
// Add a dummy move first
moves.emplace_back(A1, A2, std::nullopt, false, false, false);
moves.emplace_back(Move::make(A1, A2));

Bitboard check_mask = Bitboard::Ones();
PinResult pins;
Expand All @@ -413,7 +413,7 @@ TEST(GenerateRookLegalMovesTest, MovesVectorAccumulates) {

// Should have 1 dummy + 14 rook moves = 15 total
EXPECT_EQ(moves.size(), 15);
EXPECT_TRUE(contains_move(moves, {A1, A2, std::nullopt, false, false, false}));
EXPECT_TRUE(contains_move(moves, Move::make(A1, A2)));
}

/**
Expand Down
Loading