// Eryn Wells use crate::defs::Kind; use chessfriend_board::castle::Castle; use chessfriend_core::{Rank, Shape, Square}; use std::fmt; /// A single player's move. In chess parlance, this is a "ply". #[derive(Clone, Copy, Eq, Hash, PartialEq)] pub struct Move(pub(crate) u16); impl Move { pub fn origin_square(&self) -> Square { ((self.0 >> 4) & 0b111111).try_into().unwrap() } pub fn target_square(&self) -> Square { (self.0 >> 10).try_into().unwrap() } pub fn capture_square(&self) -> Option { if self.is_en_passant() { let target_square = self.target_square(); return Some(match target_square.rank() { Rank::THREE => Square::from_file_rank(target_square.file(), Rank::FOUR), Rank::SIX => Square::from_file_rank(target_square.file(), Rank::FIVE), _ => unreachable!(), }); } if self.is_capture() { return Some(self.target_square()); } None } pub fn is_quiet(&self) -> bool { self.flags() == Kind::Quiet as u16 } pub fn is_double_push(&self) -> bool { self.flags() == Kind::DoublePush as u16 } pub fn is_castle(&self) -> bool { self.castle().is_some() } pub fn castle(&self) -> Option { match self.flags() { 0b0010 => Some(Castle::KingSide), 0b0011 => Some(Castle::QueenSide), _ => None, } } pub fn is_capture(&self) -> bool { (self.0 & 0b0100) != 0 } pub fn is_en_passant(&self) -> bool { self.flags() == 0b0101 } pub fn is_promotion(&self) -> bool { (self.0 & 0b1000) != 0 } pub fn promotion(&self) -> Option { if !self.is_promotion() { return None; } Some(match self.special() { 0b00 => Shape::Knight, 0b01 => Shape::Bishop, 0b10 => Shape::Rook, 0b11 => Shape::Queen, _ => unreachable!(), }) } #[inline] fn flags(&self) -> u16 { self.0 & 0b1111 } #[inline] fn special(&self) -> u16 { self.0 & 0b11 } fn _transfer_char(&self) -> char { if self.is_capture() || self.is_en_passant() { 'x' } else { '-' } } } impl fmt::Display for Move { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(castle) = self.castle() { match castle { Castle::KingSide => return write!(f, "0-0"), Castle::QueenSide => return write!(f, "0-0-0"), } } write!( f, "{}{}{}", self.origin_square(), self._transfer_char(), self.target_square() )?; if let Some(promotion) = self.promotion() { write!(f, "={}", promotion)?; } else if self.is_en_passant() { write!(f, " e.p.")?; } Ok(()) } } impl fmt::Debug for Move { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Move") .field(&format_args!("{:08b}", &self.0)) .finish() } }