Various patches and Delta implementations.
Cheap summaries in main.rs
This commit is contained in:
@@ -5,8 +5,8 @@ type Offence = Team;
|
|||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Play(Play),
|
|
||||||
Kickoff(Offence),
|
Kickoff(Offence),
|
||||||
|
Play(Play),
|
||||||
Turnover(Offence),
|
Turnover(Offence),
|
||||||
Penalty(TerrainState),
|
Penalty(TerrainState),
|
||||||
Score(ScorePoints),
|
Score(ScorePoints),
|
||||||
@@ -54,13 +54,13 @@ impl Event {
|
|||||||
let a = if let TerrainState::Yards(yrds) = preceeding.terrain? {
|
let a = if let TerrainState::Yards(yrds) = preceeding.terrain? {
|
||||||
yrds
|
yrds
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
0_u8
|
||||||
};
|
};
|
||||||
|
|
||||||
let b = if let TerrainState::Yards(yrds) = following.terrain? {
|
let b = if let TerrainState::Yards(yrds) = following.terrain? {
|
||||||
yrds
|
yrds
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
0_u8
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(a as i8 - b as i8)
|
Some(a as i8 - b as i8)
|
||||||
@@ -159,27 +159,100 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert!(10_i8 == kickoff.delta(&first_down).unwrap());
|
assert!(10_i8 == kickoff.delta(&first_down).unwrap());
|
||||||
assert!(0_i8 == first_down.delta(&second_down).unwrap());
|
assert!(0_i8 == kickoff.delta(&second_down).unwrap());
|
||||||
assert!(-3_i8 == second_down.delta(&third_down).unwrap());
|
assert!(None == kickoff.delta(&penalty));
|
||||||
|
assert!(None == kickoff.delta(&score));
|
||||||
|
|
||||||
assert!(10_i8 == first_down.delta(&kickoff).unwrap());
|
assert!(10_i8 == first_down.delta(&kickoff).unwrap());
|
||||||
|
assert!(10_i8 == first_down.delta(&first_down).unwrap());
|
||||||
|
assert!(0_i8 == first_down.delta(&second_down).unwrap());
|
||||||
|
assert!(None == first_down.delta(&turnover));
|
||||||
|
assert!(None == first_down.delta(&penalty));
|
||||||
|
assert!(None == first_down.delta(&score));
|
||||||
assert!(10_i8 == first_down.delta(&goal_line).unwrap());
|
assert!(10_i8 == first_down.delta(&goal_line).unwrap());
|
||||||
assert!(10_i8 == first_down.delta(&inches).unwrap());
|
assert!(10_i8 == first_down.delta(&inches).unwrap());
|
||||||
|
assert!(None == first_down.delta(&noned_down));
|
||||||
|
|
||||||
|
assert!(10_i8 == second_down.delta(&kickoff).unwrap());
|
||||||
|
assert!(10_i8 == second_down.delta(&first_down).unwrap());
|
||||||
|
assert!(-3_i8 == second_down.delta(&third_down).unwrap());
|
||||||
|
assert!(None == second_down.delta(&turnover));
|
||||||
|
assert!(None == second_down.delta(&penalty));
|
||||||
|
assert!(None == second_down.delta(&score));
|
||||||
|
assert!(10_i8 == second_down.delta(&goal_line).unwrap());
|
||||||
|
assert!(10_i8 == second_down.delta(&inches).unwrap());
|
||||||
|
assert!(None == second_down.delta(&noned_down));
|
||||||
|
|
||||||
assert!(13_i8 == third_down.delta(&kickoff).unwrap());
|
assert!(13_i8 == third_down.delta(&kickoff).unwrap());
|
||||||
|
assert!(13_i8 == third_down.delta(&first_down).unwrap());
|
||||||
assert!(8_i8 == third_down.delta(&fourth_down).unwrap());
|
assert!(8_i8 == third_down.delta(&fourth_down).unwrap());
|
||||||
|
assert!(None == third_down.delta(&turnover));
|
||||||
|
assert!(None == third_down.delta(&penalty));
|
||||||
|
assert!(None == third_down.delta(&score));
|
||||||
assert!(13_i8 == third_down.delta(&goal_line).unwrap());
|
assert!(13_i8 == third_down.delta(&goal_line).unwrap());
|
||||||
|
assert!(13_i8 == third_down.delta(&inches).unwrap());
|
||||||
|
assert!(None == third_down.delta(&noned_down));
|
||||||
|
|
||||||
|
assert!(5_i8 == fourth_down.delta(&kickoff).unwrap());
|
||||||
|
assert!(5_i8 == fourth_down.delta(&first_down).unwrap());
|
||||||
assert!(None == fourth_down.delta(&turnover));
|
assert!(None == fourth_down.delta(&turnover));
|
||||||
assert!(None == kickoff.delta(&penalty));
|
assert!(None == fourth_down.delta(&penalty));
|
||||||
assert!(None == first_down.delta(&penalty));
|
assert!(None == fourth_down.delta(&score));
|
||||||
assert!(None == noned_down.delta(&kickoff));
|
assert!(5_i8 == fourth_down.delta(&goal_line).unwrap());
|
||||||
assert!(None == noned_down.delta(&turnover));
|
assert!(5_i8 == fourth_down.delta(&inches).unwrap());
|
||||||
assert!(None == kickoff.delta(&score));
|
assert!(None == fourth_down.delta(&noned_down));
|
||||||
assert!(None == first_down.delta(&score));
|
|
||||||
assert!(None == turnover.delta(&score));
|
|
||||||
assert!(None == goal_line.delta(&first_down));
|
|
||||||
assert!(None == inches.delta(&first_down));
|
|
||||||
assert!(None == goal_line.delta(&inches));
|
|
||||||
assert!(10_i8 == turnover.delta(&first_down).unwrap());
|
assert!(10_i8 == turnover.delta(&first_down).unwrap());
|
||||||
assert!(0_i8 == turnover.delta(&second_down).unwrap());
|
assert!(0_i8 == turnover.delta(&second_down).unwrap());
|
||||||
assert!(-3_i8 == turnover.delta(&third_down).unwrap());
|
assert!(None == turnover.delta(&turnover));
|
||||||
|
assert!(None == turnover.delta(&penalty));
|
||||||
|
assert!(None == turnover.delta(&score));
|
||||||
|
assert!(10_i8 == turnover.delta(&goal_line).unwrap());
|
||||||
|
assert!(10_i8 == turnover.delta(&inches).unwrap());
|
||||||
|
assert!(None == turnover.delta(&noned_down));
|
||||||
|
|
||||||
|
assert!(None == score.delta(&kickoff));
|
||||||
|
assert!(None == score.delta(&first_down));
|
||||||
|
assert!(None == score.delta(&second_down));
|
||||||
|
assert!(None == score.delta(&third_down));
|
||||||
|
assert!(None == score.delta(&fourth_down));
|
||||||
|
assert!(None == score.delta(&turnover));
|
||||||
|
assert!(None == score.delta(&penalty));
|
||||||
|
assert!(None == score.delta(&goal_line));
|
||||||
|
assert!(None == score.delta(&inches));
|
||||||
|
assert!(None == score.delta(&score));
|
||||||
|
|
||||||
|
assert!(None == goal_line.delta(&kickoff));
|
||||||
|
assert!(None == goal_line.delta(&first_down));
|
||||||
|
assert!(-10_i8 == goal_line.delta(&second_down).unwrap());
|
||||||
|
assert!(-13_i8 == goal_line.delta(&third_down).unwrap());
|
||||||
|
assert!(-5_i8 == goal_line.delta(&fourth_down).unwrap());
|
||||||
|
assert!(None == goal_line.delta(&turnover));
|
||||||
|
assert!(None == goal_line.delta(&penalty));
|
||||||
|
assert!(None == goal_line.delta(&goal_line));
|
||||||
|
assert!(None == goal_line.delta(&inches));
|
||||||
|
assert!(None == goal_line.delta(&score));
|
||||||
|
|
||||||
|
assert!(None == inches.delta(&kickoff));
|
||||||
|
assert!(None == inches.delta(&first_down));
|
||||||
|
assert!(-10_i8 == goal_line.delta(&second_down).unwrap());
|
||||||
|
assert!(-13_i8 == goal_line.delta(&third_down).unwrap());
|
||||||
|
assert!(-5_i8 == goal_line.delta(&fourth_down).unwrap());
|
||||||
|
assert!(None == inches.delta(&turnover));
|
||||||
|
assert!(None == inches.delta(&penalty));
|
||||||
|
assert!(None == inches.delta(&goal_line));
|
||||||
|
assert!(None == inches.delta(&inches));
|
||||||
|
assert!(None == inches.delta(&score));
|
||||||
|
|
||||||
|
assert!(None == noned_down.delta(&kickoff));
|
||||||
|
assert!(None == noned_down.delta(&first_down));
|
||||||
|
assert!(None == noned_down.delta(&second_down));
|
||||||
|
assert!(None == noned_down.delta(&third_down));
|
||||||
|
assert!(None == noned_down.delta(&fourth_down));
|
||||||
|
assert!(None == noned_down.delta(&turnover));
|
||||||
|
assert!(None == noned_down.delta(&penalty));
|
||||||
|
assert!(None == noned_down.delta(&goal_line));
|
||||||
|
assert!(None == noned_down.delta(&inches));
|
||||||
|
assert!(None == noned_down.delta(&score));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,8 +53,6 @@ impl Game {
|
|||||||
let mut idx: usize = 0;
|
let mut idx: usize = 0;
|
||||||
let mut deltas: Vec<i8> = vec![];
|
let mut deltas: Vec<i8> = vec![];
|
||||||
|
|
||||||
dbg!(&events);
|
|
||||||
|
|
||||||
while idx < len {
|
while idx < len {
|
||||||
if let Some(value) = events[idx].delta(&events[idx + 1]) {
|
if let Some(value) = events[idx].delta(&events[idx + 1]) {
|
||||||
deltas.push(value);
|
deltas.push(value);
|
||||||
@@ -66,31 +64,6 @@ impl Game {
|
|||||||
deltas
|
deltas
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The average number of plays in a quarter.
|
|
||||||
/// Does not include OT plays or quarters where team indeterminate.
|
|
||||||
pub fn avg_plays_per_quarter(&self, team: Team) -> f32 {
|
|
||||||
// Handle if teams known at start or not override via index calculation of all game events.
|
|
||||||
|
|
||||||
let quarterly_avgs: Vec<f32> = self
|
|
||||||
.periods
|
|
||||||
.iter()
|
|
||||||
.filter_map(|period| {
|
|
||||||
if !period.is_overtime() {
|
|
||||||
let plays = period.team_plays(team.to_owned(), None);
|
|
||||||
Some(plays.unwrap().len() as f32 / period.quarters().len() as f32)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<f32>>();
|
|
||||||
|
|
||||||
let mut summation = 0_f32;
|
|
||||||
|
|
||||||
quarterly_avgs.iter().for_each(|float| summation += float);
|
|
||||||
|
|
||||||
summation / quarterly_avgs.len() as f32
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn team_plays(&self, team: Team) -> usize {
|
pub fn team_plays(&self, team: Team) -> usize {
|
||||||
let quarterly_plays: Vec<usize> = self
|
let quarterly_plays: Vec<usize> = self
|
||||||
.periods
|
.periods
|
||||||
@@ -111,6 +84,67 @@ impl Game {
|
|||||||
|
|
||||||
summation
|
summation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The average number of plays in a quarter.
|
||||||
|
/// Does not include OT plays or quarters where team indeterminate.
|
||||||
|
pub fn avg_plays_per_quarter(&self, team: Team) -> f32 {
|
||||||
|
// Handle if teams known at start or not override via index calculation of all game events.
|
||||||
|
|
||||||
|
let quarterly_avgs: Vec<f32> = self
|
||||||
|
.periods
|
||||||
|
.iter()
|
||||||
|
.filter_map(|period| {
|
||||||
|
if !period.is_overtime() {
|
||||||
|
let plays = period.team_plays(team.to_owned(), None);
|
||||||
|
Some(plays.unwrap().len() as f32 / period.quarters().len() as f32)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<f32>>();
|
||||||
|
|
||||||
|
quarterly_avgs.iter().sum::<f32>() / quarterly_avgs.len() as f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn avg_delta(&self, team: Team) -> f32 {
|
||||||
|
let deltas = self.deltas(team);
|
||||||
|
|
||||||
|
// Summation doesn't like directly returning f32 from i8.
|
||||||
|
deltas.iter().sum::<i8>() as f32 / deltas.len() as f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn avg_gain(&self, team: Team) -> f32 {
|
||||||
|
let deltas: Vec<u8> = self
|
||||||
|
.deltas(team)
|
||||||
|
.iter()
|
||||||
|
.filter_map(|value| {
|
||||||
|
if value.is_positive() {
|
||||||
|
Some(value.to_owned() as u8)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Summation doesn't like directly returning f32 from u8.
|
||||||
|
deltas.iter().sum::<u8>() as f32 / deltas.len() as f32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn avg_loss(&self, team: Team) -> f32 {
|
||||||
|
let deltas: Vec<i8> = self
|
||||||
|
.deltas(team)
|
||||||
|
.iter()
|
||||||
|
.filter_map(|value| {
|
||||||
|
if value.is_negative() {
|
||||||
|
Some(value.to_owned())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
deltas.iter().sum::<i8>() as f32 / deltas.len() as f32
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use gamelog::{Flags, LogFile};
|
use gamelog::{Action, Flags, LogFile, Team};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
@@ -27,17 +27,93 @@ fn main() {
|
|||||||
Err(err) => panic!("Error: Failed to open logfile: {:?}", err),
|
Err(err) => panic!("Error: Failed to open logfile: {:?}", err),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut stats = vec![
|
||||||
|
TeamStats::new(Team::ArizonaState),
|
||||||
|
#[allow(deprecated)]
|
||||||
|
TeamStats::new(Team::BoiseState),
|
||||||
|
TeamStats::new(Team::Colorado),
|
||||||
|
TeamStats::new(Team::Iowa),
|
||||||
|
TeamStats::new(Team::Nebraska),
|
||||||
|
TeamStats::new(Team::Syracuse),
|
||||||
|
TeamStats::new(Team::SouthCarolina),
|
||||||
|
TeamStats::new(Team::TexasAnM),
|
||||||
|
];
|
||||||
|
|
||||||
for game in log.0.iter() {
|
for game in log.0.iter() {
|
||||||
if let Ok(teams) = game.teams() {
|
if let Ok(teams) = game.teams() {
|
||||||
for team in teams {
|
for team in teams {
|
||||||
if !game.flags.contains(&Flags::IgnoreTeam(team.to_owned())) {
|
if !game.flags.contains(&Flags::IgnoreTeam(team.to_owned())) {
|
||||||
println!(
|
// Team is to have their stats recorded this game of file.
|
||||||
"{:?}: {:?}",
|
let team_idx = stats
|
||||||
&team,
|
.iter()
|
||||||
game.avg_plays_per_quarter(team.to_owned())
|
.position(|stat| {
|
||||||
)
|
if stat.team == team.to_owned() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
stats[team_idx]
|
||||||
|
.avg_terrain_gain
|
||||||
|
.push(game.avg_gain(team.to_owned()));
|
||||||
|
|
||||||
|
stats[team_idx]
|
||||||
|
.avg_terrain_loss
|
||||||
|
.push(game.avg_loss(team.to_owned()));
|
||||||
|
|
||||||
|
stats[team_idx]
|
||||||
|
.avg_terrain_delta
|
||||||
|
.push(game.avg_delta(team.to_owned()));
|
||||||
|
|
||||||
|
stats[team_idx]
|
||||||
|
.plays_per_quarter
|
||||||
|
.push(game.avg_plays_per_quarter(team.to_owned()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for team in stats {
|
||||||
|
dbg!(team);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TeamStats {
|
||||||
|
team: gamelog::Team,
|
||||||
|
// Terrain
|
||||||
|
avg_terrain_gain: Vec<f32>,
|
||||||
|
avg_terrain_loss: Vec<f32>,
|
||||||
|
avg_terrain_delta: Vec<f32>,
|
||||||
|
// Play rate
|
||||||
|
plays_per_quarter: Vec<f32>,
|
||||||
|
plays_per_game: Vec<usize>,
|
||||||
|
// Penalties
|
||||||
|
penalties_per_game: Vec<u8>,
|
||||||
|
// Score
|
||||||
|
points_per_quarter: Vec<u8>,
|
||||||
|
points_per_game: Vec<u8>,
|
||||||
|
// Biases
|
||||||
|
most_common_play: Option<Action>,
|
||||||
|
least_common_play: Option<Action>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TeamStats {
|
||||||
|
fn new(team: Team) -> Self {
|
||||||
|
TeamStats {
|
||||||
|
team,
|
||||||
|
avg_terrain_gain: vec![],
|
||||||
|
avg_terrain_loss: vec![],
|
||||||
|
avg_terrain_delta: vec![],
|
||||||
|
plays_per_quarter: vec![],
|
||||||
|
plays_per_game: vec![],
|
||||||
|
penalties_per_game: vec![],
|
||||||
|
points_per_quarter: vec![],
|
||||||
|
points_per_game: vec![],
|
||||||
|
most_common_play: None,
|
||||||
|
least_common_play: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user