// Eryn Wells use crate::{castle::Castle, defs::Kind}; 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_capture() { return Some(self.target_square()); } 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!(), }); } 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 } } 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() } }