chessfriend/moves/src/builder.rs
Eryn Wells b3c472fbce Fix some imports in the moves package
Castle and EnPassant moved to the board package. Reference these types there.
Add the board packages as a dependency to the moves package.
2024-04-26 09:50:42 -04:00

396 lines
9.8 KiB
Rust

// Eryn Wells <eryn@erynwells.me>
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<Move, Error>;
type EncodedMoveResult = std::result::Result<u16, Error>;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Error {
MissingOriginSquare,
MissingTargetSquare,
MissingCaptureSquare,
InvalidEnPassantSquare,
}
pub trait Style {
fn origin_square(&self) -> Option<Square> {
None
}
fn target_square(&self) -> Option<Square> {
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<S: Style> {
style: S,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Null;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Push {
from: Option<Square>,
to: Option<Square>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct DoublePush {
from: Square,
to: Square,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Capture {
push: Push,
capture: Option<Square>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EnPassantCapture {
push: Push,
capture: Option<EnPassant>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Promotion<S> {
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<Square> {
self.from
}
fn target_square(&self) -> Option<Square> {
self.to
}
}
impl Style for Capture {
fn origin_square(&self) -> Option<Square> {
self.push.from
}
fn target_square(&self) -> Option<Square> {
self.push.to
}
}
impl Style for Castle {
fn origin_square(&self) -> Option<Square> {
let parameters = self.castle.parameters(self.color);
Some(parameters.king_origin_square())
}
fn target_square(&self) -> Option<Square> {
let parameters = self.castle.parameters(self.color);
Some(parameters.king_target_square())
}
}
impl Style for DoublePush {
fn origin_square(&self) -> Option<Square> {
Some(self.from)
}
fn target_square(&self) -> Option<Square> {
Some(self.to)
}
fn into_move_bits(&self) -> StdResult<u16, Error> {
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<Square> {
self.push.from
}
fn target_square(&self) -> Option<Square> {
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<Push> {
fn origin_square(&self) -> Option<Square> {
self.style.from
}
fn target_square(&self) -> Option<Square> {
self.style.to
}
}
impl Style for Promotion<Capture> {
fn origin_square(&self) -> Option<Square> {
self.style.push.from
}
fn target_square(&self) -> Option<Square> {
self.style.push.to
}
}
impl Promotion<Push> {
fn into_move_bits(&self) -> StdResult<u16, Error> {
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<Capture> {
fn into_move_bits(&self) -> StdResult<u16, Error> {
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<Null> {
pub fn new() -> Self {
Self { style: Null }
}
pub fn push(piece: &PlacedPiece) -> Builder<Push> {
Builder {
style: Push {
from: Some(piece.square()),
to: None,
},
}
}
pub fn double_push(file: File, color: Color) -> Builder<DoublePush> {
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<Castle> {
Builder {
style: Castle { color, castle },
}
}
pub fn capturing_piece(piece: &PlacedPiece, capturing: &PlacedPiece) -> Builder<Capture> {
Self::push(piece).capturing_piece(&capturing)
}
pub fn from(&self, square: Square) -> Builder<Push> {
Builder {
style: Push {
from: Some(square),
to: None,
},
}
}
pub fn build(&self) -> Move {
Move(0)
}
}
impl Builder<Push> {
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<Capture> {
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<EnPassantCapture> {
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<Capture> {
Builder {
style: Capture {
push: self.style.clone(),
capture: Some(piece.square()),
},
}
}
pub fn promoting_to(&self, shape: PromotionShape) -> Builder<Promotion<Push>> {
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<Castle> {
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<Capture> {
pub fn promoting_to(self, shape: PromotionShape) -> Builder<Promotion<Capture>> {
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<DoublePush> {
pub fn build(&self) -> Result {
Ok(Move(Kind::DoublePush as u16 | self.style.into_move_bits()?))
}
}
impl Builder<EnPassantCapture> {
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<Promotion<Push>> {
pub fn build(&self) -> Result {
Ok(Move(self.style.into_move_bits()?))
}
}
impl Builder<Promotion<Capture>> {
pub fn build(&self) -> Result {
Ok(Move(self.style.into_move_bits()?))
}
}