From 34c99c08665f9cc172e400ddad50e416f79e2043 Mon Sep 17 00:00:00 2001 From: konsumlamm Date: Fri, 12 Jan 2024 14:56:02 +0100 Subject: [PATCH] Track each user stat for marines, aliens and in total Track wins, score, hits, misses --- ns2-stat-cli/src/main.rs | 32 +++++++------ ns2-stat-cli/src/table.rs | 2 +- ns2-stat/src/lib.rs | 99 +++++++++++++++++++++++++++++---------- 3 files changed, 93 insertions(+), 40 deletions(-) diff --git a/ns2-stat-cli/src/main.rs b/ns2-stat-cli/src/main.rs index 12b6655..1b878ec 100644 --- a/ns2-stat-cli/src/main.rs +++ b/ns2-stat-cli/src/main.rs @@ -29,11 +29,12 @@ struct CliArgs { struct UserRow { name: String, - kills: u32, - assists: u32, - deaths: u32, kd: f32, kda: f32, + games: u32, + commander: u32, + avg_score: f32, + accuracy: f32, } struct MapRow { @@ -47,14 +48,15 @@ fn print_stats(stats: NS2Stats) { .users .into_iter() .filter_map(|(name, user)| { - if user.total_games > 2 { + if user.games.total > 2 { Some(UserRow { name, - kills: user.kills, - assists: user.assists, - deaths: user.deaths, - kd: user.kd(), - kda: user.kda(), + kd: user.kd().total, + kda: user.kda().total, + games: user.games.total, + commander: user.commander.total, + avg_score: user.average_score().total, + accuracy: user.accuracy().total, }) } else { None @@ -63,7 +65,7 @@ fn print_stats(stats: NS2Stats) { .collect::>(); users.sort_by_key(|user| -(user.kd * 100f32) as i32); table::print_table( - ["NAME", "KILLS", "ASSISTS", "DEATHS", "KD", "KDA"], + ["NAME", "KD", "KDA", "GAMES", "COMMANDER", "AVG SCORE", "ACCURACY"], [ Alignment::Left, Alignment::Right, @@ -71,16 +73,18 @@ fn print_stats(stats: NS2Stats) { Alignment::Right, Alignment::Right, Alignment::Right, + Alignment::Right, ], &users, |UserRow { name, - kills, - assists, - deaths, kd, kda, - }| row!["{name}", "{kills}", "{assists}", "{deaths}", "{kd:.2}", "{kda:.2}"], + games, + commander, + avg_score, + accuracy, + }| row!["{name}", "{kd:.2}", "{kda:.2}", "{games}", "{commander}", "{avg_score:.2}", "{accuracy:.2}"], ); println!("\n\n"); diff --git a/ns2-stat-cli/src/table.rs b/ns2-stat-cli/src/table.rs index 77b31cd..9fb23f8 100644 --- a/ns2-stat-cli/src/table.rs +++ b/ns2-stat-cli/src/table.rs @@ -1,6 +1,6 @@ #[macro_export] macro_rules! row { - ($($e:literal),*) => { + ($($e:literal),*$(,)?) => { [$(format!($e)),*] } } diff --git a/ns2-stat/src/lib.rs b/ns2-stat/src/lib.rs index d131c3b..dd92cf1 100644 --- a/ns2-stat/src/lib.rs +++ b/ns2-stat/src/lib.rs @@ -1,8 +1,9 @@ use std::collections::HashMap; +use std::ops::AddAssign; use serde::Serialize; -use input_types::{GameStats, WinningTeam}; +use input_types::{GameStats, Team, WinningTeam}; pub mod input_types; @@ -47,24 +48,66 @@ impl<'a, I: Iterator> Games<'a, I> { } } +// can be used for games, commander, wins, kills, deaths, assists +#[derive(Clone, Copy, Default, Serialize)] +pub struct Stat { + pub total: T, + pub marines: T, + pub aliens: T, +} + +impl Stat { + fn add(&mut self, team: Team, n: T) { + self.total += n; + match team { + Team::Aliens => self.aliens += n, + Team::Marines => self.marines += n, + } + } +} + +impl Stat { + fn map(stats: [Stat; N], f: impl Fn([T; N]) -> U) -> Stat { + Stat { + total: f(stats.map(|stat| stat.total)), + marines: f(stats.map(|stat| stat.marines)), + aliens: f(stats.map(|stat| stat.aliens)), + } + } +} + #[derive(Default, Serialize)] pub struct User { - pub total_games: u32, - pub commander: u32, - pub marines: u32, - pub aliens: u32, - pub kills: u32, - pub assists: u32, - pub deaths: u32, + /// The number of games played. + pub games: Stat, + /// The number of games played as commander. + pub commander: Stat, + pub wins: Stat, + pub kills: Stat, + pub assists: Stat, + pub deaths: Stat, + pub score: Stat, + pub hits: Stat, + pub misses: Stat, } impl User { - pub fn kd(&self) -> f32 { - self.kills as f32 / self.deaths as f32 + /// `kills / deaths` + pub fn kd(&self) -> Stat { + Stat::map([self.kills, self.deaths], |[kills, deaths]| kills as f32 / deaths as f32) } - pub fn kda(&self) -> f32 { - (self.kills + self.assists) as f32 / self.deaths as f32 + /// `(kills + assists) / deaths` + pub fn kda(&self) -> Stat { + Stat::map([self.kills, self.assists, self.deaths], |[kills, assists, deaths]| (kills + assists) as f32 / deaths as f32) + } + + pub fn average_score(&self) -> Stat { + Stat::map([self.games, self.score], |[games, score]| score as f32 / games as f32) + } + + pub fn accuracy(&self) -> Stat { + Stat::map([self.hits, self.misses], |[hits, misses]| hits as f32 / (hits + misses) as f32) } } @@ -105,35 +148,41 @@ impl NS2Stats { Some(user) => user, None => users.entry(player_stat.player_name.clone()).or_insert_with(User::default), }; - user.total_games += 1; - - for stats in [&player_stat.marines, &player_stat.aliens] { - user.kills += stats.kills; - user.assists += stats.assists; - user.deaths += stats.deaths; - } - if player_stat.marines.time_played > player_stat.aliens.time_played { + let (team, stats) = if player_stat.marines.time_played > player_stat.aliens.time_played { // player was in marine team - user.marines += 1; + if game.round_info.winning_team == WinningTeam::Marines { + user.wins.add(Team::Marines, 1); + } if player_stat.marines.commander_time > marine_comm_time { marine_comm = &player_stat.player_name; marine_comm_time = player_stat.marines.commander_time; } + (Team::Marines, &player_stat.marines) } else { // player was in alien team - user.aliens += 1; + if game.round_info.winning_team == WinningTeam::Aliens { + user.wins.add(Team::Aliens, 1); + } if player_stat.aliens.commander_time > alien_comm_time { alien_comm = &player_stat.player_name; alien_comm_time = player_stat.aliens.commander_time; } - } + (Team::Aliens, &player_stat.aliens) + }; + user.games.add(team, 1); + user.kills.add(team, stats.kills); + user.assists.add(team, stats.assists); + user.deaths.add(team, stats.deaths); + user.score.add(team, stats.score); + user.hits.add(team, stats.hits); + user.misses.add(team, stats.misses); } if let Some(user) = users.get_mut(marine_comm) { - user.commander += 1; + user.commander.add(Team::Marines, 1); } if let Some(user) = users.get_mut(alien_comm) { - user.commander += 1; + user.commander.add(Team::Aliens, 1); } let map_entry = match maps.get_mut(&game.round_info.map_name) {