use maxim::prelude::*;
use rand::{thread_rng, Rng};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Copy, Clone)]
struct Game {
funds: i64,
wager: u32,
total_rounds: u32,
}
impl Game {
fn roll_dice() -> bool {
let mut rng = thread_rng();
match rng.gen_range(0, 101) {
x if x > 51 => true,
_ => false,
}
}
async fn play(mut self, ctx: Context, msg: Message) -> ActorResult<Self> {
if let Some(results_aid) = msg.content_as::<Aid>() {
let mut current_round = 1;
let mut results_vec = Vec::new();
while current_round <= self.total_rounds {
current_round += 1;
match Game::roll_dice() {
true => self.funds += self.wager as i64,
false => self.funds -= self.wager as i64,
}
results_vec.push(self.funds);
}
results_aid
.send_new(GameMsg::new(ctx.aid.clone(), results_vec))
.unwrap();
return Ok(Status::stop(self));
}
Ok(Status::done(self))
}
}
impl Default for Game {
fn default() -> Self {
Self {
funds: 10_000,
wager: 100,
total_rounds: 100,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
struct GameMsg {
aid: Aid,
results_vec: Vec<i64>,
}
impl GameMsg {
fn new(aid: Aid, vec: Vec<i64>) -> Self {
Self {
aid,
results_vec: vec,
}
}
}
#[derive(Debug)]
struct GameManager {
games_finished: u32,
total_games: u32,
results: HashMap<Aid, Vec<i64>>,
}
impl GameManager {
fn new(total_games: u32) -> Self {
Self {
games_finished: 0,
total_games,
results: HashMap::new(),
}
}
}
impl GameManager {
async fn gather_results(mut self, ctx: Context, msg: Message) -> ActorResult<Self> {
if let Some(game_msg) = msg.content_as::<GameMsg>() {
self.results
.insert(game_msg.aid.clone(), game_msg.results_vec.clone());
}
if let Some(sys_msg) = msg.content_as::<SystemMsg>() {
match &*sys_msg {
SystemMsg::Start => {
let game_conditions = Game::default();
println!("Starting funds: ${}", game_conditions.funds);
println!("Wager per round: ${}", game_conditions.wager);
println!("Rounds per game: {}", game_conditions.total_rounds);
println!("Running simulations...");
for i in 0..self.total_games {
let name = format!("Game{}", i);
let aid = ctx
.system
.spawn()
.name(&name)
.with(game_conditions, Game::play)
.unwrap();
ctx.system.monitor(&ctx.aid, &aid);
aid.send_new(ctx.aid.clone()).unwrap();
}
}
SystemMsg::Stopped { .. } => {
self.games_finished += 1;
if self.games_finished == self.total_games {
let average_funds = self
.results
.values()
.map(|v| v.last().unwrap())
.sum::<i64>()
/ self.total_games as i64;
println!("Simulations ran: {}", self.results.len());
println!("Final average funds: ${}", average_funds);
ctx.system.trigger_shutdown();
}
}
_ => {}
}
}
Ok(Status::done(self))
}
}
const NUM_GAMES: u32 = 100;
fn main() {
let config = ActorSystemConfig::default().message_channel_size(210);
let system = ActorSystem::create(config);
system
.spawn()
.name("Manager")
.with(GameManager::new(NUM_GAMES), GameManager::gather_results)
.unwrap();
system.await_shutdown(None);
}