use std::collections::HashSet; const WHITE_PAWN: char = '♙'; const WHITE_KNIGHT: char = '♘'; const WHITE_BISHOP: char = '♗'; const WHITE_ROOK: char = '♖'; const WHITE_QUEEN: char = '♕'; const WHITE_KING: char = '♔'; const BLACK_PAWN: char = '♟'; const BLACK_KNIGHT: char = '♞'; const BLACK_BISHOP: char = '♝'; const BLACK_ROOK: char = '♜'; const BLACK_QUEEN: char = '♛'; const BLACK_KING: char = '♚'; #[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] #[rustfmt::skip] pub enum BoardPosition { A1, A2, A3, A4, A5, A6, A7, A8, B1, B2, B3, B4, B5, B6, B7, B8, C1, C2, C3, C4, C5, C6, C7, C8, D1, D2, D3, D4, D5, D6, D7, D8, E1, E2, E3, E4, E5, E6, E7, E8, F1, F2, F3, F4, F5, F6, F7, F8, G1, G2, G3, G4, G5, G6, G7, G8, H1, H2, H3, H4, H5, H6, H7, H8, } impl From for usize { #[rustfmt::skip] fn from(square: BoardPosition) -> Self { use BoardPosition::*; match square { A1 => 0, A2 => 1, A3 => 2, A4 => 3, A5 => 4, A6 => 5, A7 => 6, A8 => 7, B1 => 8, B2 => 9, B3 => 10, B4 => 11, B5 => 12, B6 => 13, B7 => 14, B8 => 15, C1 => 16, C2 => 17, C3 => 18, C4 => 19, C5 => 20, C6 => 21, C7 => 22, C8 => 23, D1 => 24, D2 => 25, D3 => 26, D4 => 27, D5 => 28, D6 => 29, D7 => 30, D8 => 31, E1 => 32, E2 => 33, E3 => 34, E4 => 35, E5 => 36, E6 => 37, E7 => 38, E8 => 39, F1 => 40, F2 => 41, F3 => 42, F4 => 43, F5 => 44, F6 => 45, F7 => 46, F8 => 47, G1 => 48, G2 => 49, G3 => 50, G4 => 51, G5 => 52, G6 => 53, G7 => 54, G8 => 55, H1 => 56, H2 => 57, H3 => 58, H4 => 59, H5 => 60, H6 => 61, H7 => 62, H8 => 63, } } } #[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)] pub enum MoveAmount { One, Two, Many, } #[derive(Debug, Clone, PartialEq, Hash, Eq)] pub enum MoveType { Vertical(MoveAmount), Horizontal(MoveAmount), Diagonal(MoveAmount), Knight, KingSideCastle, QueenSideCastle, EnPassant, Promoted(PieceType), } #[derive(Debug, Copy, Clone, PartialEq)] pub enum PieceColor { Black, White, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] /// Which set of squares can this bishop use? pub enum BishopType { /// Only dark/black squares Dark, /// Only light/red squares Light, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum PieceType { Pawn(Option>), Rook, Knight, King, Queen, Bishop(BishopType), } #[derive(Debug, PartialEq)] pub struct Piece { kind: PieceType, color: PieceColor, symbol: char, } impl Piece { pub fn new(color: PieceColor, kind: PieceType) -> Self { Self { kind: kind.clone(), color, symbol: Self::get_symbol(color, kind), } } pub fn get_symbol(color: PieceColor, kind: PieceType) -> char { use PieceColor::*; use PieceType::*; match (color, kind) { // Treat promoted pawns as their promoted type (c, Pawn(Some(k))) => Self::get_symbol(c, *k), (White, Pawn(None)) => WHITE_PAWN, (White, Knight) => WHITE_KNIGHT, (White, Bishop(_)) => WHITE_BISHOP, (White, Rook) => WHITE_ROOK, (White, Queen) => WHITE_QUEEN, (White, King) => WHITE_KING, (Black, Pawn(None)) => BLACK_PAWN, (Black, Knight) => BLACK_KNIGHT, (Black, Bishop(_)) => BLACK_BISHOP, (Black, Rook) => BLACK_ROOK, (Black, Queen) => BLACK_QUEEN, (Black, King) => BLACK_KING, } } pub fn valid_move_types(kind: PieceType) -> HashSet { use MoveAmount::*; use PieceType::*; match kind { Pawn(Some(k)) => Self::valid_move_types(*k), Pawn(None) => HashSet::from([ MoveType::Diagonal(One), MoveType::Vertical(One), MoveType::Vertical(Two), MoveType::EnPassant, ]), Knight => HashSet::from([MoveType::Knight]), Bishop(_) => HashSet::from([MoveType::Diagonal(Many)]), Rook => HashSet::from([ MoveType::Horizontal(Many), MoveType::Vertical(Many), MoveType::KingSideCastle, MoveType::QueenSideCastle, ]), Queen => HashSet::from([ MoveType::Horizontal(Many), MoveType::Vertical(Many), MoveType::Diagonal(Many), ]), King => HashSet::from([ MoveType::Horizontal(One), MoveType::Vertical(One), MoveType::Diagonal(One), MoveType::KingSideCastle, MoveType::QueenSideCastle, ]), } } } trait PieceBehavior { fn get_valid_move_types() -> HashSet; fn get_symbol(&self) -> char; } pub struct Pawn { color: PieceColor, has_moved: bool, } pub struct Knight { color: PieceColor, } pub struct Bishop { color: PieceColor, } pub struct Rook { color: PieceColor, has_moved: bool, } pub struct Queen { color: PieceColor, } pub struct King { color: PieceColor, has_moved: bool, } #[cfg(test)] mod test { use super::*; #[test] fn test_make_black_rook() { let piece = Piece::new(PieceColor::Black, PieceType::Rook); assert_eq!(piece.symbol, BLACK_ROOK); assert_eq!(piece.kind, PieceType::Rook); assert_eq!(piece.color, PieceColor::Black); } #[test] fn test_get_white_knight_char() { assert_eq!( Piece::get_symbol(PieceColor::White, PieceType::Knight), WHITE_KNIGHT ); } #[test] fn test_get_promoted_white_pawn_queen() { assert_eq!( Piece::get_symbol( PieceColor::White, PieceType::Pawn(Some(Box::new(PieceType::Queen))) ), WHITE_QUEEN ); } }