mahjong_cli/simulate/
stats.rs1use chrono::Utc;
2use mahjong_core::{Game, PlayerId};
3use rustc_hash::FxHashMap;
4use std::ops::{Add, Div};
5
6fn average<T: Add<Output = T> + Div<Output = T> + Default + Copy + Into<f64>>(
7 numbers: &Vec<T>,
8) -> f64 {
9 let mut total: T = Default::default();
10 for numb in numbers {
11 total = total + *numb;
12 }
13 total.into() / numbers.len() as f64
14}
15
16pub struct Stats {
17 games_num: usize,
18 games_per_second: Vec<(f32, usize)>,
19 rounds_num: Vec<u32>,
20 start_time: chrono::NaiveTime,
21 top_scores: Vec<u32>,
22 winners: FxHashMap<PlayerId, u32>,
23}
24
25impl Stats {
26 pub fn new() -> Self {
27 Self {
28 games_num: 0,
29 games_per_second: vec![],
30 rounds_num: vec![],
31 start_time: Utc::now().time(),
32 top_scores: vec![],
33 winners: FxHashMap::default(),
34 }
35 }
36
37 pub fn complete_game(&mut self, game: &Game) {
38 let mut players = game.players.clone();
40
41 players.shuffle();
42
43 let winner = players.iter().max_by_key(|k| game.score.get(k).unwrap());
44
45 if let Some(winner) = winner {
46 *self.winners.entry(winner.clone()).or_insert(0) += 1;
47 }
48
49 self.games_num += 1;
50 self.rounds_num.push(game.round.round_index + 1);
51 let top_score = game.score.0.values().max().unwrap();
52 self.top_scores.push(*top_score);
53 }
54
55 pub fn print_if_interval(&mut self, seconds: usize) -> bool {
56 let end_time = Utc::now().time();
57 let diff = (end_time - self.start_time).num_seconds() as usize;
58
59 if diff > seconds {
60 let last_average = self.games_per_second.last().unwrap_or(&(0.0, 0));
61 let games_per_s = (self.games_num as f32 - last_average.1 as f32) / diff as f32;
62
63 self.games_per_second.push((games_per_s, self.games_num));
64 let top_score = *self.top_scores.iter().max().unwrap();
65
66 self.top_scores = vec![];
67
68 let gps = self
69 .games_per_second
70 .iter()
71 .map(|(games_per_s, _)| *games_per_s)
72 .collect::<Vec<f32>>();
73 let average_games_per_s = average(&gps);
74 let average_rounds_per_game = average(&self.rounds_num);
75
76 self.start_time = end_time;
77
78 println!("Winners: {:?}", self.winners);
79 println!("Number of games: {:?}", self.games_num);
80 println!("Average games per second: {:.2}", average_games_per_s);
81 println!("Average rounds per game: {:.2}", average_rounds_per_game);
82 println!("Top score in last batch: {:?}", top_score);
83 println!("---\n");
84 }
85
86 diff > seconds
87 }
88}