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
12 changes: 10 additions & 2 deletions include/bitbishop/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
class Board {
private:
// Piece bitboards
Bitboard m_w_pawns, m_w_rooks, m_w_bishops, m_w_knights, m_w_king, m_w_queen;
Bitboard m_b_pawns, m_b_rooks, m_b_bishops, m_b_knights, m_b_king, m_b_queen;
Bitboard m_w_pawns, m_w_rooks, m_w_bishops, m_w_knights, m_w_king, m_w_queens;
Bitboard m_b_pawns, m_b_rooks, m_b_bishops, m_b_knights, m_b_king, m_b_queens;

// Game state
bool m_is_white_turn; ///< True if it is White's turn
Expand Down Expand Up @@ -163,6 +163,14 @@ class Board {
*/
[[nodiscard]] Bitboard bishops(Color side) const { return (side == Color::WHITE) ? m_w_bishops : m_b_bishops; }

/**
* @brief Returns a bitboard representing the queen(s) belonging to the given side.
*
* @param side The color corresponding to the side to move (Color::WHITE or Color::BLACK).
* @return Bitboard containing all squares occupied by that side's queen(s).
*/
[[nodiscard]] Bitboard queens(Color side) const { return (side == Color::WHITE) ? m_w_queens : m_b_queens; }

/**
* @brief Returns a bitboard of all enemy pieces relative to the given side to move.
*
Expand Down
4 changes: 4 additions & 0 deletions include/bitbishop/lookups/queen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include <bitbishop/lookups/rook.hpp>
#include <cstdint>

// NOTE: These queen lookups are not used in moves generation code.
// Instead, rook and bishop rays are used individually and reused to generate queen rays,
// as it is the same logic.

namespace Lookups {

/**
Expand Down
34 changes: 34 additions & 0 deletions include/bitbishop/moves/queen_move_gen.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once
#include <bitbishop/board.hpp>
#include <bitbishop/color.hpp>
#include <bitbishop/move.hpp>
#include <vector>

/**
* @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<Move>& moves, const Board& board, Color side);

}; // namespace QueenMoveGenerator
20 changes: 10 additions & 10 deletions src/bitbishop/board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Bitboard Board::white_pieces() const {
bitboard |= m_w_bishops;
bitboard |= m_w_knights;
bitboard |= m_w_king;
bitboard |= m_w_queen;
bitboard |= m_w_queens;
return bitboard;
}

Expand All @@ -88,7 +88,7 @@ Bitboard Board::black_pieces() const {
bitboard |= m_b_bishops;
bitboard |= m_b_knights;
bitboard |= m_b_king;
bitboard |= m_b_queen;
bitboard |= m_b_queens;
return bitboard;
}

Expand All @@ -99,13 +99,13 @@ Bitboard Board::occupied() const {
bitboard |= m_b_bishops;
bitboard |= m_b_knights;
bitboard |= m_b_king;
bitboard |= m_b_queen;
bitboard |= m_b_queens;
bitboard |= m_w_pawns;
bitboard |= m_w_rooks;
bitboard |= m_w_bishops;
bitboard |= m_w_knights;
bitboard |= m_w_king;
bitboard |= m_w_queen;
bitboard |= m_w_queens;
return bitboard;
}

Expand All @@ -115,14 +115,14 @@ std::optional<Piece> Board::get_piece(Square square) const {
if (m_w_knights.test(square)) { return Pieces::WHITE_KNIGHT; }
if (m_w_bishops.test(square)) { return Pieces::WHITE_BISHOP; }
if (m_w_rooks.test(square)) { return Pieces::WHITE_ROOK; }
if (m_w_queen.test(square)) { return Pieces::WHITE_QUEEN; }
if (m_w_queens.test(square)) { return Pieces::WHITE_QUEEN; }
if (m_w_king.test(square)) { return Pieces::WHITE_KING; }

if (m_b_pawns.test(square)) { return Pieces::BLACK_PAWN; }
if (m_b_knights.test(square)) { return Pieces::BLACK_KNIGHT; }
if (m_b_bishops.test(square)) { return Pieces::BLACK_BISHOP; }
if (m_b_rooks.test(square)) { return Pieces::BLACK_ROOK; }
if (m_b_queen.test(square)) { return Pieces::BLACK_QUEEN; }
if (m_b_queens.test(square)) { return Pieces::BLACK_QUEEN; }
if (m_b_king.test(square)) { return Pieces::BLACK_KING; }
// clang-format on

Expand All @@ -144,7 +144,7 @@ void Board::set_piece(Square square, Piece piece) {
case Piece::KNIGHT: m_w_knights.set(square); return;
case Piece::BISHOP: m_w_bishops.set(square); return;
case Piece::ROOK: m_w_rooks.set(square); return;
case Piece::QUEEN: m_w_queen.set(square); return;
case Piece::QUEEN: m_w_queens.set(square); return;
case Piece::KING: m_w_king.set(square); return;
default: break; // clang-format on
}
Expand All @@ -155,7 +155,7 @@ void Board::set_piece(Square square, Piece piece) {
case Piece::KNIGHT: m_b_knights.set(square); return;
case Piece::BISHOP: m_b_bishops.set(square); return;
case Piece::ROOK: m_b_rooks.set(square); return;
case Piece::QUEEN: m_b_queen.set(square); return;
case Piece::QUEEN: m_b_queens.set(square); return;
case Piece::KING: m_b_king.set(square); return;
default: break; // clang-format on
}
Expand All @@ -172,14 +172,14 @@ void Board::remove_piece(Square square) {
m_w_knights.clear(square);
m_w_bishops.clear(square);
m_w_rooks.clear(square);
m_w_queen.clear(square);
m_w_queens.clear(square);
m_w_king.clear(square);

m_b_pawns.clear(square);
m_b_knights.clear(square);
m_b_bishops.clear(square);
m_b_rooks.clear(square);
m_b_queen.clear(square);
m_b_queens.clear(square);
m_b_king.clear(square);
}

Expand Down
40 changes: 40 additions & 0 deletions src/bitbishop/moves/queen_move_gen.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include <bitbishop/lookups/queen.hpp>
#include <bitbishop/moves/bishop_move_gen.hpp>
#include <bitbishop/moves/queen_move_gen.hpp>
#include <bitbishop/moves/rook_move_gen.hpp>
#include <optional>

void QueenMoveGenerator::generate_pseudo_legal_moves(std::vector<Move>& 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 queen_attacks;
queen_attacks |= RookMoveGenerator::north_ray(from, occupied);
queen_attacks |= RookMoveGenerator::south_ray(from, occupied);
queen_attacks |= RookMoveGenerator::east_ray(from, occupied);
queen_attacks |= RookMoveGenerator::west_ray(from, occupied);
queen_attacks |= BishopMoveGenerator::north_east_ray(from, occupied);
queen_attacks |= BishopMoveGenerator::north_west_ray(from, occupied);
queen_attacks |= BishopMoveGenerator::south_east_ray(from, occupied);
queen_attacks |= BishopMoveGenerator::south_west_ray(from, occupied);

// Queen sliding moves
Bitboard queen_moves = queen_attacks & empty;
for (auto to : queen_moves) {
moves.emplace_back(from, to, std::nullopt, false, false, false);
}

// Queen captures
Bitboard queen_captures = queen_attacks & enemy;
for (auto to : queen_captures) {
moves.emplace_back(from, to, std::nullopt, true, false, false);
}
}
}
16 changes: 16 additions & 0 deletions tests/bitbishop/board/test_b_get_piece_bitboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,19 @@ TEST(BoardTest, BishopsBitboard) {
EXPECT_TRUE(black_bishops.test(Square::C8));
EXPECT_TRUE(black_bishops.test(Square::F8));
}

/**
* @test BoardTest.QueensBitboard
* @brief Ensures that queens() correctly returns the bitboard for each side.
*/
TEST(BoardTest, QueensBitboard) {
Board board;

Bitboard white_queens = board.queens(Color::WHITE);
Bitboard black_queens = board.queens(Color::BLACK);

EXPECT_EQ(white_queens.count(), 1);
EXPECT_EQ(black_queens.count(), 1);
EXPECT_TRUE(white_queens.test(Squares::D1));
EXPECT_TRUE(black_queens.test(Square::D8));
}
Loading