// Eryn Wells use crate::{defs::Kind, Move, PromotionShape}; use chessfriend_board::{castle, en_passant::EnPassant}; use chessfriend_core::{Color, File, PlacedPiece, Rank, Square}; use std::result::Result as StdResult; pub type Result = std::result::Result; type EncodedMoveResult = 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) -> EncodedMoveResult { let origin_square = self.origin_square().ok_or(Error::MissingOriginSquare)?; let target_square = self.target_square().ok_or(Error::MissingTargetSquare)?; Ok(self._build_move_bits(origin_square, target_square)) } unsafe fn into_move_bits_unchecked(&self) -> u16 { let origin_square = self.origin_square().unwrap(); let target_square = self.target_square().unwrap(); self._build_move_bits(origin_square, target_square) } fn _build_move_bits(&self, origin_square: Square, target_square: Square) -> u16 { (origin_square as u16 & 0b111111) << 4 | (target_square as u16 & 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 { color: Color, castle: castle::Castle, } impl EnPassantCapture { fn _build_move_bits(&self, origin_square: Square, target_square: Square) -> u16 { (origin_square as u16 & 0b111111) << 4 | (target_square as u16 & 0b111111) << 10 } } 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 { fn origin_square(&self) -> Option { let parameters = self.castle.parameters(self.color); Some(parameters.king_origin_square()) } fn target_square(&self) -> Option { let parameters = self.castle.parameters(self.color); Some(parameters.king_target_square()) } } 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) -> EncodedMoveResult { let origin_square = self.origin_square().ok_or(Error::MissingOriginSquare)?; let target_square = self.target_square().ok_or(Error::MissingTargetSquare)?; Ok(self._build_move_bits(origin_square, target_square)) } } 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) -> Builder { Builder { style: Push { from: Some(piece.square()), to: None, }, } } 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(color: Color, castle: castle::Castle) -> Builder { Builder { style: Castle { color, castle }, } } pub fn capturing_piece(piece: &PlacedPiece, capturing: &PlacedPiece) -> Builder { Self::push(piece).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.clone(); style.to = Some(square); Builder { style: Capture { push: style, capture: Some(square), }, } } pub fn capturing_en_passant_on(&self, target_square: Square) -> Builder { match EnPassant::from_target_square(target_square) { Some(en_passant) => { let mut style = self.style.clone(); style.to = Some(en_passant.target_square()); Builder { style: EnPassantCapture { push: style, capture: Some(en_passant), }, } } None => todo!(), } } pub fn capturing_piece(&self, piece: &PlacedPiece) -> Builder { Builder { style: Capture { push: self.style.clone(), capture: Some(piece.square()), }, } } pub fn promoting_to(&self, shape: PromotionShape) -> Builder> { Builder { style: Promotion { style: self.style.clone(), 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) -> Result { Ok(Move(self.bits() | self.style.into_move_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) -> Move { Move(Kind::EnPassantCapture as u16 | self.style.into_move_bits_unchecked()) } pub fn build(&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()?)) } }