// 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 ); } }