use rand::seq::SliceRandom;
use rand::thread_rng;
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Suit {
Spades,
Hearts,
Diamonds,
Clubs,
}
impl Suit {
pub fn symbol(&self) -> &'static str {
match self {
Suit::Spades => "♠",
Suit::Hearts => "♥",
Suit::Diamonds => "♦",
Suit::Clubs => "♣",
}
}
pub fn is_red(&self) -> bool {
matches!(self, Suit::Hearts | Suit::Diamonds)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum Rank {
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
Nine = 9,
Ten = 10,
Jack = 11,
Queen = 12,
King = 13,
Ace = 14,
}
impl Rank {
pub fn symbol(&self) -> &'static str {
match self {
Rank::Two => "2",
Rank::Three => "3",
Rank::Four => "4",
Rank::Five => "5",
Rank::Six => "6",
Rank::Seven => "7",
Rank::Eight => "8",
Rank::Nine => "9",
Rank::Ten => "10",
Rank::Jack => "J",
Rank::Queen => "Q",
Rank::King => "K",
Rank::Ace => "A",
}
}
pub const ALL: [Rank; 13] = [
Rank::Two,
Rank::Three,
Rank::Four,
Rank::Five,
Rank::Six,
Rank::Seven,
Rank::Eight,
Rank::Nine,
Rank::Ten,
Rank::Jack,
Rank::Queen,
Rank::King,
Rank::Ace,
];
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Card {
pub rank: Rank,
pub suit: Suit,
}
impl Card {
pub fn new(rank: Rank, suit: Suit) -> Self {
Self { rank, suit }
}
}
impl fmt::Display for Card {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}{}", self.rank.symbol(), self.suit.symbol())
}
}
#[derive(Debug, Clone)]
pub struct Deck {
cards: Vec<Card>,
index: usize,
}
impl Deck {
pub fn new() -> Self {
let mut cards = Vec::with_capacity(52);
for suit in [Suit::Spades, Suit::Hearts, Suit::Diamonds, Suit::Clubs] {
for rank in Rank::ALL {
cards.push(Card::new(rank, suit));
}
}
Self { cards, index: 0 }
}
pub fn shuffle(&mut self) {
let mut rng = thread_rng();
self.cards.shuffle(&mut rng);
self.index = 0;
}
pub fn deal(&mut self) -> Option<Card> {
if self.index < self.cards.len() {
let card = self.cards[self.index];
self.index += 1;
Some(card)
} else {
None
}
}
pub fn deal_n(&mut self, n: usize) -> Vec<Card> {
(0..n).filter_map(|_| self.deal()).collect()
}
}
impl Default for Deck {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deck_has_52_cards() {
let mut deck = Deck::new();
let cards: Vec<_> = (0..52).filter_map(|_| deck.deal()).collect();
assert_eq!(cards.len(), 52);
assert!(deck.deal().is_none());
}
#[test]
fn test_shuffle_resets_index() {
let mut deck = Deck::new();
deck.deal();
deck.deal();
deck.shuffle();
let cards: Vec<_> = (0..52).filter_map(|_| deck.deal()).collect();
assert_eq!(cards.len(), 52);
}
}