//! UCI notation. //! //! Move notation as defined by the Universal Chess Interface standard used for most chess engines //! and chess servers. //! //! A move is described by its origin and target squares. Castling is described as the move done by //! the king. For promotion, a lowercase letter is added at the end of the move. //! //! Examples: *`e2e4`*, *`d1d8`*, *`e1g1`* (short castling), *`h7h8q`* (promotion) use crate::board::*; use crate::moves::*; use crate::position::*; /// **The UCI notation of a move.** /// /// UCI notation can be obtained from a legal move using the [`Move::to_uci`] method. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct UciMove { pub from: Square, pub to: Square, pub promotion: Option, } impl core::fmt::Display for UciMove { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "{}{}", self.from, self.to)?; if let Some(promotion) = self.promotion { write!(f, "{}", promotion.to_char_lowercase())?; } Ok(()) } } impl core::fmt::Debug for UciMove { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { write!(f, "UciMove(\"{self}\")") } } impl core::str::FromStr for UciMove { type Err = ParseUciMoveError; #[inline] fn from_str(s: &str) -> Result { Self::from_ascii(s.as_bytes()).ok_or(ParseUciMoveError) } } /// A syntax error when parsing a [`UciMove`]. #[derive(Debug)] pub struct ParseUciMoveError; impl core::fmt::Display for ParseUciMoveError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str("invalid UCI notation") } } impl core::error::Error for ParseUciMoveError {} /// An error when converting [`UciMove`] notation to a playable [`Move`]. #[derive(Debug)] pub enum InvalidUciMove { /// The is no move on the position that matches the UCI notation. Illegal, } impl core::fmt::Display for InvalidUciMove { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str("illegal UCI move") } } impl core::error::Error for InvalidUciMove {} impl UciMove { /// Tries to convert UCI notation to a playable move. #[inline] pub fn to_move<'l>(&self, position: &'l Position) -> Result, InvalidUciMove> { position.move_from_uci(*self) } /// Tries to read UCI notation from ascii text. #[inline] pub fn from_ascii(s: &[u8]) -> Option { match s { [a, b, c, d, s @ ..] => Some(Self { from: Square::from_coords(File::from_ascii(*a)?, Rank::from_ascii(*b)?), to: Square::from_coords(File::from_ascii(*c)?, Rank::from_ascii(*d)?), promotion: match s { [] => None, [c] => Some(Role::from_ascii(*c)?), _ => return None, }, }), _ => None, } } }