// Eryn Wells use crate::{ castle, display::DiagramFormatter, piece_sets::{PlacePieceError, PlacePieceStrategy}, PieceSet, }; use chessfriend_bitboard::BitBoard; use chessfriend_core::{Color, Piece, Shape, Square}; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Board { pub active_color: Color, pub pieces: PieceSet, pub castling_rights: castle::Rights, pub en_passant_target: Option, pub half_move_clock: u32, pub full_move_number: u32, } impl Board { /// An empty board #[must_use] pub fn empty() -> Self { Board::default() } /// The starting position #[must_use] pub fn starting() -> Self { const BLACK_PIECES: [BitBoard; Shape::NUM] = [ BitBoard::new(0b0000_0000_1111_1111 << 48), BitBoard::new(0b0100_0010_0000_0000 << 48), BitBoard::new(0b0010_0100_0000_0000 << 48), BitBoard::new(0b1000_0001_0000_0000 << 48), BitBoard::new(0b0000_1000_0000_0000 << 48), BitBoard::new(0b0001_0000_0000_0000 << 48), ]; const WHITE_PIECES: [BitBoard; Shape::NUM] = [ BitBoard::new(0b1111_1111_0000_0000), BitBoard::new(0b0000_0000_0100_0010), BitBoard::new(0b0000_0000_0010_0100), BitBoard::new(0b0000_0000_1000_0001), BitBoard::new(0b0000_0000_0000_1000), BitBoard::new(0b0000_0000_0001_0000), ]; Self { pieces: PieceSet::new([WHITE_PIECES, BLACK_PIECES]), ..Default::default() } } } impl Board { #[must_use] pub fn get_piece(&self, square: Square) -> Option { self.pieces.get(square) } /// Place a piece on the board. /// /// ## Errors /// /// When is called with [`PlacePieceStrategy::PreserveExisting`], and a piece already exists on /// `square`, this method returns a [`PlacePieceError::ExistingPiece`] error. /// pub fn place_piece( &mut self, piece: Piece, square: Square, strategy: PlacePieceStrategy, ) -> Result<(), PlacePieceError> { self.pieces.place(piece, square, strategy) } pub fn remove_piece(&mut self, square: Square) -> Option { self.pieces.remove(square) } } impl Board { pub fn occupancy(&self) -> BitBoard { self.pieces.occpuancy() } pub fn vacancy(&self) -> BitBoard { !self.occupancy() } pub fn friendly_occupancy(&self, color: Color) -> BitBoard { self.pieces.friendly_occupancy(color) } pub fn opposing_occupancy(&self, color: Color) -> BitBoard { self.pieces.opposing_occupancy(color) } } impl Board { pub fn display(&self) -> DiagramFormatter<'_> { DiagramFormatter::new(self) } } /* impl Board { /// The rook to use for a castling move. #[must_use] pub fn rook_for_castle(&self, player: Color, castle: Castle) -> Option { let square = castle.parameters(player).rook_origin_square(); self.piece_on_square(square) } /// Returns `true` if the player is able to castle on the given side of the board. /// /// The following requirements must be met: /// /// 1. The player must still have the right to castle on that side of the /// board. The king and rook involved in the castle must not have moved. /// 1. The spaces between the king and rook must be clear /// 2. The king must not be in check /// 3. In the course of castling on that side, the king must not pass /// through a square that an enemy piece can see #[must_use] pub fn player_can_castle(&self, player: Color, castle: Castle) -> bool { if !self.castling_rights.is_set(player, castle) { return false; } let castling_parameters = castle.parameters(player); let all_pieces = self.pieces.all_pieces(); if !(all_pieces & castling_parameters.clear_squares()).is_empty() { return false; } // TODO: Reimplement king_danger here or in Position. // let danger_squares = self.king_danger(player); // if !(danger_squares & castling_parameters.check_squares()).is_empty() { // return false; // } true } pub fn iter_all_pieces(&self) -> impl Iterator + '_ { self.pieces.iter() } pub fn iter_pieces_of_color(&self, color: Color) -> impl Iterator + '_ { self.pieces .iter() .filter(move |piece| piece.color() == color) } } */ #[cfg(test)] mod tests { use super::*; use crate::test_board; use chessfriend_core::piece; #[test] fn get_piece_on_square() { let board = test_board![ Black Bishop on F7, ]; assert_eq!(board.get_piece(Square::F7), Some(piece!(Black Bishop))); } }