Add least_frequent_action method; patch test faults.
This commit is contained in:
@@ -1,68 +1,56 @@
|
|||||||
use crate::{Action, Play, Team, error};
|
use crate::{Action, Game, Play, Team, error};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{fs::File, path::PathBuf};
|
use std::{fs::File, path::PathBuf, usize};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone, Default)]
|
||||||
pub struct LogFile(pub Vec<super::Game>);
|
pub struct LogFile(pub Vec<Game>);
|
||||||
|
|
||||||
impl LogFile {
|
impl LogFile {
|
||||||
/// Returns the most common action for a given team.
|
/// Returns the most common action for a given team.
|
||||||
pub fn most_frequent_action(&self, team: Team) -> Action {
|
pub fn most_frequent_action(&self, team: Team) -> Action {
|
||||||
let mut most_freq_action = Action::Unknown;
|
let mut most_freq_action = Action::default();
|
||||||
let mut frequency = 0;
|
let mut frequency = usize::MIN;
|
||||||
|
let mut found = usize::MIN;
|
||||||
|
let team_actions = self.team_actions(team).into_iter();
|
||||||
|
|
||||||
// The following let statement is equivalent to:
|
Action::iter()
|
||||||
//
|
.filter(|action| *action != Action::Unknown)
|
||||||
// let team_actions = {
|
.for_each(|action| {
|
||||||
// let mut actions = vec![];
|
found = team_actions.clone().filter(|a| *a == action).count();
|
||||||
//
|
|
||||||
// for game in &self.0 {
|
|
||||||
// for play in game.team_plays(team.to_owned()).0 {
|
|
||||||
// actions.push(play.action.to_owned())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// actions
|
|
||||||
// }
|
|
||||||
// .into_iter();
|
|
||||||
//
|
|
||||||
// I just write iterators more naturally for some reason
|
|
||||||
// despite them being less readable afterward. I came from
|
|
||||||
// loving python's list comprehensions.
|
|
||||||
// I suppose I like the lack of nesting.
|
|
||||||
//
|
|
||||||
// I have no clue if the iterator is actually more efficient.
|
|
||||||
|
|
||||||
let team_actions = self
|
if found > frequency {
|
||||||
.0
|
frequency = found;
|
||||||
.iter()
|
most_freq_action = action.to_owned();
|
||||||
.filter_map(|game| Some(game.team_plays(team.to_owned()).0))
|
}
|
||||||
.collect::<Vec<Vec<Play>>>()
|
});
|
||||||
.concat()
|
|
||||||
.iter()
|
|
||||||
.filter_map(|play| Some(play.action.to_owned()))
|
|
||||||
.collect::<Vec<Action>>()
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
let mut found: usize;
|
|
||||||
|
|
||||||
for action in Action::iter() {
|
|
||||||
if action == Action::Unknown {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = team_actions.clone().filter(|a| *a == action).count();
|
|
||||||
|
|
||||||
if found > frequency {
|
|
||||||
frequency = found;
|
|
||||||
most_freq_action = action.to_owned();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
most_freq_action
|
most_freq_action
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the least common action for a given team.
|
||||||
|
/// This action has to have been played at least once.
|
||||||
|
pub fn least_frequent_action(&self, team: Team) -> Action {
|
||||||
|
let mut least_freq_action = Action::default();
|
||||||
|
let mut frequency = usize::MAX;
|
||||||
|
let mut found = usize::MAX;
|
||||||
|
let team_actions = self.team_actions(team).into_iter();
|
||||||
|
|
||||||
|
Action::iter()
|
||||||
|
.filter(|action| *action != Action::Unknown)
|
||||||
|
.for_each(|action| {
|
||||||
|
found = team_actions.clone().filter(|a| *a == action).count();
|
||||||
|
|
||||||
|
if (found != 0_usize) && (found < frequency) {
|
||||||
|
dbg!("hit");
|
||||||
|
frequency = found;
|
||||||
|
least_freq_action = action.to_owned();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
least_freq_action
|
||||||
|
}
|
||||||
|
|
||||||
pub fn check_teams(self) -> Result<LogFile, error::LogFileError> {
|
pub fn check_teams(self) -> Result<LogFile, error::LogFileError> {
|
||||||
for game in &self.0 {
|
for game in &self.0 {
|
||||||
if let Err(err) = game.teams() {
|
if let Err(err) = game.teams() {
|
||||||
@@ -72,6 +60,38 @@ impl LogFile {
|
|||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the team actions.
|
||||||
|
/// The following code is equivalent to:
|
||||||
|
fn team_actions(&self, team: Team) -> Vec<Action> {
|
||||||
|
// ```
|
||||||
|
// fn foo(&self, team: Team) -> Vec<Action> {
|
||||||
|
// let mut actions = vec![];
|
||||||
|
//
|
||||||
|
// for game in &self.0 {
|
||||||
|
// for play in game.team_plays(team.to_owned()).0 {
|
||||||
|
// actions.push(play.action.to_owned())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// actions
|
||||||
|
// }
|
||||||
|
// ```
|
||||||
|
// I just write iterators more naturally for some reason
|
||||||
|
// despite them being less readable afterward. I came from
|
||||||
|
// loving python's list comprehensions.
|
||||||
|
// I suppose I like the lack of nesting.
|
||||||
|
//
|
||||||
|
// I have no clue if the iterator is actually more efficient.
|
||||||
|
self.0
|
||||||
|
.iter()
|
||||||
|
.filter_map(|game| Some(game.team_plays(team.to_owned()).0))
|
||||||
|
.collect::<Vec<Vec<Play>>>()
|
||||||
|
.concat()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|play| Some(play.action.to_owned()))
|
||||||
|
.collect::<Vec<Action>>()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<File> for LogFile {
|
impl TryFrom<File> for LogFile {
|
||||||
@@ -97,3 +117,84 @@ impl TryFrom<PathBuf> for LogFile {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn most_frequent_action() {
|
||||||
|
let a = LogFile(vec![Game {
|
||||||
|
version: crate::MIN_VER,
|
||||||
|
flags: vec![],
|
||||||
|
events: vec![
|
||||||
|
Event::Kickoff(Team::Nebraska),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Mesh,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Mesh,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Mesh,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Curls,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Curls,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::SlotOut,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Kickoff(Team::ArizonaState),
|
||||||
|
],
|
||||||
|
}]);
|
||||||
|
|
||||||
|
assert!(a.most_frequent_action(Team::Nebraska) == Action::Mesh)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn least_frequent_action() {
|
||||||
|
let a = LogFile(vec![Game {
|
||||||
|
version: crate::MIN_VER,
|
||||||
|
flags: vec![],
|
||||||
|
events: vec![
|
||||||
|
Event::Kickoff(Team::Nebraska),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Mesh,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Mesh,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Mesh,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Curls,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::Curls,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Play(Play {
|
||||||
|
action: Action::SlotOut,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
Event::Kickoff(Team::ArizonaState),
|
||||||
|
],
|
||||||
|
}]);
|
||||||
|
|
||||||
|
assert!(a.least_frequent_action(Team::Nebraska) == Action::SlotOut)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -513,7 +513,7 @@ mod tests {
|
|||||||
Event::Kickoff(Team::Nebraska),
|
Event::Kickoff(Team::Nebraska),
|
||||||
Event::Play(Play::default()),
|
Event::Play(Play::default()),
|
||||||
Event::Score(ScorePoints::default()),
|
Event::Score(ScorePoints::default()),
|
||||||
Event::Kickoff(Team::SouthCarolina),
|
Event::Kickoff(Team::ArizonaState),
|
||||||
Event::Play(Play::default()),
|
Event::Play(Play::default()),
|
||||||
Event::Turnover(Team::Nebraska),
|
Event::Turnover(Team::Nebraska),
|
||||||
Event::Play(Play::default()),
|
Event::Play(Play::default()),
|
||||||
|
|||||||
Reference in New Issue
Block a user