casino 0.3.0

A casino built right into your terminal
Documentation
use std::{
    fs::{self, write},
    path::Path,
};

use crate::{baccarat::BaccaratBet, money::Money};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use tabled::Tabled;

#[derive(Copy, Clone, Default, Deserialize, Serialize, Tabled)]
pub struct Statistics {
    #[serde(default)]
    pub biggest_bankroll: Money,
    #[serde(default)]
    pub times_bankrupted: u32,
    #[serde(default)]
    #[tabled(skip)]
    pub blackjack: BlackjackStatistics,
    #[serde(default)]
    #[tabled(skip)]
    pub roulette: RouletteStatistics,
    #[serde(default)]
    #[tabled(skip)]
    pub slots: SlotMachineStatistics,
    #[serde(default)]
    #[tabled(skip)]
    pub baccarat: BaccaratStatistics,
}

impl Statistics {
    pub fn init(stats_path: &Path) -> Result<()> {
        if !stats_path.try_exists()? {
            let stats = Self::default();
            stats.save(stats_path)?;
        }
        Ok(())
    }

    pub fn load(stats_path: &Path) -> Result<Self> {
        let stats_string = fs::read_to_string(stats_path)?;

        let stats = toml::from_str(&stats_string)?;

        Ok(stats)
    }

    pub fn save(&self, stats_path: &Path) -> Result<()> {
        fs::create_dir_all(stats_path.parent().unwrap()).expect("Couldn't create stats directory!");
        write(stats_path, toml::to_string(&self)?)?;
        Ok(())
    }

    pub fn update_bankroll(&mut self, amount: Money) {
        if amount > self.biggest_bankroll {
            self.biggest_bankroll = amount;
        } else if amount.is_zero() {
            self.times_bankrupted += 1;
        }
    }
}

#[derive(Copy, Clone, Default, Deserialize, Serialize, Tabled)]
#[tabled(rename_all = "Upper Title Case")]
pub struct SlotMachineStatistics {
    pub total_pulls: u32,
    pub money_won: Money,
    pub money_spent: Money,
    pub biggest_jackpot: Money,
}

impl SlotMachineStatistics {
    pub fn record_pull(&mut self, amount: Money) {
        self.total_pulls += 1;
        self.money_spent += amount;
    }

    pub fn record_win(&mut self, amount: Money) {
        self.money_won += amount;
        if self.biggest_jackpot < amount {
            self.biggest_jackpot = amount;
        }
    }
}

#[derive(Copy, Clone, Default, Deserialize, Serialize, Tabled)]
#[tabled(rename_all = "Upper Title Case")]
pub struct RouletteStatistics {
    pub spins_won: u32,
    pub spins_lost: u32,
    pub money_won: Money,
    pub money_lost: Money,
    pub biggest_win: Money,
    pub biggest_loss: Money,
}

impl RouletteStatistics {
    pub fn record_win(&mut self, amount: Money) {
        self.spins_won += 1;
        self.money_won += amount;
        if amount > self.biggest_win {
            self.biggest_win = amount;
        }
    }

    pub fn record_loss(&mut self, amount: Money) {
        self.spins_lost += 1;
        self.money_lost += amount;
        if amount > self.biggest_loss {
            self.biggest_loss = amount;
        }
    }
}

#[derive(Copy, Clone, Default, Deserialize, Serialize, Tabled)]
#[tabled(rename_all = "Upper Title Case")]
pub struct BlackjackStatistics {
    pub hands_won: u32,
    pub hands_lost: u32,
    pub hands_push: u32,
    pub money_won: Money,
    pub money_lost: Money,
    pub biggest_win: Money,
    pub biggest_loss: Money,
}

impl BlackjackStatistics {
    pub fn record_win(&mut self, amount: Money) {
        self.hands_won += 1;
        self.money_won += amount;
        if amount > self.biggest_win {
            self.biggest_win = amount;
        }
    }

    pub fn record_loss(&mut self, amount: Money) {
        self.hands_lost += 1;
        self.money_lost += amount;
        if amount > self.biggest_loss {
            self.biggest_loss = amount;
        }
    }

    pub fn record_push(&mut self) {
        self.hands_push += 1;
    }
}

#[derive(Copy, Clone, Default, Deserialize, Serialize, Tabled)]
#[tabled(rename_all = "Upper Title Case")]
pub struct BaccaratStatistics {
    pub hands_won: u32,
    pub hands_lost: u32,
    pub hands_tied: u32,
    pub player_bets: u32,
    pub banker_bets: u32,
    pub tie_bets: u32,
    pub money_won: Money,
    pub money_lost: Money,
    pub biggest_win: Money,
    pub biggest_loss: Money,
}

impl BaccaratStatistics {
    pub fn record_win(&mut self, bet_type: &BaccaratBet, bet_amount: Money) {
        self.hands_won += 1;
        match bet_type {
            BaccaratBet::Player => self.player_bets += 1,
            BaccaratBet::Banker => self.banker_bets += 1,
            BaccaratBet::Tie => self.tie_bets += 1,
        }
        self.money_won += bet_amount;
        if bet_amount > self.biggest_win {
            self.biggest_win = bet_amount;
        }
    }

    pub fn record_tie(&mut self, bet_type: &BaccaratBet) {
        self.hands_tied += 1;
        match bet_type {
            BaccaratBet::Player => self.player_bets += 1,
            BaccaratBet::Banker => self.banker_bets += 1,
            BaccaratBet::Tie => self.tie_bets += 1,
        }
    }

    pub fn record_loss(&mut self, bet_type: &BaccaratBet, bet_amount: Money) {
        self.hands_lost += 1;
        match bet_type {
            BaccaratBet::Player => self.player_bets += 1,
            BaccaratBet::Banker => self.banker_bets += 1,
            BaccaratBet::Tie => self.tie_bets += 1,
        }
        self.money_lost += bet_amount;
        if bet_amount > self.biggest_loss {
            self.biggest_loss = bet_amount;
        }
    }
}