From b95c34f51e832f9119b5c9b5dc9b3ecd9fe3bb28 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Mon, 1 Jan 2024 09:37:44 -0800 Subject: [PATCH] [board] Implement KnightMoveGenerator Use the generated knight_moves BitBoards from bitboard::MoveLibrary to generate knight moves. This commit doesn't yet implement computing bitboards for knight moves. --- board/src/moves/knight.rs | 142 ++++++++++++++++++++++++++++++ board/src/moves/mod.rs | 1 + board/src/moves/move_generator.rs | 5 +- board/src/tests.rs | 8 ++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 board/src/moves/knight.rs diff --git a/board/src/moves/knight.rs b/board/src/moves/knight.rs new file mode 100644 index 0000000..5a7e921 --- /dev/null +++ b/board/src/moves/knight.rs @@ -0,0 +1,142 @@ +// Eryn Wells + +use std::io::empty; + +use crate::{ + bitboard::BitBoard, + piece::{Color, Piece}, + Move, Position, +}; + +enum MoveList { + Quiet, + Captures, +} + +pub(super) struct KnightMoveGenerator<'pos> { + position: &'pos Position, + color: Color, + + bitboards: [BitBoard; 2], + move_lists: [Vec; 2], +} + +impl<'pos> KnightMoveGenerator<'pos> { + pub(super) fn new(position: &'pos Position, color: Color) -> KnightMoveGenerator<'pos> { + let mut generator = KnightMoveGenerator { + position, + color, + bitboards: [BitBoard::empty(), BitBoard::empty()], + move_lists: [Vec::new(), Vec::new()], + }; + + generator.generate_moves(); + + generator + } + + pub(super) fn iter(&self) -> impl Iterator + '_ { + self.move_lists.iter().flatten() + } + + fn quiet_moves_list_mut(&mut self) -> &mut Vec { + &mut self.move_lists[MoveList::Quiet as usize] + } + + fn capture_moves_list_mut(&mut self) -> &mut Vec { + &mut self.move_lists[MoveList::Captures as usize] + } + + fn generate_moves(&mut self) { + self.generate_bitboards(); + self.populate_move_lists(); + } + + fn generate_bitboards(&mut self) { + // TODO: Calculate bitboards for each knight. + } + + fn populate_move_lists(&mut self) { + let piece = Piece::knight(self.color); + + let bb = self.position.bitboard_for_piece(piece); + if bb.is_empty() { + return; + } + + let empty_squares = self.position.empty_squares(); + let opposing_pieces = self.position.bitboard_for_color(self.color.other()); + + for from_sq in bb.occupied_squares() { + let knight_moves = BitBoard::knight_moves(from_sq); + println!("{}", knight_moves); + + let new_moves = (knight_moves & empty_squares) + .occupied_squares() + .map(|to_sq| Move::new(piece, from_sq, to_sq)); + self.quiet_moves_list_mut().extend(new_moves); + + let new_capture_moves = + (knight_moves & opposing_pieces) + .occupied_squares() + .map(|to_sq| { + let captured_piece = self.position.piece_on_square(to_sq).unwrap(); + Move::new(piece, from_sq, to_sq).capturing(captured_piece) + }); + self.capture_moves_list_mut().extend(new_capture_moves); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::Square; + use std::collections::HashSet; + + #[test] + fn one_knight() { + let mut pos = Position::empty(); + pos.place_piece(&Piece::knight(Color::White), &Square::e4()) + .expect("Failed to place knight on e4"); + + let generator = KnightMoveGenerator::new(&pos, Color::White); + + /* + let bb = generator.bitboard(); + assert_eq!( + bb, + BitBoard::new( + 0b00000000_00000000_00000000_00111000_00101000_00111000_00000000_00000000 + ) + ); + */ + + let expected_moves = [ + Move::new(Piece::knight(Color::White), Square::e4(), Square::c3()), + Move::new(Piece::knight(Color::White), Square::e4(), Square::d2()), + Move::new(Piece::knight(Color::White), Square::e4(), Square::f2()), + Move::new(Piece::knight(Color::White), Square::e4(), Square::g3()), + Move::new(Piece::knight(Color::White), Square::e4(), Square::c5()), + Move::new(Piece::knight(Color::White), Square::e4(), Square::d6()), + Move::new(Piece::knight(Color::White), Square::e4(), Square::g5()), + Move::new(Piece::knight(Color::White), Square::e4(), Square::f6()), + ]; + + let mut generated_moves: HashSet = generator.iter().cloned().collect(); + + for ex_move in expected_moves { + assert!( + generated_moves.remove(&ex_move), + "{:#?} was not generated", + &ex_move + ); + } + + assert!( + generated_moves.is_empty(), + "Moves unexpectedly present: {:#?}", + generated_moves + ); + } +} diff --git a/board/src/moves/mod.rs b/board/src/moves/mod.rs index 1745e63..4289649 100644 --- a/board/src/moves/mod.rs +++ b/board/src/moves/mod.rs @@ -1,6 +1,7 @@ // Eryn Wells mod king; +mod knight; mod r#move; mod move_generator; mod pawn; diff --git a/board/src/moves/move_generator.rs b/board/src/moves/move_generator.rs index e4c00d8..a67220e 100644 --- a/board/src/moves/move_generator.rs +++ b/board/src/moves/move_generator.rs @@ -1,11 +1,12 @@ // Eryn Wells -use super::{king::KingMoveGenerator, pawn::PawnMoveGenerator, Move}; +use super::{king::KingMoveGenerator, knight::KnightMoveGenerator, pawn::PawnMoveGenerator, Move}; use crate::piece::Color; use crate::Position; pub struct Moves<'pos> { pawn_moves: PawnMoveGenerator<'pos>, + knight_moves: KnightMoveGenerator<'pos>, king_moves: KingMoveGenerator<'pos>, } @@ -13,6 +14,7 @@ impl<'a> Moves<'a> { pub fn new(position: &Position, color: Color) -> Moves { Moves { pawn_moves: PawnMoveGenerator::new(position, color), + knight_moves: KnightMoveGenerator::new(position, color), king_moves: KingMoveGenerator::new(position, color), } } @@ -20,6 +22,7 @@ impl<'a> Moves<'a> { fn iter(&self) -> impl Iterator + '_ { self.pawn_moves .iter() + .chain(self.knight_moves.iter()) .chain(self.king_moves.iter()) .cloned() } diff --git a/board/src/tests.rs b/board/src/tests.rs index 35ac163..e1018e2 100644 --- a/board/src/tests.rs +++ b/board/src/tests.rs @@ -18,14 +18,22 @@ impl Square { sq_constructor!(a2); sq_constructor!(b1); sq_constructor!(b2); + sq_constructor!(c3); + sq_constructor!(c5); + sq_constructor!(d2); sq_constructor!(d3); sq_constructor!(d4); sq_constructor!(d5); + sq_constructor!(d6); sq_constructor!(e2); sq_constructor!(e3); sq_constructor!(e4); sq_constructor!(e5); + sq_constructor!(f2); sq_constructor!(f3); sq_constructor!(f4); sq_constructor!(f5); + sq_constructor!(f6); + sq_constructor!(g3); + sq_constructor!(g5); }