chessfriend/core/src/pieces.rs

191 lines
4.6 KiB
Rust
Raw Normal View History

// Eryn Wells <eryn@erynwells.me>
mod display;
pub use self::display::{PieceDisplay, PieceDisplayStyle};
2025-05-08 17:37:51 -07:00
use crate::{Color, Shape, Square};
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Piece {
2025-05-08 17:37:51 -07:00
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<PlacedPiece> for Piece {
fn from(value: PlacedPiece) -> Self {
value.piece
}
}
impl From<&PlacedPiece> for Piece {
fn from(value: &PlacedPiece) -> Self {
value.piece
}
}
2025-05-08 17:37:51 -07:00
#[deprecated]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct PlacedPiece {
2025-05-08 17:37:51 -07:00
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()
2025-05-08 17:37:51 -07:00
&& 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()
2025-05-08 17:37:51 -07:00
&& 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() {
2025-05-08 17:37:51 -07:00
assert_eq!(<Shape as Into<char>>::into(Shape::Pawn), 'P');
}
}