Improve unit test and a bunch of I forget what.
This commit is contained in:
@@ -260,7 +260,7 @@
|
|||||||
Play(
|
Play(
|
||||||
action: Unknown, // Original note: Same Failed Throw
|
action: Unknown, // Original note: Same Failed Throw
|
||||||
down: Fourth,
|
down: Fourth,
|
||||||
terrain: Unknown,
|
terrain: None,
|
||||||
),
|
),
|
||||||
Quarter(Third),
|
Quarter(Third),
|
||||||
Kickoff(Colorado),
|
Kickoff(Colorado),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{fmt, io};
|
|||||||
pub enum LogFileError {
|
pub enum LogFileError {
|
||||||
IOError(io::Error),
|
IOError(io::Error),
|
||||||
RonSpanned(ron::error::SpannedError),
|
RonSpanned(ron::error::SpannedError),
|
||||||
TooManyTeams(usize),
|
TeamCount(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for LogFileError {
|
impl fmt::Display for LogFileError {
|
||||||
@@ -13,7 +13,7 @@ impl fmt::Display for LogFileError {
|
|||||||
match self {
|
match self {
|
||||||
Self::IOError(err) => write!(f, "{}", err),
|
Self::IOError(err) => write!(f, "{}", err),
|
||||||
Self::RonSpanned(err) => write!(f, "{}", err),
|
Self::RonSpanned(err) => write!(f, "{}", err),
|
||||||
Self::TooManyTeams(err) => write!(f, "Expected two, found: {:?}", err),
|
Self::TeamCount(err) => write!(f, "Expected two, found: {:?}", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::{Down, Play, Quarter, TerrainState};
|
use crate::{Down, Play, Quarter, TerrainState};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use strum::EnumIter;
|
||||||
|
|
||||||
type Offence = Team;
|
type Offence = Team;
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ impl Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, PartialEq, Default)]
|
#[derive(Debug, Deserialize, Clone, PartialEq, Default, EnumIter)]
|
||||||
pub enum Team {
|
pub enum Team {
|
||||||
ArizonaState,
|
ArizonaState,
|
||||||
#[deprecated(since = "0.2.0", note = "Team left the project.")]
|
#[deprecated(since = "0.2.0", note = "Team left the project.")]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ 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, usize) {
|
||||||
let mut most_freq_action = Action::default();
|
let mut most_freq_action = Action::default();
|
||||||
let mut frequency = usize::MIN;
|
let mut frequency = usize::MIN;
|
||||||
let mut found = usize::MIN;
|
let mut found = usize::MIN;
|
||||||
@@ -25,12 +25,12 @@ impl LogFile {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
most_freq_action
|
(most_freq_action, frequency)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the least common action for a given team.
|
/// Returns the least common action for a given team.
|
||||||
/// This action has to have been played at least once.
|
/// This action has to have been played at least once.
|
||||||
pub fn least_frequent_action(&self, team: Team) -> Action {
|
pub fn least_frequent_action(&self, team: Team) -> (Action, usize) {
|
||||||
let mut least_freq_action = Action::default();
|
let mut least_freq_action = Action::default();
|
||||||
let mut frequency = usize::MAX;
|
let mut frequency = usize::MAX;
|
||||||
let mut found = usize::MAX;
|
let mut found = usize::MAX;
|
||||||
@@ -42,21 +42,20 @@ impl LogFile {
|
|||||||
found = team_actions.clone().filter(|a| *a == action).count();
|
found = team_actions.clone().filter(|a| *a == action).count();
|
||||||
|
|
||||||
if (found != 0_usize) && (found < frequency) {
|
if (found != 0_usize) && (found < frequency) {
|
||||||
dbg!("hit");
|
|
||||||
frequency = found;
|
frequency = found;
|
||||||
least_freq_action = action.to_owned();
|
least_freq_action = action.to_owned();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
least_freq_action
|
(least_freq_action, frequency)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn most_effective_play(&self, team: Team) -> (Action, TerrainState) {
|
pub fn most_effective_play(&self, team: Team) -> (Action, TerrainState) {
|
||||||
let deltas: Vec<Vec<i8>> = self
|
let deltas = self
|
||||||
.0
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.map(|game| game.deltas(team.to_owned()))
|
.map(|game| game.deltas(team.to_owned()))
|
||||||
.collect();
|
.collect::<Vec<Vec<i8>>>();
|
||||||
|
|
||||||
let team_events: Vec<Vec<Event>> = self
|
let team_events: Vec<Vec<Event>> = self
|
||||||
.0
|
.0
|
||||||
@@ -65,7 +64,7 @@ impl LogFile {
|
|||||||
.collect::<Vec<TeamEvents>>()
|
.collect::<Vec<TeamEvents>>()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|team_events| team_events.0.to_owned())
|
.map(|team_events| team_events.0.to_owned())
|
||||||
.collect::<Vec<Vec<Event>>>();
|
.collect();
|
||||||
|
|
||||||
let mut action_return = Action::Unknown;
|
let mut action_return = Action::Unknown;
|
||||||
let mut terrain_delta: u8 = 0;
|
let mut terrain_delta: u8 = 0;
|
||||||
@@ -87,15 +86,15 @@ impl LogFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
event_idx += 1;
|
if (event_idx + 1) == game.len() {
|
||||||
|
event_idx = 0;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
event_idx += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game_idx += 1;
|
game_idx += 1;
|
||||||
|
|
||||||
if (event_idx + 1) == game.len() {
|
|
||||||
event_idx = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sum: u8 = action_deltas.iter().sum::<i8>() as u8;
|
let sum: u8 = action_deltas.iter().sum::<i8>() as u8;
|
||||||
@@ -194,11 +193,11 @@ mod tests {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Event::Play(Play {
|
Event::Play(Play {
|
||||||
action: Action::Mesh,
|
action: Action::Curls,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Event::Play(Play {
|
Event::Play(Play {
|
||||||
action: Action::Curls,
|
action: Action::Mesh,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Event::Play(Play {
|
Event::Play(Play {
|
||||||
@@ -239,11 +238,11 @@ mod tests {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Event::Play(Play {
|
Event::Play(Play {
|
||||||
action: Action::Curls,
|
action: Action::SlotOut,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Event::Play(Play {
|
Event::Play(Play {
|
||||||
action: Action::SlotOut,
|
action: Action::Curls,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
Event::Kickoff(Team::ArizonaState),
|
Event::Kickoff(Team::ArizonaState),
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ impl Game {
|
|||||||
if teams.len() == 2 || ignore.len() != 0 {
|
if teams.len() == 2 || ignore.len() != 0 {
|
||||||
Ok(teams)
|
Ok(teams)
|
||||||
} else {
|
} else {
|
||||||
Err(error::LogFileError::TooManyTeams(teams.len()))
|
Err(error::LogFileError::TeamCount(teams.len()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,13 @@ impl Game {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let len = events.len() - 1;
|
|
||||||
|
let len = if events.len() == 0 {
|
||||||
|
return vec![0];
|
||||||
|
} else {
|
||||||
|
events.len() - 1
|
||||||
|
};
|
||||||
|
|
||||||
let mut idx: usize = 0;
|
let mut idx: usize = 0;
|
||||||
let mut deltas: Vec<i8> = vec![];
|
let mut deltas: Vec<i8> = vec![];
|
||||||
|
|
||||||
@@ -326,7 +332,7 @@ impl Period {
|
|||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
||||||
pub enum Flags {
|
pub enum Flags {
|
||||||
ClockBleeding(Team),
|
ClockBleed(Team),
|
||||||
IgnoreActions,
|
IgnoreActions,
|
||||||
IgnoreTeam(Team),
|
IgnoreTeam(Team),
|
||||||
IgnoreScore,
|
IgnoreScore,
|
||||||
@@ -400,15 +406,6 @@ mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let c = Game {
|
let c = Game {
|
||||||
events: vec![
|
|
||||||
Event::Kickoff(Team::Nebraska),
|
|
||||||
Event::Turnover(Team::ArizonaState),
|
|
||||||
Event::Kickoff(Team::Nebraska),
|
|
||||||
],
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let d = Game {
|
|
||||||
flags: vec![Flags::IgnoreTeam(Team::Nebraska)],
|
flags: vec![Flags::IgnoreTeam(Team::Nebraska)],
|
||||||
events: vec![Event::Kickoff(Team::Nebraska)],
|
events: vec![Event::Kickoff(Team::Nebraska)],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -416,8 +413,7 @@ mod tests {
|
|||||||
|
|
||||||
assert!(a.teams().unwrap() == vec![Team::Nebraska, Team::ArizonaState]);
|
assert!(a.teams().unwrap() == vec![Team::Nebraska, Team::ArizonaState]);
|
||||||
assert!(b.teams().is_err() == true);
|
assert!(b.teams().is_err() == true);
|
||||||
assert!(c.teams().unwrap() == vec![Team::ArizonaState]);
|
assert!(c.teams().unwrap() == vec![]);
|
||||||
assert!(d.teams().unwrap() == vec![]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
1
miller/Cargo.lock
generated
1
miller/Cargo.lock
generated
@@ -314,6 +314,7 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"gamelog",
|
"gamelog",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
|
"strum 0.27.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ license = "MIT"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ratatui = "0.29"
|
ratatui = "0.29"
|
||||||
|
strum = "0.27"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "4.5"
|
version = "4.5"
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ mod tui;
|
|||||||
|
|
||||||
use clap::{ArgAction, Parser};
|
use clap::{ArgAction, Parser};
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use gamelog::{Action, Down, Flags, Key, LogFile, Team};
|
use gamelog::{Action, Down, Flags, Key, LogFile, Team, TerrainState};
|
||||||
use std::{io, path::PathBuf, sync::mpsc, thread};
|
use std::{io, path::PathBuf, sync::mpsc, thread};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
use tui::App;
|
use tui::App;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
@@ -43,16 +44,14 @@ fn main() -> io::Result<()> {
|
|||||||
TeamStats::new(Team::Iowa),
|
TeamStats::new(Team::Iowa),
|
||||||
TeamStats::new(Team::Nebraska),
|
TeamStats::new(Team::Nebraska),
|
||||||
TeamStats::new(Team::Syracuse),
|
TeamStats::new(Team::Syracuse),
|
||||||
|
#[allow(deprecated)]
|
||||||
TeamStats::new(Team::SouthCarolina),
|
TeamStats::new(Team::SouthCarolina),
|
||||||
TeamStats::new(Team::TexasAnM),
|
TeamStats::new(Team::TexasAnM),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Work on knocking down the nesting here?
|
// Work on knocking down the nesting here?
|
||||||
for game in log.0.iter() {
|
for game in log.0.iter() {
|
||||||
let teams = match game.teams() {
|
let teams = game.teams().unwrap();
|
||||||
Ok(teams) => teams,
|
|
||||||
Err(_) => continue,
|
|
||||||
};
|
|
||||||
|
|
||||||
for team in teams {
|
for team in teams {
|
||||||
// Skip team if they are to be ignored this game.
|
// Skip team if they are to be ignored this game.
|
||||||
@@ -89,6 +88,21 @@ fn main() -> io::Result<()> {
|
|||||||
.penalties_per_game
|
.penalties_per_game
|
||||||
.push(game.penalties(team.to_owned()));
|
.push(game.penalties(team.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for team in gamelog::Team::iter() {
|
||||||
|
let team_idx = stats
|
||||||
|
.iter()
|
||||||
|
.position(|stat| stat.team == team.to_owned())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
stats[team_idx].most_common_play = Some(log.most_frequent_action(team.to_owned()));
|
||||||
|
stats[team_idx].least_common_play =
|
||||||
|
Some(log.least_frequent_action(team.to_owned()));
|
||||||
|
/*
|
||||||
|
stats[team_idx].most_effective_play =
|
||||||
|
Some(log.most_effective_play(team.to_owned()));
|
||||||
|
*/
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// :#? for pretty-printing.
|
// :#? for pretty-printing.
|
||||||
@@ -127,14 +141,12 @@ struct TeamStats {
|
|||||||
plays_per_game: Vec<usize>,
|
plays_per_game: Vec<usize>,
|
||||||
// Penalties
|
// Penalties
|
||||||
penalties_per_game: Vec<usize>,
|
penalties_per_game: Vec<usize>,
|
||||||
// Score
|
|
||||||
points_per_quarter: Vec<u8>,
|
|
||||||
points_per_game: Vec<u8>,
|
|
||||||
// Biases
|
// Biases
|
||||||
most_common_play: Option<Action>,
|
most_common_play: Option<(Action, usize)>,
|
||||||
least_common_play: Option<Action>,
|
least_common_play: Option<(Action, usize)>,
|
||||||
most_common_key: Option<Key>,
|
most_common_key: Option<Key>,
|
||||||
least_common_key: Option<Key>,
|
least_common_key: Option<Key>,
|
||||||
|
most_effective_play: Option<(Action, TerrainState)>,
|
||||||
// Traits
|
// Traits
|
||||||
// Typical number of downs to achieve 10 yards.
|
// Typical number of downs to achieve 10 yards.
|
||||||
time_to_first_down: Option<Down>,
|
time_to_first_down: Option<Down>,
|
||||||
@@ -150,12 +162,11 @@ impl TeamStats {
|
|||||||
plays_per_quarter: vec![],
|
plays_per_quarter: vec![],
|
||||||
plays_per_game: vec![],
|
plays_per_game: vec![],
|
||||||
penalties_per_game: vec![],
|
penalties_per_game: vec![],
|
||||||
points_per_quarter: vec![],
|
|
||||||
points_per_game: vec![],
|
|
||||||
most_common_play: None,
|
most_common_play: None,
|
||||||
least_common_play: None,
|
least_common_play: None,
|
||||||
most_common_key: None,
|
most_common_key: None,
|
||||||
least_common_key: None,
|
least_common_key: None,
|
||||||
|
most_effective_play: None,
|
||||||
time_to_first_down: None,
|
time_to_first_down: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user