Skip to content

Commit

Permalink
Implements first-pass of simulating games, not parallelized
Browse files Browse the repository at this point in the history
  • Loading branch information
schuylermartin45 committed Apr 28, 2024
1 parent 5fbec97 commit bdaefd0
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 4 deletions.
15 changes: 11 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::types::hand::{
Hand, Outcome, Strategy, DEALER_INFINITE_CREDITS, DEFAULT_BET_VALUE, HUMAN_DEFAULT_CREDITS,
NO_BET_VALUE,
};
use crate::types::stats::RunStats;

pub mod data;
pub mod types;
Expand Down Expand Up @@ -105,7 +106,7 @@ fn reset_game(player: &mut Hand, dealer: &mut Hand) -> Deck {
/// This simulates a single "session" of a player sitting down to play a game.
/// TODO: Add Monte Carlo and other betting strats
/// TODO: Add support for a physical game by re-using the Deck to some degree.
fn run_automated_match(max_games: usize) {
fn run_automated_match(max_games: usize) -> RunStats {
let mut deck = Deck::new();
let mut dealer = Hand::new("Dealer", Strategy::Dealer, DEALER_INFINITE_CREDITS);
let mut player = Hand::new(
Expand All @@ -114,6 +115,8 @@ fn run_automated_match(max_games: usize) {
HUMAN_DEFAULT_CREDITS,
);

let mut stats = RunStats::new();

for _ in 0..max_games {
init_game(&mut player, &mut dealer, &mut deck);

Expand All @@ -138,7 +141,8 @@ fn run_automated_match(max_games: usize) {
}
}

match Hand::determine_outcome(&player, &dealer) {
let match_outcome = Hand::determine_outcome(&player, &dealer);
match match_outcome {
Outcome::Win => {
player.add_credits(final_bet * 2);
}
Expand All @@ -147,6 +151,7 @@ fn run_automated_match(max_games: usize) {
player.add_credits(final_bet);
}
}
stats.record_match_end(match_outcome);

// Broke players can't play
if player.get_credits() <= 0 {
Expand All @@ -156,7 +161,9 @@ fn run_automated_match(max_games: usize) {
// According to the internet, digital Blackjack machines reset the deck every game instance.
deck = reset_game(&mut player, &mut dealer);
}
// TODO return some final stats

stats.record_credits(player.get_credits());
stats
}

/// Runs a single player text-based game or runs a parallelized simulation.
Expand All @@ -166,7 +173,7 @@ fn main() {
if args.runs > 0 {
// TODO run n simulations in parallel.
for _ in 0..args.runs {
run_automated_match(DEFAULT_MAX_GAMES_PER_RUN);
println!("{}", run_automated_match(DEFAULT_MAX_GAMES_PER_RUN));
}
process::exit(0);
}
Expand Down
1 change: 1 addition & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod card;
pub mod deck;
pub mod hand;
pub mod stats;
56 changes: 56 additions & 0 deletions src/types/stats.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//!
//! File: stats.rs
//! Description: Data structures for gathering statistics
//!
//!
//!
use std::fmt;

use crate::types::hand::Outcome;

/// Data to track per player "run" (how long a player sits at the table)
pub struct RunStats {
num_games: usize,
wins: usize,
losses: usize,
pushes: usize,
remaining_credits: isize,
}

impl RunStats {
pub fn new() -> Self {
RunStats {
num_games: 0,
wins: 0,
losses: 0,
pushes: 0,
remaining_credits: 0,
}
}

/// Records stats when a game (single match) ends
pub fn record_match_end(&mut self, outcome: Outcome) {
self.num_games += 1;
match outcome {
Outcome::Win => self.wins += 1,
Outcome::Loss => self.losses += 1,
Outcome::Push => self.pushes += 1,
}
}

/// Record the final credit count
pub fn record_credits(&mut self, credits: isize) {
self.remaining_credits = credits;
}
}

impl fmt::Display for RunStats {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Games: {} | W/L/P: {}/{}/{} | Credits: ${}",
self.num_games, self.wins, self.losses, self.pushes, self.remaining_credits
)
}
}

0 comments on commit bdaefd0

Please sign in to comment.