From 6842b341e8c575677ee757013b37061cbb40d656 Mon Sep 17 00:00:00 2001 From: Danny Hammer Date: Mon, 28 Oct 2024 16:13:04 -0600 Subject: [PATCH] chore: debugging some castling / parsing issues --- chessie/src/moves.rs | 20 ++++++++++++++------ chessie/src/position.rs | 15 +++++++++------ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/chessie/src/moves.rs b/chessie/src/moves.rs index bb0b412..5480068 100644 --- a/chessie/src/moves.rs +++ b/chessie/src/moves.rs @@ -143,7 +143,10 @@ impl MoveKind { } // King moves are only special if castling - PieceKind::King if victim.is_some_and(|victim| victim.color() == piece.color()) => { + PieceKind::King + if victim + .is_some_and(|victim| victim.color() == piece.color() && victim.is_rook()) => + { if to.file() > from.file() { kind = Self::ShortCastle; } else { @@ -456,18 +459,23 @@ impl Move { is_ok } } + /// Creates a [`Move`] from a string, according to the [Universal Chess Interface](https://en.wikipedia.org//wiki/Universal_Chess_Interface) notation, extracting extra info from the provided [`Position`] /// /// Will return a [`anyhow::Error`] if the string is invalid in any way. /// /// # Example /// ``` - /// # use chessie::{Move, Square, MoveKind, PieceKind, Position}; - /// // A sample test position for discovering promotion bugs. + /// # use chessie::*; /// let position = Position::from_fen("n1n5/PPPk4/8/8/8/8/4Kppp/5N1N b - - 0 1 ").unwrap(); /// let b7c8b = Move::from_uci(&position, "b7c8b"); - /// assert!(b7c8b.is_ok()); /// assert_eq!(b7c8b.unwrap(), Move::new(Square::B7, Square::C8, MoveKind::promotion_capture(PieceKind::Bishop))); + /// + /// // Automatically parses castling moves in standard notation to use the KxR format + /// let position = Position::from_fen("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 1").unwrap(); + /// let e1c1 = Move::from_uci(&position, "e1c1"); + /// // Rook is on A1 + /// assert_eq!(e1c1.unwrap(), Move::new(Square::E1, Square::A1, MoveKind::LongCastle)); /// ``` pub fn from_uci(position: &Position, uci: &str) -> Result { // Extract the to/from squares @@ -550,10 +558,10 @@ impl Move { pub fn into_standard_castle(self) -> Self { if self.is_short_castle() { let new_to = Square::new(File::G, self.from().rank()); - Self::new(self.from(), new_to, self.kind()) + Self::new(self.from(), new_to, MoveKind::ShortCastle) } else if self.is_long_castle() { let new_to = Square::new(File::C, self.from().rank()); - Self::new(self.from(), new_to, self.kind()) + Self::new(self.from(), new_to, MoveKind::LongCastle) } else { // If this move isn't a castle, no modification needs to be done self diff --git a/chessie/src/position.rs b/chessie/src/position.rs index 5e2514a..2a6778d 100644 --- a/chessie/src/position.rs +++ b/chessie/src/position.rs @@ -583,25 +583,26 @@ impl Position { if mv.is_capture() { // If this move was en passant, the piece we captured isn't at `to`, it's one square behind let victim_square = if mv.is_en_passant() { - // Safety: En passant cannot occur on the first or eighth, so this is guaranteed to have a square behind it. + // Safety: En passant cannot occur on the first or eighth rank, so this is guaranteed to have a square behind it. unsafe { to.backward_by(color, 1).unwrap_unchecked() } } else { to }; // Safety: This is a capture; there *must* be a piece at the destination square. - let victim = unsafe { self.take(victim_square).unwrap_unchecked() }; + let victim = self.take(victim_square).unwrap(); + // let victim = unsafe { self.take(victim_square).unwrap_unchecked() }; let victim_color = victim.color(); // If the capture was on a rook's starting square, disable that side's castling. if self.castling_rights[victim_color] .long - .is_some_and(|sq| to == sq) + .is_some_and(|sq| victim_square == sq) { self.clear_long_castling_rights(victim_color); } else if self.castling_rights[victim_color] .short - .is_some_and(|sq| to == sq) + .is_some_and(|sq| victim_square == sq) { self.clear_short_castling_rights(victim_color); } @@ -614,7 +615,8 @@ impl Position { self.key.hash_optional_ep_square(self.ep_square()); } else if mv.is_short_castle() { // Safety; This is a castle. There *must* be a Rook at `to`. - let rook = unsafe { self.take(to).unwrap_unchecked() }; + // let rook = unsafe { self.take(to).unwrap_unchecked() }; + let rook = self.take(to).unwrap(); self.place(rook, Square::rook_short_castle(color)); // The King doesn't actually move to the Rook, so update the destination square @@ -624,7 +626,8 @@ impl Position { self.clear_castling_rights(color); } else if mv.is_long_castle() { // Safety; This is a castle. There *must* be a Rook at `to`. - let rook = unsafe { self.take(to).unwrap_unchecked() }; + // let rook = unsafe { self.take(to).unwrap_unchecked() }; + let rook = self.take(to).unwrap(); self.place(rook, Square::rook_long_castle(color)); // The King doesn't actually move to the Rook, so update the destination square