From 4ce7e89cdb0ad2508d901b547dbd8f7167b3caaa Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Wed, 18 Jun 2025 23:44:40 +0000 Subject: [PATCH] [board, explorer, moves] Clean up the castling rights API Reorganize castling rights API on Board into methods named according to conventions applied to other API. Board::has_castling_right Board::has_castling_right_active Board::has_castling_right_unwrapped These all check if a color has the right to castle on a particular side (wing) of the board. The first takes an Option, the latter two operate on bare Colors: the active color, or an explicit Color. Board::grant_castling_right Board::grant_castling_right_active Board::grant_castling_right_unwrapped Grant castling rights to a color. Color arguments follow the pattern above. Board::revoke_castling_right Board::revoke_castling_right_active Board::revoke_castling_right_unwrapped Revoke castling rights from a color. Color arguments follow the pattern above. The latter two groups of methods take a new CastleRightsOption type that specifies either a single Wing or All. Rework the implementation of CastleRights to take a CastleRightsOption. Update the unit tests and make sure everything builds. --- board/src/board.rs | 70 ++++++++++++-------------------- board/src/castle.rs | 69 ++++++++++++++++++++++++++------ board/src/castle/rights.rs | 81 +++++++++++++++++++++++++------------- board/src/fen.rs | 28 ++++++++----- explorer/src/main.rs | 15 +++---- moves/src/make_move.rs | 18 ++++----- moves/src/record.rs | 4 +- moves/src/unmake_move.rs | 16 ++++---- 8 files changed, 177 insertions(+), 124 deletions(-) diff --git a/board/src/board.rs b/board/src/board.rs index 666488e..6c56346 100644 --- a/board/src/board.rs +++ b/board/src/board.rs @@ -1,13 +1,13 @@ // Eryn Wells use crate::{ - PieceSet, castle, + CastleRights, PieceSet, display::DiagramFormatter, piece_sets::{PlacePieceError, PlacePieceStrategy}, zobrist::{ZobristHash, ZobristState}, }; use chessfriend_bitboard::BitBoard; -use chessfriend_core::{Color, Piece, Shape, Square, Wing}; +use chessfriend_core::{Color, Piece, Shape, Square}; use std::sync::Arc; pub type HalfMoveClock = u32; @@ -17,7 +17,7 @@ pub type FullMoveClock = u32; pub struct Board { active_color: Color, pieces: PieceSet, - castling_rights: castle::Rights, + castling_rights: CastleRights, en_passant_target: Option, pub half_move_clock: HalfMoveClock, pub full_move_number: FullMoveClock, @@ -92,59 +92,27 @@ impl Board { impl Board { #[must_use] - pub fn castling_rights(&self) -> castle::Rights { - self.castling_rights + pub fn castling_rights(&self) -> &CastleRights { + &self.castling_rights } - pub fn set_castling_rights(&mut self, rights: castle::Rights) { + pub(crate) fn castling_rights_mut(&mut self) -> &mut CastleRights { + &mut self.castling_rights + } + + /// Replace castling rights with new rights wholesale. + pub fn set_castling_rights(&mut self, rights: CastleRights) { if rights == self.castling_rights { return; } let old_rights = self.castling_rights; self.castling_rights = rights; + self.update_zobrist_hash_castling_rights(old_rights); } - #[must_use] - pub fn active_color_has_castling_right(&self, wing: Wing) -> bool { - self.color_has_castling_right_unwrapped(self.active_color, wing) - } - - #[must_use] - pub fn color_has_castling_right(&self, color: Option, wing: Wing) -> bool { - self.color_has_castling_right_unwrapped(self.unwrap_color(color), wing) - } - - #[must_use] - pub fn color_has_castling_right_unwrapped(&self, color: Color, wing: Wing) -> bool { - self.castling_rights.color_has_right(color, wing) - } - - pub fn grant_castling_right(&mut self, color: Color, wing: Wing) { - let old_rights = self.castling_rights; - self.castling_rights.grant(color, wing); - self.update_zobrist_hash_castling_rights(old_rights); - } - - pub fn revoke_all_castling_rights(&mut self) { - let old_rights = self.castling_rights; - self.castling_rights.revoke_all(); - self.update_zobrist_hash_castling_rights(old_rights); - } - - pub fn revoke_castling_right(&mut self, color: Option, wing: Wing) { - let color = self.unwrap_color(color); - self.revoke_castling_right_unwrapped(color, wing); - } - - pub fn revoke_castling_right_unwrapped(&mut self, color: Color, wing: Wing) { - let old_rights = self.castling_rights; - self.castling_rights.revoke(color, wing); - self.update_zobrist_hash_castling_rights(old_rights); - } - - fn update_zobrist_hash_castling_rights(&mut self, old_rights: castle::Rights) { + pub(crate) fn update_zobrist_hash_castling_rights(&mut self, old_rights: CastleRights) { let new_rights = self.castling_rights; if old_rights == new_rights { return; @@ -154,6 +122,18 @@ impl Board { zobrist.update_modifying_castling_rights(new_rights, old_rights); } } + + pub(crate) fn castling_king(&self, square: Square) -> Option { + let active_color = self.active_color(); + self.get_piece(square) + .filter(|piece| piece.color == active_color && piece.is_king()) + } + + pub(crate) fn castling_rook(&self, square: Square) -> Option { + let active_color = self.active_color(); + self.get_piece(square) + .filter(|piece| piece.color == active_color && piece.is_rook()) + } } impl Board { diff --git a/board/src/castle.rs b/board/src/castle.rs index f8f9c24..5acdaaf 100644 --- a/board/src/castle.rs +++ b/board/src/castle.rs @@ -4,10 +4,10 @@ mod parameters; mod rights; pub use parameters::Parameters; -pub use rights::Rights; +pub use rights::{CastleRightsOption, Rights}; use crate::{Board, CastleParameters}; -use chessfriend_core::{Color, Piece, Square, Wing}; +use chessfriend_core::{Color, Wing}; use thiserror::Error; #[derive(Clone, Copy, Debug, Error, Eq, PartialEq)] @@ -46,7 +46,7 @@ impl Board { let color = self.unwrap_color(color); - if !self.color_has_castling_right_unwrapped(color, wing) { + if !self.has_castling_right_unwrapped(color, wing.into()) { return Err(CastleEvaluationError::NoRights { color, wing }); } @@ -76,17 +76,60 @@ impl Board { Ok(parameters) } +} - pub(crate) fn castling_king(&self, square: Square) -> Option { - let active_color = self.active_color(); - self.get_piece(square) - .filter(|piece| piece.color == active_color && piece.is_king()) +impl Board { + #[must_use] + pub fn has_castling_right(&self, color: Option, wing: Wing) -> bool { + self.has_castling_right_unwrapped(self.unwrap_color(color), wing) } - pub(crate) fn castling_rook(&self, square: Square) -> Option { - let active_color = self.active_color(); - self.get_piece(square) - .filter(|piece| piece.color == active_color && piece.is_rook()) + #[must_use] + pub fn has_castling_right_active(&self, wing: Wing) -> bool { + self.has_castling_right_unwrapped(self.active_color(), wing) + } + + #[must_use] + pub fn has_castling_right_unwrapped(&self, color: Color, wing: Wing) -> bool { + self.castling_rights().get(color, wing.into()) + } +} + +impl Board { + pub fn grant_castling_rights(&mut self, color: Option, rights: CastleRightsOption) { + let color = self.unwrap_color(color); + self.grant_castling_rights_unwrapped(color, rights); + } + + pub fn grant_castling_rights_active(&mut self, rights: CastleRightsOption) { + self.grant_castling_rights_unwrapped(self.active_color(), rights); + } + + pub fn grant_castling_rights_unwrapped(&mut self, color: Color, rights: CastleRightsOption) { + let old_rights = *self.castling_rights(); + self.castling_rights_mut().grant(color, rights); + self.update_zobrist_hash_castling_rights(old_rights); + } +} + +impl Board { + pub fn revoke_all_castling_rights(&mut self) { + self.castling_rights_mut().revoke_all(); + } + + pub fn revoke_castling_rights(&mut self, color: Option, rights: CastleRightsOption) { + let color = self.unwrap_color(color); + self.revoke_castling_rights_unwrapped(color, rights); + } + + pub fn revoke_castling_rights_active(&mut self, rights: CastleRightsOption) { + self.revoke_castling_rights_unwrapped(self.active_color(), rights); + } + + pub fn revoke_castling_rights_unwrapped(&mut self, color: Color, rights: CastleRightsOption) { + let old_rights = *self.castling_rights(); + self.castling_rights_mut().revoke(color, rights); + self.update_zobrist_hash_castling_rights(old_rights); } } @@ -104,8 +147,8 @@ mod tests { White Rook on H1 ); - assert!(board.color_has_castling_right_unwrapped(Color::White, Wing::KingSide)); - assert!(board.color_has_castling_right_unwrapped(Color::White, Wing::QueenSide)); + assert!(board.has_castling_right_unwrapped(Color::White, Wing::KingSide)); + assert!(board.has_castling_right_unwrapped(Color::White, Wing::QueenSide)); } #[test] diff --git a/board/src/castle/rights.rs b/board/src/castle/rights.rs index b65461b..2c0a961 100644 --- a/board/src/castle/rights.rs +++ b/board/src/castle/rights.rs @@ -1,6 +1,14 @@ +// Eryn Wells + use chessfriend_core::{Color, Wing}; use std::fmt; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum CastleRightsOption { + Wing(Wing), + All, +} + #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub struct Rights(u8); @@ -12,16 +20,16 @@ impl Rights { /// as long as they have not moved their king, or the rook on that side of /// the board. #[must_use] - pub fn color_has_right(self, color: Color, wing: Wing) -> bool { - (self.0 & (1 << Self::flag_offset(color, wing))) != 0 + pub fn get(self, color: Color, option: CastleRightsOption) -> bool { + (self.0 & Self::flags(color, option)) != 0 } - pub fn grant(&mut self, color: Color, wing: Wing) { - self.0 |= 1 << Self::flag_offset(color, wing); + pub fn grant(&mut self, color: Color, option: CastleRightsOption) { + self.0 |= Self::flags(color, option); } - pub fn revoke(&mut self, color: Color, wing: Wing) { - self.0 &= !(1 << Self::flag_offset(color, wing)); + pub fn revoke(&mut self, color: Color, option: CastleRightsOption) { + self.0 &= !Self::flags(color, option); } /// Revoke castling rights for all colors and all sides of the board. @@ -31,14 +39,14 @@ impl Rights { } impl Rights { - pub(crate) fn as_index(&self) -> usize { + pub(crate) fn as_index(self) -> usize { self.0 as usize } } impl Rights { - fn flag_offset(color: Color, wing: Wing) -> usize { - ((color as usize) << 1) + wing as usize + const fn flags(color: Color, option: CastleRightsOption) -> u8 { + option.as_flags() << (color as u8 * 2) } } @@ -54,36 +62,55 @@ impl Default for Rights { } } +impl CastleRightsOption { + #[must_use] + pub const fn as_flags(self) -> u8 { + match self { + Self::Wing(wing) => 1 << (wing as u8), + Self::All => (1 << Wing::KingSide as u8) | (1 << Wing::QueenSide as u8), + } + } +} + +impl From for CastleRightsOption { + fn from(value: Wing) -> Self { + Self::Wing(value) + } +} + #[cfg(test)] mod tests { use super::*; #[test] fn bitfield_offsets() { - assert_eq!(Rights::flag_offset(Color::White, Wing::KingSide), 0); - assert_eq!(Rights::flag_offset(Color::White, Wing::QueenSide), 1); - assert_eq!(Rights::flag_offset(Color::Black, Wing::KingSide), 2); - assert_eq!(Rights::flag_offset(Color::Black, Wing::QueenSide), 3); + assert_eq!(Rights::flags(Color::White, Wing::KingSide.into()), 1); + assert_eq!(Rights::flags(Color::White, Wing::QueenSide.into()), 1 << 1); + assert_eq!(Rights::flags(Color::Black, Wing::KingSide.into()), 1 << 2); + assert_eq!(Rights::flags(Color::Black, Wing::QueenSide.into()), 1 << 3); + + assert_eq!(Rights::flags(Color::White, CastleRightsOption::All), 0b11); + assert_eq!(Rights::flags(Color::Black, CastleRightsOption::All), 0b1100); } #[test] fn default_rights() { let mut rights = Rights::default(); - assert!(rights.color_has_right(Color::White, Wing::KingSide)); - assert!(rights.color_has_right(Color::White, Wing::QueenSide)); - assert!(rights.color_has_right(Color::Black, Wing::KingSide)); - assert!(rights.color_has_right(Color::Black, Wing::QueenSide)); + assert!(rights.get(Color::White, Wing::KingSide.into())); + assert!(rights.get(Color::White, Wing::QueenSide.into())); + assert!(rights.get(Color::Black, Wing::KingSide.into())); + assert!(rights.get(Color::Black, Wing::QueenSide.into())); - rights.revoke(Color::White, Wing::QueenSide); - assert!(rights.color_has_right(Color::White, Wing::KingSide)); - assert!(!rights.color_has_right(Color::White, Wing::QueenSide)); - assert!(rights.color_has_right(Color::Black, Wing::KingSide)); - assert!(rights.color_has_right(Color::Black, Wing::QueenSide)); + rights.revoke(Color::White, Wing::QueenSide.into()); + assert!(rights.get(Color::White, Wing::KingSide.into())); + assert!(!rights.get(Color::White, Wing::QueenSide.into())); + assert!(rights.get(Color::Black, Wing::KingSide.into())); + assert!(rights.get(Color::Black, Wing::QueenSide.into())); - rights.grant(Color::White, Wing::QueenSide); - assert!(rights.color_has_right(Color::White, Wing::KingSide)); - assert!(rights.color_has_right(Color::White, Wing::QueenSide)); - assert!(rights.color_has_right(Color::Black, Wing::KingSide)); - assert!(rights.color_has_right(Color::Black, Wing::QueenSide)); + rights.grant(Color::White, Wing::QueenSide.into()); + assert!(rights.get(Color::White, Wing::KingSide.into())); + assert!(rights.get(Color::White, Wing::QueenSide.into())); + assert!(rights.get(Color::Black, Wing::KingSide.into())); + assert!(rights.get(Color::Black, Wing::QueenSide.into())); } } diff --git a/board/src/fen.rs b/board/src/fen.rs index a125aca..65c468a 100644 --- a/board/src/fen.rs +++ b/board/src/fen.rs @@ -24,12 +24,16 @@ pub enum ToFenStrError { pub enum FromFenStrError { #[error("missing {0} field")] MissingField(Field), + #[error("missing piece placement")] MissingPlacement, + #[error("invalid value")] InvalidValue, + #[error("{0}")] ParseIntError(#[from] std::num::ParseIntError), + #[error("{0}")] ParseSquareError(#[from] ParseSquareError), } @@ -122,12 +126,12 @@ impl ToFenStr for Board { (Color::Black, Wing::KingSide), (Color::Black, Wing::QueenSide), ] - .map(|(color, castle)| { - if !self.color_has_castling_right_unwrapped(color, castle) { + .map(|(color, wing)| { + if !self.has_castling_right_unwrapped(color, wing) { return ""; } - match (color, castle) { + match (color, wing) { (Color::White, Wing::KingSide) => "K", (Color::White, Wing::QueenSide) => "Q", (Color::Black, Wing::KingSide) => "k", @@ -226,19 +230,23 @@ impl FromFenStr for Board { )?; board.set_active_color(active_color); + let color_wing_from_char = |ch| match ch { + 'K' => Some((Color::White, Wing::KingSide)), + 'Q' => Some((Color::White, Wing::QueenSide)), + 'k' => Some((Color::Black, Wing::KingSide)), + 'q' => Some((Color::Black, Wing::QueenSide)), + _ => None, + }; + let castling_rights = fields .next() .ok_or(FromFenStrError::MissingField(Field::CastlingRights))?; board.revoke_all_castling_rights(); if castling_rights != "-" { for ch in castling_rights.chars() { - match ch { - 'K' => board.grant_castling_right(Color::White, Wing::KingSide), - 'Q' => board.grant_castling_right(Color::White, Wing::QueenSide), - 'k' => board.grant_castling_right(Color::Black, Wing::KingSide), - 'q' => board.grant_castling_right(Color::Black, Wing::QueenSide), - _ => return Err(FromFenStrError::InvalidValue), - }; + let (color, wing) = + color_wing_from_char(ch).ok_or(FromFenStrError::InvalidValue)?; + board.grant_castling_rights_unwrapped(color, wing.into()); } } diff --git a/explorer/src/main.rs b/explorer/src/main.rs index b409cd0..4f98a63 100644 --- a/explorer/src/main.rs +++ b/explorer/src/main.rs @@ -1,16 +1,11 @@ // Eryn Wells -use chessfriend_board::castle::CastleEvaluationError; -use chessfriend_board::{Board, fen::FromFenStr}; -use chessfriend_board::{CastleParameters, ZobristState}; -use chessfriend_core::random::RandomNumberGenerator; -use chessfriend_core::{Color, Piece, Shape, Square, Wing}; -use chessfriend_moves::algebraic::AlgebraicMoveComponents; -use chessfriend_moves::{GeneratedMove, ValidateMove}; +use chessfriend_board::{Board, ZobristState, fen::FromFenStr}; +use chessfriend_core::{Color, Piece, Shape, Square, Wing, random::RandomNumberGenerator}; +use chessfriend_moves::{GeneratedMove, ValidateMove, algebraic::AlgebraicMoveComponents}; use chessfriend_position::{PlacePieceStrategy, Position, fen::ToFenStr}; use clap::{Arg, Command, value_parser}; -use rustyline::DefaultEditor; -use rustyline::error::ReadlineError; +use rustyline::{DefaultEditor, error::ReadlineError}; use std::sync::Arc; use thiserror::Error; @@ -202,7 +197,7 @@ fn do_flags_command(state: &mut State, _matches: &clap::ArgMatches) -> CommandRe (Color::Black, Wing::KingSide), (Color::Black, Wing::QueenSide), ] { - let has_right = board.color_has_castling_right_unwrapped(color, wing); + let has_right = board.has_castling_right_unwrapped(color, wing.into()); let can_castle = board.color_can_castle(wing, Some(color)); let can_castle_message = match can_castle { diff --git a/moves/src/make_move.rs b/moves/src/make_move.rs index 0ddeb1e..f413e72 100644 --- a/moves/src/make_move.rs +++ b/moves/src/make_move.rs @@ -3,7 +3,8 @@ use crate::{Move, MoveRecord}; use chessfriend_board::{ Board, BoardProvider, CastleParameters, PlacePieceError, PlacePieceStrategy, - castle::CastleEvaluationError, movement::Movement, + castle::{CastleEvaluationError, CastleRightsOption}, + movement::Movement, }; use chessfriend_core::{Color, Piece, Rank, Shape, Square, Wing}; use thiserror::Error; @@ -251,7 +252,7 @@ impl MakeMoveInternal for T { // original board state is preserved. let record = MoveRecord::new(board, ply, None); - board.revoke_castling_right_unwrapped(active_color, wing); + board.revoke_castling_rights_active(wing.into()); self.advance_board_state(&ply, &king, None, HalfMoveClock::Advance); @@ -307,23 +308,22 @@ impl MakeMoveInternal for T { Shape::Rook => { let origin = ply.origin_square(); - if board.color_has_castling_right(None, Wing::KingSide) { + if board.has_castling_right(None, Wing::KingSide) { let kingside_parameters = CastleParameters::get(board.active_color(), Wing::KingSide); if origin == kingside_parameters.origin.rook { - board.revoke_castling_right(None, Wing::KingSide); + board.revoke_castling_rights(None, Wing::KingSide.into()); } } let queenside_parameters = CastleParameters::get(board.active_color(), Wing::QueenSide); if origin == queenside_parameters.origin.rook { - board.revoke_castling_right(None, Wing::QueenSide); + board.revoke_castling_rights(None, Wing::QueenSide.into()); } } Shape::King => { - board.revoke_castling_right(None, Wing::KingSide); - board.revoke_castling_right(None, Wing::QueenSide); + board.revoke_castling_rights(None, CastleRightsOption::All); } _ => {} } @@ -562,7 +562,7 @@ mod tests { assert_eq!(board.get_piece(Square::H1), None); assert_eq!(board.get_piece(Square::G1), Some(piece!(White King))); assert_eq!(board.get_piece(Square::F1), Some(piece!(White Rook))); - assert!(!board.color_has_castling_right_unwrapped(Color::White, Wing::KingSide)); + assert!(!board.has_castling_right_unwrapped(Color::White, Wing::KingSide)); Ok(()) } @@ -582,7 +582,7 @@ mod tests { assert_eq!(board.get_piece(Square::A1), None); assert_eq!(board.get_piece(Square::C1), Some(piece!(White King))); assert_eq!(board.get_piece(Square::D1), Some(piece!(White Rook))); - assert!(!board.color_has_castling_right_unwrapped(Color::White, Wing::QueenSide)); + assert!(!board.has_castling_right_unwrapped(Color::White, Wing::QueenSide)); Ok(()) } diff --git a/moves/src/record.rs b/moves/src/record.rs index 47a2c3f..24472b8 100644 --- a/moves/src/record.rs +++ b/moves/src/record.rs @@ -1,7 +1,7 @@ // Eryn Wells use crate::Move; -use chessfriend_board::{board::HalfMoveClock, Board, CastleRights}; +use chessfriend_board::{Board, CastleRights, board::HalfMoveClock}; use chessfriend_core::{Color, Piece, Square}; /// A record of a move made on a board. This struct contains all the information @@ -35,7 +35,7 @@ impl MoveRecord { color: board.active_color(), ply, en_passant_target: board.en_passant_target(), - castling_rights: board.castling_rights(), + castling_rights: *board.castling_rights(), half_move_clock: board.half_move_clock, captured_piece: capture, } diff --git a/moves/src/unmake_move.rs b/moves/src/unmake_move.rs index 8a477c6..69c43b7 100644 --- a/moves/src/unmake_move.rs +++ b/moves/src/unmake_move.rs @@ -396,7 +396,7 @@ mod tests { White Rook on H1, ]; - let original_castling_rights = board.castling_rights(); + let original_castling_rights = *board.castling_rights(); let ply = Move::castle(Color::White, Wing::KingSide); let record = board.make_move(ply, ValidateMove::Yes)?; @@ -406,7 +406,7 @@ mod tests { assert_eq!(board.get_piece(Square::H1), None); assert_eq!(board.get_piece(Square::G1), Some(piece!(White King))); assert_eq!(board.get_piece(Square::F1), Some(piece!(White Rook))); - assert!(!board.color_has_castling_right_unwrapped(Color::White, Wing::KingSide)); + assert!(!board.has_castling_right_unwrapped(Color::White, Wing::KingSide)); board.unmake_move(&record)?; @@ -415,7 +415,7 @@ mod tests { assert_eq!(board.get_piece(Square::H1), Some(piece!(White Rook))); assert_eq!(board.get_piece(Square::G1), None); assert_eq!(board.get_piece(Square::F1), None); - assert_eq!(board.castling_rights(), original_castling_rights); + assert_eq!(*board.castling_rights(), original_castling_rights); assert_eq!(board.active_color(), Color::White); Ok(()) @@ -428,7 +428,7 @@ mod tests { White Rook on A1, ]; - let original_castling_rights = board.castling_rights(); + let original_castling_rights = *board.castling_rights(); let ply = Move::castle(Color::White, Wing::QueenSide); let record = board.make_move(ply, ValidateMove::Yes)?; @@ -438,7 +438,7 @@ mod tests { assert_eq!(board.get_piece(Square::A1), None); assert_eq!(board.get_piece(Square::C1), Some(piece!(White King))); assert_eq!(board.get_piece(Square::D1), Some(piece!(White Rook))); - assert!(!board.color_has_castling_right_unwrapped(Color::White, Wing::QueenSide)); + assert!(!board.has_castling_right_unwrapped(Color::White, Wing::QueenSide)); board.unmake_move(&record)?; @@ -447,7 +447,7 @@ mod tests { assert_eq!(board.get_piece(Square::A1), Some(piece!(White Rook))); assert_eq!(board.get_piece(Square::C1), None); assert_eq!(board.get_piece(Square::D1), None); - assert_eq!(board.castling_rights(), original_castling_rights); + assert_eq!(*board.castling_rights(), original_castling_rights); assert_eq!(board.active_color(), Color::White); Ok(()) @@ -460,7 +460,7 @@ mod tests { Black Rook on H8, ]); - let original_castling_rights = board.castling_rights(); + let original_castling_rights = *board.castling_rights(); let ply = Move::castle(Color::Black, Wing::KingSide); let record = board.make_move(ply, ValidateMove::Yes)?; @@ -478,7 +478,7 @@ mod tests { assert_eq!(board.get_piece(Square::H8), Some(piece!(Black Rook))); assert_eq!(board.get_piece(Square::G8), None); assert_eq!(board.get_piece(Square::F8), None); - assert_eq!(board.castling_rights(), original_castling_rights); + assert_eq!(*board.castling_rights(), original_castling_rights); assert_eq!(board.active_color(), Color::Black); Ok(())