diff --git a/board/src/board.rs b/board/src/board.rs index e091b52..334885e 100644 --- a/board/src/board.rs +++ b/board/src/board.rs @@ -1,19 +1,16 @@ // Eryn Wells -use crate::{ - castle, display::DiagramFormatter, piece_sets::PlacePieceError, EnPassant, MoveCounter, - PieceSet, -}; +use crate::{castle, display::DiagramFormatter, Castle, Clock, PieceSet}; use chessfriend_bitboard::BitBoard; use chessfriend_core::{Color, Piece, PlacedPiece, Shape, Square}; use std::iter::Iterator; -#[derive(Clone, Debug, Eq)] +#[derive(Clone, Debug, Default, Eq)] pub struct Board { - pieces: PieceSet, - en_passant: Option, - pub move_counter: MoveCounter, + pub clock: Clock, + pub pieces: PieceSet, pub castling_rights: castle::Rights, + pub en_passant_target: Option, } impl Board { @@ -52,18 +49,7 @@ impl Board { #[must_use] pub fn player_to_move(&self) -> Color { - self.move_counter.active_color - } - - /// Returns `true` if the player has the right to castle on the given side - /// of the board. - /// - /// A player retains the right to castle on a particular side of the board - /// as long as they have not moved their king, or the rook on that side of - /// the board. - #[must_use] - pub fn player_has_right_to_castle(&self, color: Color, castle: Castle) -> bool { - self.flags.player_has_right_to_castle(color, castle) + self.clock.active_color() } /// The rook to use for a castling move. @@ -83,11 +69,9 @@ impl Board { /// 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 - .player_has_right_to_castle(player, castle.into()) - { + if !self.castling_rights.is_set(player, castle.into()) { return false; } @@ -115,12 +99,13 @@ impl Board { #[must_use] pub fn friendly_pieces_bitboard(&self) -> BitBoard { - self.pieces.all_pieces_of_color(self.player_to_move) + self.pieces.all_pieces_of_color(self.clock.active_color()) } #[must_use] pub fn opposing_pieces_bitboard(&self) -> BitBoard { - self.pieces.all_pieces_of_color(self.player_to_move.other()) + self.pieces + .all_pieces_of_color(self.clock.active_color().other()) } #[must_use] @@ -131,7 +116,15 @@ impl Board { ) } - /// A [BitBoard] representing the set of squares containing a piece. This + pub fn all_pieces_bitboard(&self) -> BitBoard { + self.pieces.all_pieces() + } + + pub fn all_pieces_of_color_bitboard(&self, color: Color) -> BitBoard { + self.pieces.all_pieces_of_color(color) + } + + /// A [`BitBoard`] representing the set of squares containing a piece. This /// set is the inverse of [`Board::occupied_squares`]. #[must_use] pub fn empty_squares(&self) -> BitBoard { @@ -145,12 +138,10 @@ impl Board { .map(|piece| PlacedPiece::new(piece, square)) } - #[must_use] pub fn iter_all_pieces(&self) -> impl Iterator + '_ { self.pieces.iter() } - #[must_use] pub fn iter_pieces_of_color(&self, color: Color) -> impl Iterator + '_ { self.pieces .iter() @@ -158,13 +149,8 @@ impl Board { } #[must_use] - pub fn has_en_passant_square(&self) -> bool { - self.en_passant.is_some() - } - - #[must_use] - pub fn en_passant(&self) -> Option { - self.en_passant + pub fn en_passant_target(&self) -> Option { + self.en_passant_target } fn king_bitboard(&self, player: Color) -> BitBoard { @@ -172,10 +158,7 @@ impl Board { } pub(crate) fn king_square(&self, player: Color) -> Square { - self.king_bitboard(player) - .occupied_squares() - .next() - .unwrap() + self.king_bitboard(player).try_into().unwrap() } #[must_use] @@ -192,16 +175,19 @@ impl Board { pub fn bitboard_for_piece(&self, piece: Piece) -> BitBoard { self.pieces.bitboard_for_piece(piece) } -} -impl Default for Board { - fn default() -> Self { - Self { - castling_rights: castle::Rights::default(), - pieces: PieceSet::default(), - en_passant: None, - move_counter: MoveCounter::default(), - } + /// A [`BitBoard`] representing the squares where a king of the given color will + /// be in danger of being captured by the opposing player. If the king is on + /// one of these squares, it is in check. The king cannot move to these + /// squares. + pub(crate) fn king_danger(&self, color: Color) -> BitBoard { + let board_without_king = { + let mut cloned_board = self.clone(); + cloned_board.pieces.remove(self.king_square(color)); + cloned_board + }; + + BitBoard::full() } } @@ -209,8 +195,8 @@ impl PartialEq for Board { fn eq(&self, other: &Self) -> bool { self.pieces == other.pieces && self.castling_rights == other.castling_rights - && self.en_passant == other.en_passant - && self.move_counter == other.move_counter + && self.en_passant_target == other.en_passant_target + && self.clock == other.clock } } @@ -243,49 +229,4 @@ mod tests { Some(piece!(Black Rook on A8)) ); } - - #[test] - fn king_not_on_starting_square_cannot_castle() { - let board = test_board!(White King on E4); - assert!(!board - .castling_rights - .player_has_right_to_castle(Color::White, Castle::KingSide)); - assert!(!board - .castling_rights - .player_has_right_to_castle(Color::White, Castle::QueenSide)); - } - - #[test] - fn king_on_starting_square_can_castle() { - let board = test_board!( - White King on E1, - White Rook on A1, - White Rook on H1 - ); - - assert!(board - .castling_rights - .player_has_right_to_castle(Color::White, Castle::KingSide)); - assert!(board - .castling_rights - .player_has_right_to_castle(Color::White, Castle::QueenSide)); - } - - #[test] - fn rook_for_castle() { - let board = test_board![ - White King on E1, - White Rook on H1, - White Rook on A1, - ]; - - assert_eq!( - board.rook_for_castle(Color::White, Castle::KingSide), - Some(piece!(White Rook on H1)) - ); - assert_eq!( - board.rook_for_castle(Color::White, Castle::QueenSide), - Some(piece!(White Rook on A1)) - ); - } } diff --git a/board/src/castle/rights.rs b/board/src/castle/rights.rs index f6016e8..c32a46e 100644 --- a/board/src/castle/rights.rs +++ b/board/src/castle/rights.rs @@ -12,24 +12,25 @@ impl Rights { /// A player retains the right to castle on a particular side of the board /// as long as they have not moved their king, or the rook on that side of /// the board. - pub fn player_has_right_to_castle(self, color: Color, castle: Castle) -> bool { - (self.0 & (1 << Self::_player_has_right_to_castle_flag_offset(color, castle))) != 0 + #[must_use] + pub fn is_set(self, color: Color, castle: Castle) -> bool { + (self.0 & (1 << Self::flag_offset(color, castle))) != 0 } - pub fn set_player_has_right_to_castle_flag(&mut self, color: Color, castle: Castle) { - self.0 |= 1 << Self::_player_has_right_to_castle_flag_offset(color, castle); + pub fn set(&mut self, color: Color, castle: Castle) { + self.0 |= 1 << Self::flag_offset(color, castle); } - pub fn clear_player_has_right_to_castle_flag(&mut self, color: Color, castle: Castle) { - self.0 &= !(1 << Self::_player_has_right_to_castle_flag_offset(color, castle)); + pub fn clear(&mut self, color: Color, castle: Castle) { + self.0 &= !(1 << Self::flag_offset(color, castle)); } pub fn clear_all(&mut self) { - self.0 &= 0b1111_1100; + self.0 = 0; } - fn _player_has_right_to_castle_flag_offset(color: Color, castle: Castle) -> usize { - ((color as usize) << 1) & castle as usize + fn flag_offset(color: Color, castle: Castle) -> usize { + ((color as usize) << 1) + castle as usize } } @@ -50,43 +51,31 @@ mod tests { use super::*; #[test] - fn castling_rights() { - assert_eq!( - Rights::_player_has_right_to_castle_flag_offset(Color::White, Castle::KingSide), - 0 - ); - assert_eq!( - Rights::_player_has_right_to_castle_flag_offset(Color::White, Castle::QueenSide), - 1 - ); - assert_eq!( - Rights::_player_has_right_to_castle_flag_offset(Color::Black, Castle::KingSide), - 2 - ); - assert_eq!( - Rights::_player_has_right_to_castle_flag_offset(Color::Black, Castle::QueenSide), - 3 - ); + fn bitfield_offsets() { + assert_eq!(Rights::flag_offset(Color::White, Castle::KingSide), 0); + assert_eq!(Rights::flag_offset(Color::White, Castle::QueenSide), 1); + assert_eq!(Rights::flag_offset(Color::Black, Castle::KingSide), 2); + assert_eq!(Rights::flag_offset(Color::Black, Castle::QueenSide), 3); } #[test] fn default_rights() { let mut rights = Rights::default(); - assert!(rights.player_has_right_to_castle(Color::White, Castle::KingSide)); - assert!(rights.player_has_right_to_castle(Color::White, Castle::QueenSide)); - assert!(rights.player_has_right_to_castle(Color::Black, Castle::KingSide)); - assert!(rights.player_has_right_to_castle(Color::Black, Castle::QueenSide)); + assert!(rights.is_set(Color::White, Castle::KingSide)); + assert!(rights.is_set(Color::White, Castle::QueenSide)); + assert!(rights.is_set(Color::Black, Castle::KingSide)); + assert!(rights.is_set(Color::Black, Castle::QueenSide)); - rights.clear_player_has_right_to_castle_flag(Color::White, Castle::QueenSide); - assert!(rights.player_has_right_to_castle(Color::White, Castle::KingSide)); - assert!(!rights.player_has_right_to_castle(Color::White, Castle::QueenSide)); - assert!(rights.player_has_right_to_castle(Color::Black, Castle::KingSide)); - assert!(rights.player_has_right_to_castle(Color::Black, Castle::QueenSide)); + rights.clear(Color::White, Castle::QueenSide); + assert!(rights.is_set(Color::White, Castle::KingSide)); + assert!(!rights.is_set(Color::White, Castle::QueenSide)); + assert!(rights.is_set(Color::Black, Castle::KingSide)); + assert!(rights.is_set(Color::Black, Castle::QueenSide)); - rights.set_player_has_right_to_castle_flag(Color::White, Castle::QueenSide); - assert!(rights.player_has_right_to_castle(Color::White, Castle::KingSide)); - assert!(rights.player_has_right_to_castle(Color::White, Castle::QueenSide)); - assert!(rights.player_has_right_to_castle(Color::Black, Castle::KingSide)); - assert!(rights.player_has_right_to_castle(Color::Black, Castle::QueenSide)); + rights.set(Color::White, Castle::QueenSide); + assert!(rights.is_set(Color::White, Castle::KingSide)); + assert!(rights.is_set(Color::White, Castle::QueenSide)); + assert!(rights.is_set(Color::Black, Castle::KingSide)); + assert!(rights.is_set(Color::Black, Castle::QueenSide)); } } diff --git a/board/src/fen.rs b/board/src/fen.rs index 3ee39d6..a370702 100644 --- a/board/src/fen.rs +++ b/board/src/fen.rs @@ -1,6 +1,6 @@ // Eryn Wells -use crate::{Board, Builder, Castle, EnPassant}; +use crate::{piece_sets::PlacePieceStrategy, Board, Castle, EnPassant}; use chessfriend_core::{ coordinates::ParseSquareError, piece, Color, File, Piece, PlacedPiece, Rank, Square, }; @@ -103,10 +103,7 @@ impl ToFenStr for Board { (Color::Black, Castle::QueenSide), ] .map(|(color, castle)| { - if !self - .castling_rights - .player_has_right_to_castle(color, castle) - { + if !self.castling_rights.is_set(color, castle) { return ""; } @@ -129,14 +126,14 @@ impl ToFenStr for Board { write!( fen_string, " {}", - self.en_passant() - .map_or("-".to_string(), |ep| ep.target_square().to_string()) + self.en_passant_target + .map_or("-".to_string(), |square| square.to_string()) ) .map_err(ToFenStrError::FmtError)?; - write!(fen_string, " {}", self.move_counter.halfmove_number) + write!(fen_string, " {}", self.clock.half_move_number()) .map_err(ToFenStrError::FmtError)?; - write!(fen_string, " {}", self.move_counter.fullmove_number) + write!(fen_string, " {}", self.clock.full_move_number()) .map_err(ToFenStrError::FmtError)?; Ok(fen_string) @@ -178,7 +175,7 @@ impl FromFenStr for Board { type Error = FromFenStrError; fn from_fen_str(string: &str) -> Result { - let mut builder = Builder::default(); + let mut board = Board::empty(); let mut fields = string.split(' '); @@ -202,34 +199,35 @@ impl FromFenStr for Board { let file = files.next().ok_or(FromFenStrError::MissingPlacement)?; let piece = Piece::from_fen_str(&ch.to_string())?; - builder.place_piece(PlacedPiece::new( + let _ = board.pieces.place( piece, Square::from_file_rank(*file, *rank), - )); + PlacePieceStrategy::default(), + ); } debug_assert_eq!(files.next(), None); } - let player_to_move = Color::from_fen_str( + let active_color = Color::from_fen_str( fields .next() .ok_or(FromFenStrError::MissingField(Field::PlayerToMove))?, )?; - builder.to_move(player_to_move); + board.clock.active_color = active_color; let castling_rights = fields .next() .ok_or(FromFenStrError::MissingField(Field::CastlingRights))?; if castling_rights == "-" { - builder.no_castling_rights(); + board.castling_rights.clear_all(); } else { for ch in castling_rights.chars() { match ch { - 'K' => builder.player_can_castle(Color::White, Castle::KingSide), - 'Q' => builder.player_can_castle(Color::White, Castle::QueenSide), - 'k' => builder.player_can_castle(Color::Black, Castle::KingSide), - 'q' => builder.player_can_castle(Color::Black, Castle::QueenSide), + 'K' => board.castling_rights.set(Color::White, Castle::KingSide), + 'Q' => board.castling_rights.set(Color::White, Castle::QueenSide), + 'k' => board.castling_rights.set(Color::Black, Castle::KingSide), + 'q' => board.castling_rights.set(Color::Black, Castle::QueenSide), _ => return Err(FromFenStrError::InvalidValue), }; } @@ -241,7 +239,7 @@ impl FromFenStr for Board { if en_passant_square != "-" { let square = Square::from_algebraic_str(en_passant_square) .map_err(FromFenStrError::ParseSquareError)?; - builder.en_passant(Some(EnPassant::from_target_square(square).unwrap())); + board.en_passant_target = Some(square); } let half_move_clock = fields @@ -250,7 +248,7 @@ impl FromFenStr for Board { let half_move_clock: u16 = half_move_clock .parse() .map_err(FromFenStrError::ParseIntError)?; - builder.halfmove_number(half_move_clock); + board.clock.half_move_number = half_move_clock; let full_move_counter = fields .next() @@ -258,11 +256,11 @@ impl FromFenStr for Board { let full_move_counter: u16 = full_move_counter .parse() .map_err(FromFenStrError::ParseIntError)?; - builder.fullmove_number(full_move_counter); + board.clock.full_move_number = full_move_counter; debug_assert_eq!(fields.next(), None); - Ok(builder.build()) + Ok(board) } } @@ -318,16 +316,14 @@ mod tests { let pos = test_board!(starting); assert_eq!( - pos.to_fen_str(), - Ok(String::from( - "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" - )) + pos.to_fen_str().unwrap(), + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 0" ); } #[test] fn from_starting_fen() { - let board = fen!("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap(); + let board = fen!("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 0").unwrap(); let expected = Board::starting(); assert_eq!(board, expected, "{board:#?}\n{expected:#?}"); } diff --git a/board/src/lib.rs b/board/src/lib.rs index 10916c6..6a5bc2a 100644 --- a/board/src/lib.rs +++ b/board/src/lib.rs @@ -5,14 +5,14 @@ pub mod display; pub mod en_passant; pub mod fen; pub mod macros; -pub mod move_counter; mod board; +mod move_counter; mod piece_sets; pub use board::Board; +pub use move_counter::Clock; use castle::Castle; use en_passant::EnPassant; -use move_counter::MoveCounter; -use piece_sets::PieceSet; +use piece_sets::{PieceSet, PlacePieceError, PlacePieceStrategy}; diff --git a/board/src/macros.rs b/board/src/macros.rs index 547071b..f3ca5dc 100644 --- a/board/src/macros.rs +++ b/board/src/macros.rs @@ -16,24 +16,20 @@ macro_rules! board { }; } -#[cfg(test)] #[macro_export] macro_rules! test_board { ($to_move:ident, [ $($color:ident $shape:ident on $square:ident),* $(,)? ], $en_passant:ident) => { { - let board = $crate::Builder::new() - $(.place_piece( - chessfriend_core::PlacedPiece::new( - chessfriend_core::Piece::new( - chessfriend_core::Color::$color, - chessfriend_core::Shape::$shape - ), - chessfriend_core::Square::$square - )) - )* - .to_move(chessfriend_core::Color::$to_move) - .en_passant(Some(chessfriend_moves::EnPassant::from_target_square(chessfriend_core::Square::$en_passant)).unwrap()) - .build(); + let mut board = $crate::Board::empty(); + $(let _ = board.pieces.place( + chessfriend_core::Piece::new( + chessfriend_core::Color::$color, + chessfriend_core::Shape::$shape + ), + chessfriend_core::Square::$square); + )* + board.clock.active_color = chessfriend_core::Color::$to_move; + board.en_passant_target = Some(chessfriend_core::Square::$en_passant); println!("{}", board.display()); @@ -42,37 +38,33 @@ macro_rules! test_board { }; ($to_move:ident, [ $($color:ident $shape:ident on $square:ident),* $(,)? ]) => { { - let board = $crate::Builder::new() - $(.place_piece( - chessfriend_core::PlacedPiece::new( - chessfriend_core::Piece::new( - chessfriend_core::Color::$color, - chessfriend_core::Shape::$shape - ), - chessfriend_core::Square::$square - )) - )* - .to_move(chessfriend_core::Color::$to_move) - .build(); + let mut board = $crate::Board::empty(); + $(let _ = board.pieces.place( + chessfriend_core::Piece::new( + chessfriend_core::Color::$color, + chessfriend_core::Shape::$shape + ), + chessfriend_core::Square::$square, + $crate::PlacePieceStrategy::default()); + )* + board.clock.active_color = chessfriend_core::Color::$to_move; println!("{}", board.display()); - pos + board } }; ($($color:ident $shape:ident on $square:ident),* $(,)?) => { { - let board = $crate::Builder::new() - $(.place_piece( - chessfriend_core::PlacedPiece::new( - chessfriend_core::Piece::new( - chessfriend_core::Color::$color, - chessfriend_core::Shape::$shape - ), - chessfriend_core::Square::$square - )) - )* - .build(); + let mut board = $crate::Board::empty(); + $(let _ = board.pieces.place( + chessfriend_core::Piece::new( + chessfriend_core::Color::$color, + chessfriend_core::Shape::$shape + ), + chessfriend_core::Square::$square, + $crate::PlacePieceStrategy::default()); + )* println!("{}", board.display()); diff --git a/board/src/move_counter.rs b/board/src/move_counter.rs index cca9840..cd24bdf 100644 --- a/board/src/move_counter.rs +++ b/board/src/move_counter.rs @@ -1,34 +1,92 @@ use chessfriend_core::Color; -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct MoveCounter { +#[derive(Default)] +pub enum AdvanceHalfMove { + Reset, + #[default] + Advance, +} + +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct Clock { /// The player who's turn it is to move. - pub active_color: Color, + pub(crate) active_color: Color, + /// The number of completed turns. A turn finishes when every player has moved. - pub fullmove_number: u16, + pub(crate) full_move_number: u16, + /// The number of moves by all players since the last pawn advance or capture. - pub halfmove_number: u16, + pub(crate) half_move_number: u16, } -impl MoveCounter { - pub fn advance(&mut self, should_reset_halfmove_number: bool) { - self.active_color = self.active_color.next(); - - self.fullmove_number += 1; - self.halfmove_number = if should_reset_halfmove_number { - 0 - } else { - self.halfmove_number + 1 - }; +impl Clock { + #[must_use] + pub fn active_color(&self) -> Color { + self.active_color } -} -impl Default for MoveCounter { - fn default() -> Self { - Self { - active_color: Color::default(), - fullmove_number: 0, - halfmove_number: 0, + #[must_use] + pub fn full_move_number(&self) -> u16 { + self.full_move_number + } + + #[must_use] + pub fn half_move_number(&self) -> u16 { + self.half_move_number + } + + pub fn advance(&mut self, advance_half_move: &AdvanceHalfMove) { + let next_color = self.active_color.next(); + + match self.active_color { + Color::Black => self.full_move_number += 1, + Color::White => {} } + + self.half_move_number = match advance_half_move { + AdvanceHalfMove::Reset => 0, + AdvanceHalfMove::Advance => self.half_move_number + 1, + }; + + self.active_color = next_color; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn default_state() { + let clock = Clock::default(); + assert_eq!(clock.active_color, Color::White); + assert_eq!(clock.half_move_number, 0); + assert_eq!(clock.full_move_number, 0); + } + + #[test] + fn advance() { + let mut clock = Clock::default(); + + clock.advance(&AdvanceHalfMove::default()); + assert_eq!(clock.active_color, Color::Black); + assert_eq!(clock.half_move_number, 1); + assert_eq!(clock.full_move_number, 0); + + clock.advance(&AdvanceHalfMove::default()); + assert_eq!(clock.active_color, Color::White); + assert_eq!(clock.half_move_number, 2); + assert_eq!(clock.full_move_number, 1); + + clock.advance(&AdvanceHalfMove::default()); + assert_eq!(clock.active_color, Color::Black); + assert_eq!(clock.half_move_number, 3); + assert_eq!(clock.full_move_number, 1); + + // The half move clock resets after a capture or pawn push. + clock.advance(&AdvanceHalfMove::Reset); + assert_eq!(clock.active_color, Color::White); + assert_eq!(clock.half_move_number, 0); + assert_eq!(clock.full_move_number, 2); } } diff --git a/board/src/piece_sets.rs b/board/src/piece_sets.rs index 9ef1647..2467b9d 100644 --- a/board/src/piece_sets.rs +++ b/board/src/piece_sets.rs @@ -29,7 +29,7 @@ impl Default for PlacePieceStrategy { /// The internal data structure of a [Board] that efficiently manages the /// placement of pieces on the board. #[derive(Clone, Debug, Default, Eq, Hash, PartialEq)] -pub(crate) struct PieceSet { +pub struct PieceSet { mailbox: Mailbox, by_color: ByColor, by_color_and_shape: ByColorAndShape, @@ -52,7 +52,7 @@ impl PieceSet { for c in Color::into_iter() { for s in Shape::into_iter() { let bitboard = pieces[c as usize][s as usize]; - for square in bitboard.occupied_squares(IterationDirection::default()) { + for square in bitboard.occupied_squares(&IterationDirection::default()) { mailbox.set(Piece::new(c, s), square); } } @@ -65,10 +65,6 @@ impl PieceSet { } } - pub(crate) fn mailbox(&self) -> &Mailbox { - &self.mailbox - } - /// A [`BitBoard`] representing all the pieces currently on the board. Other /// engines might refer to this concept as 'occupancy'. pub(crate) fn all_pieces(&self) -> BitBoard { @@ -95,15 +91,7 @@ impl PieceSet { self.mailbox.get(square) } - pub(crate) fn place_piece_on_square( - &mut self, - piece: Piece, - square: Square, - ) -> Result { - self.place_piece_on_square_with_strategy(piece, square, PlacePieceStrategy::default()) - } - - pub(crate) fn place_piece_on_square_with_strategy( + pub(crate) fn place( &mut self, piece: Piece, square: Square, @@ -128,7 +116,7 @@ impl PieceSet { Ok(PlacedPiece::new(piece, square)) } - pub(crate) fn remove_piece_from_square(&mut self, square: Square) -> Option { + pub(crate) fn remove(&mut self, square: Square) -> Option { if let Some(piece) = self.mailbox.get(square) { self.by_color_and_shape.clear_square(square, piece.into()); self.by_color.clear_square(square, piece.color()); @@ -146,7 +134,7 @@ impl FromIterator for PieceSet { let mut pieces: Self = Self::default(); for piece in iter { - let _ = pieces.place_piece_on_square(piece.piece(), piece.square()); + let _ = pieces.place(piece.piece(), piece.square(), PlacePieceStrategy::default()); } pieces