// Eryn Wells mod display; pub use self::display::{PieceDisplay, PieceDisplayStyle}; use crate::{Color, Shape, Square}; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct Piece { pub color: Color, pub shape: Shape, } macro_rules! piece_constructor { ($func_name:ident, $type:tt) => { #[must_use] pub fn $func_name(color: Color) -> Piece { Piece { color, shape: Shape::$type, } } }; } macro_rules! is_shape { ($func_name:ident, $shape:ident) => { #[must_use] pub fn $func_name(&self) -> bool { self.shape == Shape::$shape } }; } impl Piece { #[must_use] pub fn new(color: Color, shape: Shape) -> Piece { Piece { color, shape } } piece_constructor!(pawn, Pawn); piece_constructor!(knight, Knight); piece_constructor!(bishop, Bishop); piece_constructor!(rook, Rook); piece_constructor!(queen, Queen); piece_constructor!(king, King); is_shape!(is_pawn, Pawn); is_shape!(is_knight, Knight); is_shape!(is_bishop, Bishop); is_shape!(is_rook, Rook); is_shape!(is_queen, Queen); is_shape!(is_king, King); #[must_use] pub fn to_ascii(self) -> char { let ch = self.shape.to_ascii(); match self.color { Color::White => ch, Color::Black => ch.to_ascii_lowercase(), } } #[must_use] fn to_unicode(self) -> char { match (self.color, self.shape) { (Color::Black, Shape::Pawn) => '♟', (Color::Black, Shape::Knight) => '♞', (Color::Black, Shape::Bishop) => '♝', (Color::Black, Shape::Rook) => '♜', (Color::Black, Shape::Queen) => '♛', (Color::Black, Shape::King) => '♚', (Color::White, Shape::Pawn) => '♙', (Color::White, Shape::Knight) => '♘', (Color::White, Shape::Bishop) => '♗', (Color::White, Shape::Rook) => '♖', (Color::White, Shape::Queen) => '♕', (Color::White, Shape::King) => '♔', } } } impl std::fmt::Display for Piece { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}", PieceDisplay { piece: *self, style: PieceDisplayStyle::default() } ) } } impl From for Piece { fn from(value: PlacedPiece) -> Self { value.piece } } impl From<&PlacedPiece> for Piece { fn from(value: &PlacedPiece) -> Self { value.piece } } #[deprecated] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct PlacedPiece { pub piece: Piece, pub square: Square, } macro_rules! is_shape { ($func_name:ident, $shape:ident) => { #[must_use] pub fn $func_name(&self) -> bool { self.piece().shape == Shape::$shape } }; } impl PlacedPiece { #[must_use] pub const fn new(piece: Piece, square: Square) -> PlacedPiece { PlacedPiece { piece, square } } /// The [Piece] itself #[inline] #[must_use] pub fn piece(&self) -> Piece { self.piece } is_shape!(is_pawn, Pawn); is_shape!(is_knight, Knight); is_shape!(is_bishop, Bishop); is_shape!(is_rook, Rook); is_shape!(is_queen, Queen); is_shape!(is_king, King); #[must_use] pub fn is_kingside_rook(&self) -> bool { self.is_rook() && match self.piece.color { Color::White => self.square == Square::H1, Color::Black => self.square == Square::H8, } } #[must_use] pub fn is_queenside_rook(&self) -> bool { self.is_rook() && match self.piece.color { Color::White => self.square == Square::A1, Color::Black => self.square == Square::A8, } } } impl std::fmt::Display for PlacedPiece { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}{}", self.piece, self.square) } } impl From<(&Square, &Piece)> for PlacedPiece { fn from(value: (&Square, &Piece)) -> Self { PlacedPiece::new(*value.1, *value.0) } } #[cfg(test)] mod tests { use super::*; #[test] fn shape_try_from() { assert_eq!(Shape::try_from('p'), Ok(Shape::Pawn)); assert_eq!(Shape::try_from("p"), Ok(Shape::Pawn)); } #[test] fn shape_into_char() { assert_eq!(>::into(Shape::Pawn), 'P'); } }