#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Card(u8); impl Card { // Constants for suits pub const SPADES: u8 = 0; pub const HEARTS: u8 = 1; pub const DIAMONDS: u8 = 2; pub const CLUBS: u8 = 3; // Constants for ranks pub const TWO: u8 = 2; pub const THREE: u8 = 3; pub const FOUR: u8 = 4; pub const FIVE: u8 = 5; pub const SIX: u8 = 6; pub const SEVEN: u8 = 7; pub const EIGHT: u8 = 8; pub const NINE: u8 = 9; pub const TEN: u8 = 10; pub const JACK: u8 = 11; pub const QUEEN: u8 = 12; pub const KING: u8 = 13; pub const ACE: u8 = 14; // Special constants pub const BAD_CARD: u8 = 255; pub const NUM_SUITS: u8 = 4; pub const NUM_RANKS: u8 = 13; pub const NUM_CARDS: u8 = 52; // Constructor for an empty/invalid card pub fn new() -> Self { Self(Self::BAD_CARD) } // Constructor from rank and suit pub fn from_rank_suit(rank: u8, suit: u8) -> Self { assert!(rank >= Self::TWO && rank <= Self::ACE, "Invalid rank"); assert!(suit < Self::NUM_SUITS, "Invalid suit"); Self((suit << 4) | (rank & 0xF)) } // Constructor from index (0..51) pub fn from_index(index: u8) -> Self { assert!(index < Self::NUM_CARDS, "Invalid index"); let rank = (index % Self::NUM_RANKS) + Self::TWO; let suit = index / Self::NUM_RANKS; Self::from_rank_suit(rank, suit) } // Constructor from string (e.g., "As" for Ace of Spades) pub fn from_string(s: &str) -> Self { assert!(s.len() == 2, "Invalid card string"); let rank_char = s.chars().nth(0).unwrap(); let suit_char = s.chars().nth(1).unwrap(); let rank = Self::rank_from_char(rank_char); let suit = Self::suit_from_char(suit_char); Self::from_rank_suit(rank, suit) } // Get the rank of the card pub fn rank(&self) -> u8 { self.0 & 0xF } // Get the suit of the card pub fn suit(&self) -> u8 { (self.0 >> 4) & 0x3 } // Get the index of the card (0..51) pub fn index(&self) -> u8 { (self.suit() * Self::NUM_RANKS) + (self.rank() - Self::TWO) } // Check if the card is valid pub fn is_valid(&self) -> bool { self.0 != Self::BAD_CARD } // Convert rank to character (e.g., 14 -> 'A') pub fn rank_to_char(rank: u8) -> char { match rank { Self::TWO => '2', Self::THREE => '3', Self::FOUR => '4', Self::FIVE => '5', Self::SIX => '6', Self::SEVEN => '7', Self::EIGHT => '8', Self::NINE => '9', Self::TEN => 'T', Self::JACK => 'J', Self::QUEEN => 'Q', Self::KING => 'K', Self::ACE => 'A', _ => panic!("Invalid rank"), } } // Convert suit to character (e.g., 0 -> 's') pub fn suit_to_char(suit: u8) -> char { match suit { Self::SPADES => 's', Self::HEARTS => 'h', Self::DIAMONDS => 'd', Self::CLUBS => 'c', _ => panic!("Invalid suit"), } } // Convert rank character to rank (e.g., 'A' -> 14) pub fn rank_from_char(rank_char: char) -> u8 { match rank_char { '2' => Self::TWO, '3' => Self::THREE, '4' => Self::FOUR, '5' => Self::FIVE, '6' => Self::SIX, '7' => Self::SEVEN, '8' => Self::EIGHT, '9' => Self::NINE, 'T' => Self::TEN, 'J' => Self::JACK, 'Q' => Self::QUEEN, 'K' => Self::KING, 'A' => Self::ACE, _ => panic!("Invalid rank character"), } } // Convert suit character to suit (e.g., 's' -> 0) pub fn suit_from_char(suit_char: char) -> u8 { match suit_char { 's' => Self::SPADES, 'h' => Self::HEARTS, 'd' => Self::DIAMONDS, 'c' => Self::CLUBS, _ => panic!("Invalid suit character"), } } } impl std::fmt::Display for Card { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if !self.is_valid() { write!(f, "Invalid Card") } else { let rank_char = Self::rank_to_char(self.rank()); let suit_char = Self::suit_to_char(self.suit()); write!(f, "{}{}", rank_char, suit_char) } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_card_creation() { let card = Card::from_rank_suit(Card::ACE, Card::SPADES); assert_eq!(card.rank(), Card::ACE); assert_eq!(card.suit(), Card::SPADES); assert_eq!(card.index(), 12); // Ace of Spades is index 12 assert!(card.is_valid()); } #[test] fn test_card_from_string() { let card = Card::from_string("As"); assert_eq!(card.rank(), Card::ACE); assert_eq!(card.suit(), Card::SPADES); assert_eq!(card.to_string(), "As"); } #[test] fn test_card_from_index() { let card = Card::from_index(0); assert_eq!(card.rank(), Card::TWO); assert_eq!(card.suit(), Card::SPADES); assert_eq!(card.to_string(), "2s"); } #[test] fn test_invalid_card() { let card = Card::new(); assert!(!card.is_valid()); assert_eq!(card.to_string(), "Invalid Card"); } }