casino 0.3.0

A casino built right into your terminal
Documentation
use rand::prelude::*;
use rand::rng;
use rand::seq::SliceRandom;
use serde::{Deserialize, Serialize};
use std::fmt;

#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum Suit {
    Clubs,
    Diamonds,
    Hearts,
    Spades,
}

#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum Rank {
    Ace,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Jack,
    Queen,
    King,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Card {
    pub suit: Suit,
    pub rank: Rank,
}

impl fmt::Display for Card {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let symbol = match (&self.rank, &self.suit) {
            (Rank::Ace, Suit::Spades) => "🂡",
            (Rank::Two, Suit::Spades) => "🂢",
            (Rank::Three, Suit::Spades) => "🂣",
            (Rank::Four, Suit::Spades) => "🂤",
            (Rank::Five, Suit::Spades) => "🂥",
            (Rank::Six, Suit::Spades) => "🂦",
            (Rank::Seven, Suit::Spades) => "🂧",
            (Rank::Eight, Suit::Spades) => "🂨",
            (Rank::Nine, Suit::Spades) => "🂩",
            (Rank::Ten, Suit::Spades) => "🂪",
            (Rank::Jack, Suit::Spades) => "🂫",
            (Rank::Queen, Suit::Spades) => "🂭",
            (Rank::King, Suit::Spades) => "🂮",
            (Rank::Ace, Suit::Hearts) => "🂱",
            (Rank::Two, Suit::Hearts) => "🂲",
            (Rank::Three, Suit::Hearts) => "🂳",
            (Rank::Four, Suit::Hearts) => "🂴",
            (Rank::Five, Suit::Hearts) => "🂵",
            (Rank::Six, Suit::Hearts) => "🂶",
            (Rank::Seven, Suit::Hearts) => "🂷",
            (Rank::Eight, Suit::Hearts) => "🂸",
            (Rank::Nine, Suit::Hearts) => "🂹",
            (Rank::Ten, Suit::Hearts) => "🂺",
            (Rank::Jack, Suit::Hearts) => "🂻",
            (Rank::Queen, Suit::Hearts) => "🂽",
            (Rank::King, Suit::Hearts) => "🂾",
            (Rank::Ace, Suit::Diamonds) => "🃁",
            (Rank::Two, Suit::Diamonds) => "🃂",
            (Rank::Three, Suit::Diamonds) => "🃃",
            (Rank::Four, Suit::Diamonds) => "🃄",
            (Rank::Five, Suit::Diamonds) => "🃅",
            (Rank::Six, Suit::Diamonds) => "🃆",
            (Rank::Seven, Suit::Diamonds) => "🃇",
            (Rank::Eight, Suit::Diamonds) => "🃈",
            (Rank::Nine, Suit::Diamonds) => "🃉",
            (Rank::Ten, Suit::Diamonds) => "🃊",
            (Rank::Jack, Suit::Diamonds) => "🃋",
            (Rank::Queen, Suit::Diamonds) => "🃍",
            (Rank::King, Suit::Diamonds) => "🃎",
            (Rank::Ace, Suit::Clubs) => "🃑",
            (Rank::Two, Suit::Clubs) => "🃒",
            (Rank::Three, Suit::Clubs) => "🃓",
            (Rank::Four, Suit::Clubs) => "🃔",
            (Rank::Five, Suit::Clubs) => "🃕",
            (Rank::Six, Suit::Clubs) => "🃖",
            (Rank::Seven, Suit::Clubs) => "🃗",
            (Rank::Eight, Suit::Clubs) => "🃘",
            (Rank::Nine, Suit::Clubs) => "🃙",
            (Rank::Ten, Suit::Clubs) => "🃚",
            (Rank::Jack, Suit::Clubs) => "🃛",
            (Rank::Queen, Suit::Clubs) => "🃝",
            (Rank::King, Suit::Clubs) => "🃞",
        };

        write!(f, "{symbol} ")
    }
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Shoe {
    deck_count: u8,
    reshuffle_threshold: f32,
    cards: Vec<Card>,
}

impl Shoe {
    pub fn new(deck_count: u8, reshuffle_threshold: f32) -> Self {
        Self {
            deck_count,
            reshuffle_threshold,
            cards: Self::build_cards(deck_count),
        }
    }

    pub fn draw_card(&mut self) -> Card {
        if self.cards.len()
            < ((self.deck_count as usize * 52) as f32 * self.reshuffle_threshold) as usize
        {
            self.cards = Self::build_cards(self.deck_count);
        }

        self.cards.pop().unwrap()
    }

    pub fn shuffle(&mut self) {
        self.cards = Self::build_cards(self.deck_count);
    }

    fn build_cards(deck_count: u8) -> Vec<Card> {
        let deck = deck();

        let mut shoe = vec![];

        for _i in 1..deck_count {
            let mut next_deck = deck.clone();
            shoe.append(&mut next_deck);
        }

        let mut rng = rng();
        shoe.shuffle(&mut rng);

        shoe
    }
}

pub fn deck() -> Vec<Card> {
    let suits = [Suit::Clubs, Suit::Diamonds, Suit::Hearts, Suit::Spades];
    let ranks = [
        Rank::Ace,
        Rank::Two,
        Rank::Three,
        Rank::Four,
        Rank::Five,
        Rank::Six,
        Rank::Seven,
        Rank::Eight,
        Rank::Nine,
        Rank::Ten,
        Rank::Jack,
        Rank::Queen,
        Rank::King,
    ];

    let mut cards = vec![];

    for suit in suits {
        for rank in &ranks {
            let card = Card {
                suit: suit.clone(),
                rank: rank.clone(),
            };

            cards.push(card);
        }
    }

    let mut rng = rng();
    cards.shuffle(&mut rng);

    cards
}

pub fn random_card() -> Card {
    let suits = [Suit::Clubs, Suit::Diamonds, Suit::Hearts, Suit::Spades];
    let ranks = [
        Rank::Ace,
        Rank::Two,
        Rank::Three,
        Rank::Four,
        Rank::Five,
        Rank::Six,
        Rank::Seven,
        Rank::Eight,
        Rank::Nine,
        Rank::Ten,
        Rank::Jack,
        Rank::Queen,
        Rank::King,
    ];

    let mut rng = rng();
    let suit = suits.choose(&mut rng).unwrap().clone();
    let rank = ranks.choose(&mut rng).unwrap().clone();

    Card { suit, rank }
}