[position] Plumb capture mask and push mask arguments through all move generators

These masks will help when generating moves that address checks.
Create BitBoard::EMPTY and BitBoard::FULL.
This commit is contained in:
Eryn Wells 2024-01-29 20:11:34 -08:00
parent 9c4360c886
commit b93f8684fa
9 changed files with 111 additions and 46 deletions

View file

@ -18,6 +18,9 @@ macro_rules! moves_getter {
}
impl BitBoard {
pub const EMPTY: BitBoard = BitBoard(0);
pub const FULL: BitBoard = BitBoard(0xFFFFFFFFFFFFFFFF);
pub const fn empty() -> BitBoard {
BitBoard(0)
}

View file

@ -17,6 +17,7 @@ use self::{
rook::ClassicalMoveGenerator as RookMoveGenerator,
};
use crate::{Move, Position};
use chessfriend_bitboard::BitBoard;
use chessfriend_core::{Color, Piece, PlacedPiece, Shape, Square};
use std::collections::BTreeMap;
@ -47,10 +48,12 @@ macro_rules! move_generator_declaration {
pub(super) fn new(
position: &$crate::Position,
color: chessfriend_core::Color,
capture_mask: chessfriend_bitboard::BitBoard,
push_mask: chessfriend_bitboard::BitBoard,
) -> $name {
$name {
color,
move_sets: Self::move_sets(position, color),
move_sets: Self::move_sets(position, color, capture_mask, push_mask),
}
}
}
@ -83,21 +86,32 @@ pub(self) use move_generator_declaration;
trait MoveGeneratorInternal {
fn piece(color: Color) -> Piece;
fn move_sets(position: &Position, color: Color) -> BTreeMap<Square, MoveSet> {
fn move_sets(
position: &Position,
color: Color,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> BTreeMap<Square, MoveSet> {
let piece = Self::piece(color);
BTreeMap::from_iter(
position
.bitboard_for_piece(piece)
.occupied_squares()
.map(|sq| {
let placed_piece = PlacedPiece::new(piece, sq);
let move_set = Self::move_set_for_piece(position, placed_piece);
(sq, move_set)
.map(|square| {
let piece = PlacedPiece::new(piece, square);
let move_set =
Self::move_set_for_piece(position, piece, capture_mask, push_mask);
(square, move_set)
}),
)
}
fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet;
fn move_set_for_piece(
position: &Position,
piece: PlacedPiece,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> MoveSet;
}
#[derive(Clone, Debug, Eq, PartialEq)]
@ -111,14 +125,19 @@ pub struct Moves {
}
impl Moves {
pub fn new(position: &Position, color: Color) -> Moves {
pub fn new(
position: &Position,
color: Color,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> Moves {
Moves {
pawn_moves: PawnMoveGenerator::new(position, color),
knight_moves: KnightMoveGenerator::new(position, color),
bishop_moves: BishopMoveGenerator::new(position, color),
rook_moves: RookMoveGenerator::new(position, color),
queen_moves: QueenMoveGenerator::new(position, color),
king_moves: KingMoveGenerator::new(position, color),
pawn_moves: PawnMoveGenerator::new(position, color, capture_mask, push_mask),
knight_moves: KnightMoveGenerator::new(position, color, capture_mask, push_mask),
bishop_moves: BishopMoveGenerator::new(position, color, capture_mask, push_mask),
rook_moves: RookMoveGenerator::new(position, color, capture_mask, push_mask),
queen_moves: QueenMoveGenerator::new(position, color, capture_mask, push_mask),
king_moves: KingMoveGenerator::new(position, color, capture_mask, push_mask),
}
}

View file

@ -12,7 +12,12 @@ impl MoveGeneratorInternal for ClassicalMoveGenerator {
Piece::bishop(color)
}
fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet {
fn move_set_for_piece(
position: &Position,
placed_piece: PlacedPiece,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> MoveSet {
let piece = placed_piece.piece();
let square = placed_piece.square();
@ -64,7 +69,8 @@ mod tests {
White Bishop on A1,
];
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),
@ -84,7 +90,8 @@ mod tests {
println!("{}", DiagramFormatter::new(&pos));
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),
@ -102,7 +109,8 @@ mod tests {
Black Knight on C3,
];
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),
@ -120,7 +128,8 @@ mod tests {
println!("{}", DiagramFormatter::new(&pos));
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let bitboard = generator.bitboard();
let expected = BitBoard::new(
0b00000001_10000010_01000100_00101000_00000000_00101000_01000100_10000010,

View file

@ -17,7 +17,12 @@ impl MoveGeneratorInternal for KingMoveGenerator {
Piece::king(color)
}
fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet {
fn move_set_for_piece(
position: &Position,
placed_piece: PlacedPiece,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> MoveSet {
let piece = placed_piece.piece();
let color = piece.color();
let square = placed_piece.square();
@ -61,7 +66,7 @@ mod tests {
fn one_king() {
let pos = position![White King on E4];
let generator = KingMoveGenerator::new(&pos, Color::White);
let generator = KingMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),
@ -88,7 +93,7 @@ mod tests {
fn one_king_corner() {
let pos = position![White King on A1];
let generator = KingMoveGenerator::new(&pos, Color::White);
let generator = KingMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let generated_bitboard = generator.bitboard();
let expected_bitboard = bitboard![A2, B2, B1];
@ -132,7 +137,7 @@ mod tests {
assert!(pos.is_king_in_check());
let generator = KingMoveGenerator::new(&pos, Color::Black);
let generator = KingMoveGenerator::new(&pos, Color::Black, BitBoard::FULL, BitBoard::FULL);
let generated_moves = generator.bitboard();
let expected_moves = bitboard![F8, F7, F6, D6, D7, D8];
@ -151,7 +156,7 @@ mod tests {
assert!(pos.player_can_castle(Color::White, Castle::KingSide));
assert!(pos.player_can_castle(Color::White, Castle::QueenSide));
let generator = KingMoveGenerator::new(&pos, Color::White);
let generator = KingMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let generated_moves: HashSet<Move> = generator.iter().collect();
let king = piece!(White King);
@ -179,7 +184,7 @@ mod tests {
assert!(pos.player_can_castle(Color::White, Castle::KingSide));
assert!(!pos.player_can_castle(Color::White, Castle::QueenSide));
let generator = KingMoveGenerator::new(&pos, Color::White);
let generator = KingMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let generated_moves: HashSet<Move> = generator.iter().collect();
let king = piece!(White King);
@ -207,7 +212,7 @@ mod tests {
assert!(!pos.player_can_castle(Color::White, Castle::KingSide));
assert!(pos.player_can_castle(Color::White, Castle::QueenSide));
let generator = KingMoveGenerator::new(&pos, Color::White);
let generator = KingMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let generated_moves: HashSet<Move> = generator.iter().collect();
let king = piece!(White King);

View file

@ -12,7 +12,12 @@ impl MoveGeneratorInternal for KnightMoveGenerator {
Piece::knight(color)
}
fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet {
fn move_set_for_piece(
position: &Position,
placed_piece: PlacedPiece,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> MoveSet {
let opposing_pieces = position.bitboard_for_color(placed_piece.piece().color().other());
let empty_squares = position.empty_squares();
let knight_moves = BitBoard::knight_moves(placed_piece.square());
@ -39,7 +44,8 @@ mod tests {
White Knight on E4,
];
let generator = KnightMoveGenerator::new(&pos, Color::White);
let generator =
KnightMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
/*
let bb = generator.bitboard();

View file

@ -15,7 +15,12 @@ impl MoveGeneratorInternal for PawnMoveGenerator {
Piece::pawn(color)
}
fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet {
fn move_set_for_piece(
position: &Position,
placed_piece: PlacedPiece,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> MoveSet {
let capture_moves = Self::attacks(position, placed_piece);
let quiet_moves = Self::pushes(position, placed_piece);
@ -65,7 +70,7 @@ mod tests {
fn one_2square_push() {
let pos = test_position![White Pawn on E2];
let generator = PawnMoveGenerator::new(&pos, Color::White);
let generator = PawnMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let expected_moves = HashSet::from_iter([
MoveBuilder::new(piece!(White Pawn), Square::E2, Square::E3).build(),
@ -81,7 +86,7 @@ mod tests {
fn one_1square_push() {
let pos = test_position![White Pawn on E3];
let generator = PawnMoveGenerator::new(&pos, Color::White);
let generator = PawnMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let expected_moves = HashSet::from_iter([MoveBuilder::new(
Piece::pawn(Color::White),
@ -104,7 +109,7 @@ mod tests {
println!("{}", DiagramFormatter::new(&pos));
let generator = PawnMoveGenerator::new(&pos, Color::White);
let generator = PawnMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let expected_moves = HashSet::from_iter([MoveBuilder::new(
Piece::pawn(Color::White),
@ -125,7 +130,7 @@ mod tests {
White Knight on E3,
];
let generator = PawnMoveGenerator::new(&pos, Color::White);
let generator = PawnMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let generated_moves: HashSet<Move> = generator.iter().collect();
let expected_moves: HashSet<Move> = HashSet::new();
@ -141,7 +146,7 @@ mod tests {
Black Knight on D5,
];
let generator = PawnMoveGenerator::new(&pos, Color::White);
let generator = PawnMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let expected_moves =
HashSet::from_iter(
@ -164,7 +169,7 @@ mod tests {
Black Queen on F5,
];
let generator = PawnMoveGenerator::new(&pos, Color::White);
let generator = PawnMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let expected_moves = HashSet::from_iter([
MoveBuilder::new(piece!(White Pawn), Square::E4, Square::D5)

View file

@ -12,7 +12,12 @@ impl MoveGeneratorInternal for ClassicalMoveGenerator {
Piece::queen(color)
}
fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet {
fn move_set_for_piece(
position: &Position,
placed_piece: PlacedPiece,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> MoveSet {
let piece = placed_piece.piece();
let color = piece.color();
let square = placed_piece.square();
@ -68,7 +73,8 @@ mod tests {
fn classical_single_queen_bitboard() {
let pos = position![White Queen on B2];
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let bitboard = generator.bitboard();
let expected = bitboard![
A2, C2, D2, E2, F2, G2, H2, // Rank
@ -94,7 +100,8 @@ mod tests {
println!("{}", DiagramFormatter::new(&pos));
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
let bitboard = generator.bitboard();
let expected = BitBoard::new(
0b10000001_01000001_00100001_00010001_00001001_00000101_00000011_00001110,
@ -116,7 +123,8 @@ mod tests {
];
println!("{}", DiagramFormatter::new(&pos));
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),
@ -134,7 +142,8 @@ mod tests {
let pos = position![White Queen on D3];
println!("{}", DiagramFormatter::new(&pos));
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),

View file

@ -12,7 +12,12 @@ impl MoveGeneratorInternal for ClassicalMoveGenerator {
Piece::rook(color)
}
fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet {
fn move_set_for_piece(
position: &Position,
placed_piece: PlacedPiece,
capture_mask: BitBoard,
push_mask: BitBoard,
) -> MoveSet {
let piece = placed_piece.piece();
let color = piece.color();
let square = placed_piece.square();
@ -64,7 +69,8 @@ mod tests {
fn classical_single_rook_bitboard() {
let pos = test_position![White Rook on A2];
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),
@ -82,7 +88,8 @@ mod tests {
println!("{}", DiagramFormatter::new(&pos));
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),
@ -100,7 +107,8 @@ mod tests {
Black Knight on E1,
];
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),
@ -112,7 +120,8 @@ mod tests {
fn classical_single_rook_in_center() {
let pos = test_position![White Rook on D4];
let generator = ClassicalMoveGenerator::new(&pos, Color::White);
let generator =
ClassicalMoveGenerator::new(&pos, Color::White, BitBoard::FULL, BitBoard::FULL);
assert_eq!(
generator.bitboard(),

View file

@ -136,7 +136,7 @@ impl Position {
pub fn moves(&self) -> &Moves {
self.moves
.get_or_init(|| Moves::new(self, self.color_to_move))
.get_or_init(|| Moves::new(self, self.color_to_move, BitBoard::FULL, BitBoard::FULL))
}
/// Return a BitBoard representing the set of squares containing a piece.