pub type CardIdx = u8;
pub const DECK_SIZE: usize = 52;
#[cfg_attr(test, derive(Debug, Hash, Eq, PartialEq))]
pub enum CardSuit {
Spades,
Hearts,
Clubs,
Diamonds,
}
impl CardSuit {
pub fn from_index(suit_idx: CardIdx) -> Self {
match suit_idx {
0 => CardSuit::Spades,
1 => CardSuit::Hearts,
2 => CardSuit::Clubs,
3 => CardSuit::Diamonds,
_ => {
let ok_suit_idx = suit_idx % 4;
CardSuit::from_index(ok_suit_idx)
}
}
}
}
impl std::fmt::Display for CardSuit {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CardSuit::Spades => write!(f, "Spades"),
CardSuit::Hearts => write!(f, "Hearts"),
CardSuit::Clubs => write!(f, "Clubs"),
CardSuit::Diamonds => write!(f, "Diamonds"),
}
}
}
#[cfg_attr(test, derive(Hash, Eq, PartialEq))]
pub struct Card {
pub rank: u8,
pub suit: CardSuit,
}
impl Card {
pub fn from_index(card_idx: CardIdx) -> Self {
if card_idx >= (DECK_SIZE as u8) {
let ok_card_idx = card_idx % (DECK_SIZE as u8);
return Card::from_index(ok_card_idx);
}
let rank = card_idx / 4 + 1; let suit_idx = card_idx % 4;
Card {
rank,
suit: CardSuit::from_index(suit_idx),
}
}
pub fn rank_to_str(&self) -> &str {
match self.rank {
1 => "A",
2 => "2",
3 => "3",
4 => "4",
5 => "5",
6 => "6",
7 => "7",
8 => "8",
9 => "9",
10 => "10",
11 => "J",
12 => "Q",
13 => "K",
_ => "", }
}
pub fn print_ascii_art(cards: &[Self]) -> String {
let mut ascii_arts: Vec<String> = vec![String::new(); 6];
for card in cards.iter() {
ascii_arts[0].push_str(" .------.");
ascii_arts[1].push_str(
format!(
" |{}--. |",
format!("{:<2}", card.rank_to_str()).replace(" ", ".")
)
.as_str(),
);
ascii_arts[2].push_str(match card.suit {
CardSuit::Spades => " | :/\\: |", CardSuit::Hearts => " | (\\/) |", CardSuit::Clubs => " | :(): |", CardSuit::Diamonds => " | :/\\: |", });
ascii_arts[3].push_str(match card.suit {
CardSuit::Spades => " | (__) |", CardSuit::Hearts => " | :\\/: |", CardSuit::Clubs => " | ()() |", CardSuit::Diamonds => " | :\\/: |", });
ascii_arts[4].push_str(
format!(
" | '--{}|",
format!("{:>2}", card.rank_to_str()).replace(" ", "'")
)
.as_str(),
);
ascii_arts[5].push_str(" `------'");
}
let all_ascii_ars = ascii_arts.join("\n");
println!("{}", all_ascii_ars);
all_ascii_ars
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_card_index_creation() {
let card = Card::from_index(0);
assert_eq!(card.rank, 1);
assert_eq!(card.suit, CardSuit::Spades);
let card = Card::from_index(1);
assert_eq!(card.rank, 1);
assert_eq!(card.suit, CardSuit::Hearts);
let card = Card::from_index(2);
assert_eq!(card.rank, 1);
assert_eq!(card.suit, CardSuit::Clubs);
let card = Card::from_index(3);
assert_eq!(card.rank, 1);
assert_eq!(card.suit, CardSuit::Diamonds);
let card = Card::from_index(10);
assert_eq!(card.rank, 3);
assert_eq!(card.suit, CardSuit::Clubs);
let card = Card::from_index(52);
assert_eq!(card.rank, 1);
assert_eq!(card.suit, CardSuit::Spades);
let card = Card::from_index(53);
assert_eq!(card.rank, 1);
assert_eq!(card.suit, CardSuit::Hearts);
}
#[test]
fn test_ascii_art() {
let cards = vec![
Card::from_index(0), Card::from_index(1), Card::from_index(2), Card::from_index(3), ];
Card::print_ascii_art(&cards);
assert_eq!(
Card::print_ascii_art(&cards),
r#" .------. .------. .------. .------.
|A.--. | |A.--. | |A.--. | |A.--. |
| :/\: | | (\/) | | :(): | | :/\: |
| (__) | | :\/: | | ()() | | :\/: |
| '--'A| | '--'A| | '--'A| | '--'A|
`------' `------' `------' `------'"#
.to_string()
)
}
}