// Eryn Wells use crate::{castle, defs::Kind, Move, PromotionShape}; use chessfriend_core::{Color, File, PlacedPiece, Rank, Square}; use std::result::Result as StdResult; pub type Result = std::result::Result; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Error { MissingOriginSquare, MissingTargetSquare, MissingCaptureSquare, InvalidEnPassantSquare, } pub trait Style { fn origin_square(&self) -> Option { None } fn target_square(&self) -> Option { None } fn into_move_bits(&self) -> StdResult { let origin_square = self.origin_square().ok_or(Error::MissingOriginSquare)? as u16; let target_square = self.target_square().ok_or(Error::MissingTargetSquare)? as u16; Ok((origin_square & 0b111111) << 4 | (target_square & 0b111111) << 10) } } #[derive(Clone, Debug, Eq, PartialEq)] pub struct Builder { style: S, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct Null; #[derive(Clone, Debug, Eq, PartialEq)] pub struct Push { from: Option, to: Option, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct DoublePush { from: Square, to: Square, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct Capture { push: Push, capture: Option, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct EnPassantCapture { push: Push, capture: Option, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct Promotion { style: S, promotion: PromotionShape, } #[derive(Clone, Debug, Eq, PartialEq)] pub struct Castle { castle: castle::Castle, } impl Style for Null {} impl Style for Push { fn origin_square(&self) -> Option { self.from } fn target_square(&self) -> Option { self.to } } impl Style for Capture { fn origin_square(&self) -> Option { self.push.from } fn target_square(&self) -> Option { self.push.to } } impl Style for Castle {} impl Style for DoublePush { fn origin_square(&self) -> Option { Some(self.from) } fn target_square(&self) -> Option { Some(self.to) } fn into_move_bits(&self) -> StdResult { Ok(Kind::DoublePush as u16 | (self.from as u16 & 0b111111) << 4 | (self.to as u16 & 0b111111) << 10) } } impl Style for EnPassantCapture { fn origin_square(&self) -> Option { self.push.from } fn target_square(&self) -> Option { self.push.to } fn into_move_bits(&self) -> StdResult { let origin_square = self.origin_square().ok_or(Error::MissingOriginSquare)? as u16; let target_square = self.target_square().ok_or(Error::MissingTargetSquare)? as u16; Ok((origin_square & 0b111111) << 4 | (target_square & 0b111111) << 10) } } impl Style for Promotion { fn origin_square(&self) -> Option { self.style.from } fn target_square(&self) -> Option { self.style.to } } impl Style for Promotion { fn origin_square(&self) -> Option { self.style.push.from } fn target_square(&self) -> Option { self.style.push.to } } impl Promotion { fn into_move_bits(&self) -> StdResult { let origin_square = self .style .origin_square() .ok_or(Error::MissingOriginSquare)? as u16; let target_square = self .style .target_square() .ok_or(Error::MissingTargetSquare)? as u16; Ok(Kind::Promotion as u16 | self.promotion as u16 | (origin_square & 0b111111) << 4 | (target_square & 0b111111) << 10) } } impl Promotion { fn into_move_bits(&self) -> StdResult { let origin_square = self .style .origin_square() .ok_or(Error::MissingOriginSquare)? as u16; let target_square = self .style .target_square() .ok_or(Error::MissingTargetSquare)? as u16; Ok(Kind::CapturePromotion as u16 | self.promotion as u16 | (origin_square & 0b111111) << 4 | (target_square & 0b111111) << 10) } } impl Builder { pub fn new() -> Self { Self { style: Null } } pub fn push(piece: &PlacedPiece, to: Square) -> Builder { Builder { style: Push { from: Some(piece.square()), to: Some(to), }, } } pub fn double_push(file: File, color: Color) -> Builder { let (from, to) = match color { Color::White => ( Square::from_file_rank(file, Rank::TWO), Square::from_file_rank(file, Rank::FOUR), ), Color::Black => ( Square::from_file_rank(file, Rank::SEVEN), Square::from_file_rank(file, Rank::FIVE), ), }; Builder { style: DoublePush { from, to }, } } pub fn castling(castle: castle::Castle) -> Builder { Builder { style: Castle { castle }, } } pub fn capturing_on(piece: &PlacedPiece, to: Square) -> Builder { Self::push(piece, to).capturing_on(to) } pub fn capturing_piece(piece: &PlacedPiece, capturing: &PlacedPiece) -> Builder { Self::push(piece, capturing.square()).capturing_piece(&capturing) } pub fn from(self, square: Square) -> Builder { Builder { style: Push { from: Some(square), to: None, }, } } pub fn build(&self) -> Move { Move(0) } } impl Builder { pub fn from(&mut self, square: Square) -> &mut Self { self.style.from = Some(square); self } pub fn to(&mut self, square: Square) -> &mut Self { self.style.to = Some(square); self } pub fn capturing_on(self, square: Square) -> Builder { let mut style = self.style; style.to = Some(square); Builder { style: Capture { push: style, capture: Some(square), }, } } pub fn capturing_en_passant_on(self, square: Square) -> Builder { let mut style = self.style; style.to = Some(square); Builder { style: EnPassantCapture { push: self.style, capture: Some(square), }, } } pub fn capturing_piece(self, piece: &PlacedPiece) -> Builder { Builder { style: Capture { push: self.style, capture: Some(piece.square()), }, } } pub fn promoting_to(self, shape: PromotionShape) -> Builder> { Builder { style: Promotion { style: self.style, promotion: shape, }, } } pub fn build(&self) -> Result { Ok(Move(Kind::Quiet as u16 | self.style.into_move_bits()?)) } } impl Builder { fn bits(&self) -> u16 { let bits = match self.style.castle { castle::Castle::KingSide => Kind::KingSideCastle, castle::Castle::QueenSide => Kind::QueenSideCastle, }; bits as u16 } pub fn build(&self) -> Move { Move(self.bits()) } } impl Builder { pub fn promoting_to(self, shape: PromotionShape) -> Builder> { Builder { style: Promotion { style: self.style, promotion: shape, }, } } pub fn build(&self) -> Result { Ok(Move(Kind::Capture as u16 | self.style.into_move_bits()?)) } } impl Builder { pub fn build(&self) -> Result { Ok(Move(Kind::DoublePush as u16 | self.style.into_move_bits()?)) } } impl Builder { pub unsafe fn build_unchecked(&self) -> Result { Ok(Move( Kind::EnPassantCapture as u16 | self.style.into_move_bits()?, )) } } impl Builder> { pub fn build(&self) -> Result { Ok(Move(self.style.into_move_bits()?)) } } impl Builder> { pub fn build(&self) -> Result { Ok(Move(self.style.into_move_bits()?)) } }