// Eryn Wells //! Declares the KingMoveGenerator type. This struct is responsible for //! generating the possible moves for the king in the given position. use super::{move_generator_declaration, MoveGeneratorInternal, MoveSet}; use crate::{ piece::{Color, Piece, PlacedPiece}, position::BoardSide, BitBoard, Move, MoveBuilder, Position, }; move_generator_declaration!(KingMoveGenerator, struct); move_generator_declaration!(KingMoveGenerator, new); move_generator_declaration!(KingMoveGenerator, getters); impl<'a> KingMoveGenerator<'a> { #[allow(unused_variables)] fn king_side_castle(position: &Position, color: Color) -> Option { if !position.player_has_right_to_castle(color, BoardSide::King) { return None; } // TODO: Implement king side castle. None } #[allow(unused_variables)] fn queen_side_castle(position: &Position, color: Color) -> Option { if !position.player_has_right_to_castle(color, BoardSide::Queen) { return None; } // TODO: Implement queen side castle. None } } impl<'pos> MoveGeneratorInternal for KingMoveGenerator<'pos> { fn piece(color: Color) -> Piece { Piece::king(color) } fn move_set_for_piece(position: &Position, placed_piece: PlacedPiece) -> MoveSet { let piece = placed_piece.piece(); let color = piece.color(); let square = placed_piece.square(); let empty_squares = position.empty_squares(); let opposing_pieces = position.bitboard_for_color(color.other()); let all_moves = BitBoard::king_moves(square); let quiet_moves_bb = all_moves & empty_squares; let capture_moves_bb = all_moves & opposing_pieces; // TODO: Handle checks. Prevent moving a king to a square attacked by a // piece of the opposite color. let map_to_move = |sq| MoveBuilder::new(piece, square, sq).build(); let king_side_castle = Self::king_side_castle(position, color); let queen_side_castle = Self::queen_side_castle(position, color); let quiet_moves = quiet_moves_bb .occupied_squares() .map(map_to_move) .chain(king_side_castle.iter().cloned()) .chain(queen_side_castle.iter().cloned()); let capture_moves = capture_moves_bb.occupied_squares().map(map_to_move); MoveSet::new(placed_piece) .quiet_moves(quiet_moves_bb, quiet_moves) .capture_moves(capture_moves_bb, capture_moves) } } #[cfg(test)] mod tests { use super::*; use crate::{piece, piece::Piece, Position, Square}; use std::collections::HashSet; #[test] fn one_king() { let mut pos = Position::empty(); pos.place_piece(Piece::king(Color::White), Square::E4) .expect("Failed to place king on e4"); let generator = KingMoveGenerator::new(&pos, Color::White); let bb = generator.bitboard(); assert_eq!( bb, BitBoard::new( 0b00000000_00000000_00000000_00111000_00101000_00111000_00000000_00000000 ) ); let expected_moves = [ MoveBuilder::new(piece!(White King), Square::E4, Square::D5).build(), MoveBuilder::new(piece!(White King), Square::E4, Square::E5).build(), MoveBuilder::new(piece!(White King), Square::E4, Square::F5).build(), MoveBuilder::new(piece!(White King), Square::E4, Square::F4).build(), MoveBuilder::new(piece!(White King), Square::E4, Square::F3).build(), MoveBuilder::new(piece!(White King), Square::E4, Square::E3).build(), MoveBuilder::new(piece!(White King), Square::E4, Square::D3).build(), MoveBuilder::new(piece!(White King), Square::E4, Square::D4).build(), ]; 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 ); } #[test] fn one_king_corner() { let mut pos = Position::empty(); pos.place_piece(Piece::king(Color::White), Square::A1) .expect("Failed to place king on a1"); let generator = KingMoveGenerator::new(&pos, Color::White); let bb = generator.bitboard(); assert_eq!( bb, BitBoard::new( 0b00000000_00000000_00000000_00000000_00000000_00000000_00000011_00000010 ) ); let expected_moves = [ MoveBuilder::new(piece!(White King), Square::A1, Square::A2).build(), MoveBuilder::new(piece!(White King), Square::A1, Square::B1).build(), MoveBuilder::new(piece!(White King), Square::A1, Square::B2).build(), ]; 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 ); } }