2023-12-23 09:18:01 -07:00
|
|
|
// Eryn Wells <eryn@erynwells.me>
|
|
|
|
|
2025-05-19 14:18:31 -07:00
|
|
|
mod display;
|
2024-01-22 08:10:40 -08:00
|
|
|
|
2025-05-19 14:18:31 -07:00
|
|
|
pub use self::display::{PieceDisplay, PieceDisplayStyle};
|
2025-05-08 17:37:51 -07:00
|
|
|
|
2025-05-19 14:18:31 -07:00
|
|
|
use crate::{Color, Shape, Square};
|
2023-12-26 13:57:36 -07:00
|
|
|
|
2023-12-26 09:15:24 -07:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
2023-12-23 09:18:01 -07:00
|
|
|
pub struct Piece {
|
2025-05-08 17:37:51 -07:00
|
|
|
pub color: Color,
|
|
|
|
pub shape: Shape,
|
2023-12-23 09:18:01 -07:00
|
|
|
}
|
|
|
|
|
2023-12-26 21:31:05 -07:00
|
|
|
macro_rules! piece_constructor {
|
|
|
|
($func_name:ident, $type:tt) => {
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
2023-12-26 21:31:05 -07:00
|
|
|
pub fn $func_name(color: Color) -> Piece {
|
|
|
|
Piece {
|
|
|
|
color,
|
|
|
|
shape: Shape::$type,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-01-21 09:15:41 -08:00
|
|
|
macro_rules! is_shape {
|
|
|
|
($func_name:ident, $shape:ident) => {
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
2024-01-21 09:15:41 -08:00
|
|
|
pub fn $func_name(&self) -> bool {
|
|
|
|
self.shape == Shape::$shape
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-12-23 09:18:01 -07:00
|
|
|
impl Piece {
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
2023-12-23 20:14:24 -07:00
|
|
|
pub fn new(color: Color, shape: Shape) -> Piece {
|
|
|
|
Piece { color, shape }
|
2023-12-23 09:18:01 -07:00
|
|
|
}
|
2023-12-26 21:31:05 -07:00
|
|
|
|
|
|
|
piece_constructor!(pawn, Pawn);
|
|
|
|
piece_constructor!(knight, Knight);
|
|
|
|
piece_constructor!(bishop, Bishop);
|
|
|
|
piece_constructor!(rook, Rook);
|
|
|
|
piece_constructor!(queen, Queen);
|
|
|
|
piece_constructor!(king, King);
|
2023-12-29 09:17:33 -08:00
|
|
|
|
2024-01-21 09:15:41 -08:00
|
|
|
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);
|
2024-01-21 14:56:03 -08:00
|
|
|
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
|
|
|
pub fn to_ascii(self) -> char {
|
2024-02-11 08:45:19 -07:00
|
|
|
let ch = self.shape.to_ascii();
|
|
|
|
match self.color {
|
|
|
|
Color::White => ch,
|
|
|
|
Color::Black => ch.to_ascii_lowercase(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
|
|
|
fn to_unicode(self) -> char {
|
2024-02-11 08:45:19 -07:00
|
|
|
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) => '♔',
|
|
|
|
}
|
2024-01-21 14:56:03 -08:00
|
|
|
}
|
2023-12-23 09:18:01 -07:00
|
|
|
}
|
2023-12-26 09:19:38 -07:00
|
|
|
|
2025-05-19 14:18:31 -07:00
|
|
|
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()
|
|
|
|
}
|
|
|
|
)
|
2024-01-14 10:51:40 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-13 07:34:50 -07:00
|
|
|
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]
|
2023-12-26 09:19:38 -07:00
|
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
|
|
|
pub struct PlacedPiece {
|
2025-05-08 17:37:51 -07:00
|
|
|
pub piece: Piece,
|
|
|
|
pub square: Square,
|
2023-12-26 09:19:38 -07:00
|
|
|
}
|
|
|
|
|
2024-01-21 09:15:41 -08:00
|
|
|
macro_rules! is_shape {
|
|
|
|
($func_name:ident, $shape:ident) => {
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
2024-01-21 09:15:41 -08:00
|
|
|
pub fn $func_name(&self) -> bool {
|
|
|
|
self.piece().shape == Shape::$shape
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-12-26 09:19:38 -07:00
|
|
|
impl PlacedPiece {
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
2024-01-06 08:49:51 -08:00
|
|
|
pub const fn new(piece: Piece, square: Square) -> PlacedPiece {
|
2023-12-26 09:19:38 -07:00
|
|
|
PlacedPiece { piece, square }
|
|
|
|
}
|
2023-12-29 09:17:33 -08:00
|
|
|
|
2024-03-14 17:00:46 -07:00
|
|
|
/// The [Piece] itself
|
2024-01-06 08:49:51 -08:00
|
|
|
#[inline]
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
2024-07-13 07:34:50 -07:00
|
|
|
pub fn piece(&self) -> Piece {
|
|
|
|
self.piece
|
2023-12-29 09:17:33 -08:00
|
|
|
}
|
|
|
|
|
2024-01-21 09:15:41 -08:00
|
|
|
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);
|
|
|
|
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
2024-01-21 09:15:41 -08:00
|
|
|
pub fn is_kingside_rook(&self) -> bool {
|
|
|
|
self.is_rook()
|
2025-05-08 17:37:51 -07:00
|
|
|
&& match self.piece.color {
|
2024-01-21 09:15:41 -08:00
|
|
|
Color::White => self.square == Square::H1,
|
|
|
|
Color::Black => self.square == Square::H8,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-14 17:00:46 -07:00
|
|
|
#[must_use]
|
2024-01-21 09:15:41 -08:00
|
|
|
pub fn is_queenside_rook(&self) -> bool {
|
|
|
|
self.is_rook()
|
2025-05-08 17:37:51 -07:00
|
|
|
&& match self.piece.color {
|
2024-01-21 09:15:41 -08:00
|
|
|
Color::White => self.square == Square::A1,
|
|
|
|
Color::Black => self.square == Square::A8,
|
|
|
|
}
|
|
|
|
}
|
2023-12-26 09:19:38 -07:00
|
|
|
}
|
2023-12-28 19:47:40 -07:00
|
|
|
|
2025-05-19 14:18:31 -07:00
|
|
|
impl std::fmt::Display for PlacedPiece {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
2024-01-19 17:59:34 -08:00
|
|
|
write!(f, "{}{}", self.piece, self.square)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-19 18:08:41 -08:00
|
|
|
impl From<(&Square, &Piece)> for PlacedPiece {
|
|
|
|
fn from(value: (&Square, &Piece)) -> Self {
|
|
|
|
PlacedPiece::new(*value.1, *value.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-28 19:47:40 -07:00
|
|
|
#[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');
|
2023-12-28 19:47:40 -07:00
|
|
|
}
|
|
|
|
}
|