diff --git a/src/chess.rs b/src/chess.rs new file mode 100644 index 0000000..34c9fd7 --- /dev/null +++ b/src/chess.rs @@ -0,0 +1,244 @@ +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 + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index 73e0257..824c321 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,284 +1,2 @@ -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 { - 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 - ); - } -} +mod chess; +mod shogi; \ No newline at end of file diff --git a/src/shogi.rs b/src/shogi.rs new file mode 100644 index 0000000..fdbfabc --- /dev/null +++ b/src/shogi.rs @@ -0,0 +1,62 @@ +//! Shogi, the game of Generals + +const DEFENDING_KING: char = '王'; +const CHALLENGER_KING: char = '玉'; +const ROOK: char = '飛'; +const BISHOP: char = '角'; +const GOLD_GENERAL: char = '金'; +const SILVER_GENERAL: char = '銀'; +const KNIGHT: char = '桂'; +const LANCE: char = '香'; +const PAWN: char = '歩'; +const PROMOTED_ROOK: char = '竜'; +const PROMOTED_BISHOP: char = '馬'; +const PROMOTED_SILVER_GENERAL: char = '全'; +const PROMOTED_KNIGHT: char = '圭'; +const PROMOTED_LANCE: char = '仝'; +const PROMOTED_PAWN: char = '个'; + +const DRAGON: char = PROMOTED_ROOK; +const HORSE: char = PROMOTED_BISHOP; +const TOKIN: char = PROMOTED_PAWN; + +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)] +#[rustfmt::skip] +pub enum BoardPosition { + A1, A2, A3, A4, A5, A6, A7, A8, A9, + B1, B2, B3, B4, B5, B6, B7, B8, B9, + C1, C2, C3, C4, C5, C6, C7, C8, C9, + D1, D2, D3, D4, D5, D6, D7, D8, D9, + E1, E2, E3, E4, E5, E6, E7, E8, E9, + F1, F2, F3, F4, F5, F6, F7, F8, F9, + G1, G2, G3, G4, G5, G6, G7, G8, G9, + H1, H2, H3, H4, H5, H6, H7, H8, H9, + I1, I2, I3, I4, I5, I6, I7, I8, I9, +} + +/// For Shogi this designates the direction the pieces face: +/// 'Black +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum PieceColor { + Black, + White, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum PieceType { + King, + Rook, + Bishop, + GoldGeneral, + SilverGeneral, + Knight, + Lance, + Pawn, +} + +#[derive(Debug, PartialEq)] +pub struct Piece { + kind: PieceType, + color: PieceColor, + symbol: char, +} \ No newline at end of file