Merge pull request #15 from Cutieguwu/dev
Update main to gamelog v0.7.1 and early tui model from dev.
This commit was merged in pull request #15.
This commit is contained in:
19
README.adoc
19
README.adoc
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
== Prelude
|
== Prelude
|
||||||
|
|
||||||
VERY EARLY ALPHA -- NOT YET FUNCTIONAL
|
|
||||||
|
|
||||||
For my stats course (4U Data Management) I have to interpret a bunch of data generated in class.
|
For my stats course (4U Data Management) I have to interpret a bunch of data generated in class.
|
||||||
In an effort to not spend ages mindlessly using a calculator every summative check-in, I have started this project.
|
In an effort to not spend ages mindlessly using a calculator every summative check-in, I have started this project.
|
||||||
|
|
||||||
@@ -14,6 +12,19 @@ I figured, that since I already had to digitize every note, that I was required
|
|||||||
|
|
||||||
== Goals
|
== Goals
|
||||||
|
|
||||||
|
* [ ] Auto Ranking system?
|
||||||
|
* [ ] Data Visualizer?
|
||||||
|
* [ ] Dynamic Web Page?
|
||||||
|
* [ ] Pattern Analysis / Play Trend Analysis
|
||||||
|
** [ ] Most Frequent Play
|
||||||
|
** [ ] Least Frequent Play
|
||||||
|
** [ ] Most Effective Play (Greatest Terrain Gain on average)
|
||||||
|
** [ ] Most frequent play set.
|
||||||
|
** [ ] Repeating play pattern.
|
||||||
|
** [ ] Slow after score.
|
||||||
|
** [ ] Bias to using Play Actions
|
||||||
|
** [ ] Bias to using Runs
|
||||||
|
|
||||||
=== Gamelog
|
=== Gamelog
|
||||||
* [*] Data Format
|
* [*] Data Format
|
||||||
** [*] Support recording multiple games
|
** [*] Support recording multiple games
|
||||||
@@ -53,7 +64,3 @@ I figured, that since I already had to digitize every note, that I was required
|
|||||||
** [*] Avg. Offence Plays per quarter
|
** [*] Avg. Offence Plays per quarter
|
||||||
** [*] Avg. Offence Plays per game
|
** [*] Avg. Offence Plays per game
|
||||||
** [*] Avg. Penalties per game
|
** [*] Avg. Penalties per game
|
||||||
* [ ] Play Trend Analysis
|
|
||||||
** [ ] Most Frequent Play
|
|
||||||
** [ ] Least Frequent Play
|
|
||||||
** [ ] Most Effective Play (Greatest Terrain Gain given sufficient data)
|
|
||||||
|
|||||||
2724
gamelog.ron
2724
gamelog.ron
File diff suppressed because it is too large
Load Diff
2
gamelog/Cargo.lock
generated
2
gamelog/Cargo.lock
generated
@@ -19,7 +19,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gamelog"
|
name = "gamelog"
|
||||||
version = "0.5.0"
|
version = "0.7.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ron",
|
"ron",
|
||||||
"semver",
|
"semver",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gamelog"
|
name = "gamelog"
|
||||||
version = "0.5.0"
|
version = "0.7.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ pub enum Action {
|
|||||||
CrackStudentBodyRightTackle,
|
CrackStudentBodyRightTackle,
|
||||||
Curls,
|
Curls,
|
||||||
FleaFlicker,
|
FleaFlicker,
|
||||||
|
HailMary,
|
||||||
HalfbackSlam,
|
HalfbackSlam,
|
||||||
HalfbackSlipScreen,
|
HalfbackSlipScreen,
|
||||||
HalfbackSweep,
|
HalfbackSweep,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{Down, Play, Team, TerrainState, error};
|
use crate::{Down, Play, Quarter, TerrainState, error};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
type Offence = Team;
|
type Offence = Team;
|
||||||
@@ -10,6 +10,7 @@ pub enum Event {
|
|||||||
Turnover(Offence),
|
Turnover(Offence),
|
||||||
Penalty(TerrainState),
|
Penalty(TerrainState),
|
||||||
Score(ScorePoints),
|
Score(ScorePoints),
|
||||||
|
Quarter(Quarter),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
@@ -74,6 +75,27 @@ impl Event {
|
|||||||
_ => Err(error::NoTeamAttribute),
|
_ => Err(error::NoTeamAttribute),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn quarter(&self) -> Option<Quarter> {
|
||||||
|
if let Event::Quarter(quarter) = self {
|
||||||
|
Some(quarter.to_owned())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
||||||
|
pub enum Team {
|
||||||
|
ArizonaState,
|
||||||
|
#[deprecated(since = "0.2.0", note = "Team left the project.")]
|
||||||
|
BoiseState,
|
||||||
|
Colorado,
|
||||||
|
Iowa,
|
||||||
|
Nebraska,
|
||||||
|
SouthCarolina,
|
||||||
|
Syracuse,
|
||||||
|
TexasAnM,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, PartialEq, Default)]
|
#[derive(Debug, Deserialize, Clone, PartialEq, Default)]
|
||||||
@@ -158,6 +180,20 @@ mod tests {
|
|||||||
terrain: Some(TerrainState::Inches),
|
terrain: Some(TerrainState::Inches),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let quarter = Event::Quarter(Quarter::First);
|
||||||
|
|
||||||
|
assert!(None == quarter.delta(&kickoff));
|
||||||
|
assert!(None == quarter.delta(&first_down));
|
||||||
|
assert!(None == quarter.delta(&second_down));
|
||||||
|
assert!(None == quarter.delta(&third_down));
|
||||||
|
assert!(None == quarter.delta(&fourth_down));
|
||||||
|
assert!(None == quarter.delta(&turnover));
|
||||||
|
assert!(None == quarter.delta(&penalty));
|
||||||
|
assert!(None == quarter.delta(&goal_line));
|
||||||
|
assert!(None == quarter.delta(&inches));
|
||||||
|
assert!(None == quarter.delta(&score));
|
||||||
|
assert!(None == quarter.delta(&quarter));
|
||||||
|
|
||||||
assert!(10_i8 == kickoff.delta(&first_down).unwrap());
|
assert!(10_i8 == kickoff.delta(&first_down).unwrap());
|
||||||
assert!(0_i8 == kickoff.delta(&second_down).unwrap());
|
assert!(0_i8 == kickoff.delta(&second_down).unwrap());
|
||||||
assert!(None == kickoff.delta(&penalty));
|
assert!(None == kickoff.delta(&penalty));
|
||||||
@@ -235,9 +271,9 @@ mod tests {
|
|||||||
|
|
||||||
assert!(None == inches.delta(&kickoff));
|
assert!(None == inches.delta(&kickoff));
|
||||||
assert!(None == inches.delta(&first_down));
|
assert!(None == inches.delta(&first_down));
|
||||||
assert!(-10_i8 == goal_line.delta(&second_down).unwrap());
|
assert!(-10_i8 == inches.delta(&second_down).unwrap());
|
||||||
assert!(-13_i8 == goal_line.delta(&third_down).unwrap());
|
assert!(-13_i8 == inches.delta(&third_down).unwrap());
|
||||||
assert!(-5_i8 == goal_line.delta(&fourth_down).unwrap());
|
assert!(-5_i8 == inches.delta(&fourth_down).unwrap());
|
||||||
assert!(None == inches.delta(&turnover));
|
assert!(None == inches.delta(&turnover));
|
||||||
assert!(None == inches.delta(&penalty));
|
assert!(None == inches.delta(&penalty));
|
||||||
assert!(None == inches.delta(&goal_line));
|
assert!(None == inches.delta(&goal_line));
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use crate::{Event, Period, Team, error};
|
use crate::{Event, Quarter, Team, error};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
pub struct Game {
|
pub struct Game {
|
||||||
pub version: semver::Version,
|
pub version: semver::Version,
|
||||||
pub flags: Vec<Flags>,
|
pub flags: Vec<Flags>,
|
||||||
pub periods: Vec<Period>,
|
pub events: Vec<Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Game {
|
impl Game {
|
||||||
@@ -25,12 +26,10 @@ impl Game {
|
|||||||
|
|
||||||
let mut teams = vec![];
|
let mut teams = vec![];
|
||||||
|
|
||||||
self.periods.iter().for_each(|period| {
|
self.events.iter().for_each(|event| {
|
||||||
for event in period.events.iter() {
|
if let Ok(team) = event.team() {
|
||||||
if let Ok(team) = event.team() {
|
if !ignore.contains(&team) && !teams.contains(&team) {
|
||||||
if !ignore.contains(&team) && !teams.contains(&team) {
|
teams.push(team)
|
||||||
teams.push(team)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -43,12 +42,17 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deltas(&self, team: Team) -> Vec<i8> {
|
pub fn deltas(&self, team: Team) -> Vec<i8> {
|
||||||
let events = self
|
let events: Vec<Event> = self
|
||||||
.periods
|
.team_events(team)
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|period| Some(period.team_events(team.to_owned(), None).ok().unwrap()))
|
.filter_map(|event| {
|
||||||
.collect::<Vec<Vec<Event>>>()
|
if let Event::Quarter(_) = event {
|
||||||
.concat();
|
None
|
||||||
|
} else {
|
||||||
|
Some(event.to_owned())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
let len = events.len() - 1;
|
let len = 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![];
|
||||||
@@ -65,33 +69,30 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn team_plays(&self, team: Team) -> usize {
|
pub fn team_plays(&self, team: Team) -> usize {
|
||||||
self.periods
|
self.team_events(team)
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|period| {
|
.filter_map(|event| {
|
||||||
if !period.is_overtime() {
|
if let Event::Play(_) = event {
|
||||||
let plays = period.team_plays(team.to_owned(), None);
|
Some(event)
|
||||||
Some(plays.unwrap().len())
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<usize>>()
|
.collect::<Vec<&Event>>()
|
||||||
.iter()
|
.len()
|
||||||
.sum::<usize>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The average number of plays in a quarter.
|
/// 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 {
|
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 periods: Vec<Period> = Quarter::iter()
|
||||||
|
.filter_map(|quarter| Some(self.to_owned().get_period(quarter.to_owned())).to_owned())
|
||||||
|
.collect();
|
||||||
|
|
||||||
let quarterly_avgs: Vec<f32> = self
|
let quarterly_avgs: Vec<f32> = periods
|
||||||
.periods
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|period| {
|
.filter_map(|period| {
|
||||||
if !period.is_overtime() {
|
if !period.is_overtime() {
|
||||||
let plays = period.team_plays(team.to_owned(), None);
|
Some(period.team_plays(team.to_owned()) as f32)
|
||||||
Some(plays.unwrap().len() as f32 / period.quarters().len() as f32)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -142,36 +143,150 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn penalties(&self, team: Team) -> usize {
|
pub fn penalties(&self, team: Team) -> usize {
|
||||||
self.periods
|
self.team_events(team)
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|period| {
|
.filter_map(|event| {
|
||||||
Some(
|
if let Event::Penalty(_) = event {
|
||||||
period
|
Some(event.to_owned())
|
||||||
.team_events(team.to_owned(), None)
|
} else {
|
||||||
.ok()?
|
None
|
||||||
.iter()
|
}
|
||||||
.filter_map(|event| {
|
|
||||||
if let Event::Penalty(_) = event {
|
|
||||||
Some(event.to_owned())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<Event>>(),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<Vec<Event>>>()
|
.collect::<Vec<Event>>()
|
||||||
.concat()
|
|
||||||
.len()
|
.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_period(&self, quarter: Quarter) -> Period {
|
||||||
|
let mut record = false;
|
||||||
|
|
||||||
|
Period {
|
||||||
|
period: quarter.to_owned(),
|
||||||
|
events: self
|
||||||
|
.events
|
||||||
|
.iter()
|
||||||
|
.filter_map(|event| {
|
||||||
|
if let Event::Quarter(_) = event {
|
||||||
|
record = Event::Quarter(quarter.to_owned()) == *event;
|
||||||
|
}
|
||||||
|
|
||||||
|
if record {
|
||||||
|
return Some(event.to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.collect::<Vec<Event>>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn team_events(&self, team: Team) -> Vec<Event> {
|
||||||
|
let mut events: Vec<Event> = vec![];
|
||||||
|
let mut first = true;
|
||||||
|
let mut record: bool = true;
|
||||||
|
|
||||||
|
self.events.iter().for_each(|event| {
|
||||||
|
if let Event::Kickoff(_) | Event::Turnover(_) = event {
|
||||||
|
record = {
|
||||||
|
if team == event.team().unwrap() {
|
||||||
|
// Wipe events vec if the start of quarter was opposition
|
||||||
|
// on offence.
|
||||||
|
if first {
|
||||||
|
events = vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
events.push(event.to_owned());
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if record {
|
||||||
|
events.push(event.to_owned());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// If already handled or assumption override applicable
|
||||||
|
events
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Period {
|
||||||
|
period: Quarter,
|
||||||
|
events: Vec<Event>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Period {
|
||||||
|
pub fn team_events(&self, team: Team) -> Vec<Event> {
|
||||||
|
let mut events: Vec<Event> = vec![];
|
||||||
|
let mut first = true;
|
||||||
|
let mut record: bool = true;
|
||||||
|
|
||||||
|
self.events.iter().for_each(|event| {
|
||||||
|
if let Event::Kickoff(_) | Event::Turnover(_) = event {
|
||||||
|
record = {
|
||||||
|
if team == event.team().unwrap() {
|
||||||
|
// Wipe events vec if the start of quarter was opposition
|
||||||
|
// on offence.
|
||||||
|
if first {
|
||||||
|
events = vec![];
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
events.push(event.to_owned());
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if record {
|
||||||
|
events.push(event.to_owned());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
events
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn team_plays(&self, team: Team) -> usize {
|
||||||
|
self.team_events(team)
|
||||||
|
.iter()
|
||||||
|
.filter_map(|event| {
|
||||||
|
if let Event::Play(_) = event {
|
||||||
|
Some(event)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<&Event>>()
|
||||||
|
.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_overtime(&self) -> bool {
|
||||||
|
if let Quarter::Overtime(_) = self.period {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
||||||
pub enum Flags {
|
pub enum Flags {
|
||||||
|
IgnoreActions,
|
||||||
IgnoreTeam(Team),
|
IgnoreTeam(Team),
|
||||||
IgnoreScore,
|
IgnoreScore,
|
||||||
|
Interval(u8),
|
||||||
|
SheerDumbFuckingLuck
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::*;
|
use crate::*;
|
||||||
@@ -181,30 +296,20 @@ mod tests {
|
|||||||
let a = Game {
|
let a = Game {
|
||||||
version: crate::MIN_VER,
|
version: crate::MIN_VER,
|
||||||
flags: vec![],
|
flags: vec![],
|
||||||
periods: vec![
|
events: vec![
|
||||||
Period {
|
Event::Quarter(Quarter::First),
|
||||||
start: Quarter::First,
|
Event::Kickoff(Team::Nebraska),
|
||||||
end: None,
|
Event::Play(Play::default()),
|
||||||
events: vec![
|
Event::Turnover(Team::ArizonaState),
|
||||||
Event::Kickoff(Team::Nebraska),
|
Event::Quarter(Quarter::Second),
|
||||||
Event::Play(Play::default()),
|
Event::Turnover(Team::Nebraska),
|
||||||
Event::Turnover(Team::ArizonaState),
|
Event::Play(Play::default()),
|
||||||
],
|
Event::Play(Play::default()),
|
||||||
},
|
Event::Play(Play::default()),
|
||||||
Period {
|
Event::Play(Play::default()),
|
||||||
start: Quarter::Second,
|
Event::Play(Play::default()),
|
||||||
end: Some(Quarter::Fourth),
|
Event::Play(Play::default()),
|
||||||
events: vec![
|
Event::Turnover(Team::ArizonaState),
|
||||||
Event::Turnover(Team::Nebraska),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Turnover(Team::ArizonaState),
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -403,7 +508,149 @@ mod tests {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(dbg!(game.deltas(Team::Nebraska)) == vec![10_i8, -3_i8, 5_i8, -2_i8, 12_i8]);
|
assert!(game.deltas(Team::Nebraska) == vec![10_i8, -3_i8, 5_i8, -2_i8, 12_i8]);
|
||||||
assert!(dbg!(game.deltas(Team::ArizonaState)) == vec![10_i8, 0_i8]);
|
assert!(game.deltas(Team::ArizonaState) == vec![10_i8, 0_i8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn team_events() {
|
||||||
|
let a = Period {
|
||||||
|
start: Quarter::First,
|
||||||
|
end: None,
|
||||||
|
events: vec![
|
||||||
|
Event::Kickoff(Team::Nebraska),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Turnover(Team::ArizonaState),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Kickoff(Team::Nebraska),
|
||||||
|
Event::Score(ScorePoints::Touchdown),
|
||||||
|
Event::Kickoff(Team::SouthCarolina),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let b = Period {
|
||||||
|
start: Quarter::Second,
|
||||||
|
end: None,
|
||||||
|
events: vec![
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Turnover(Team::SouthCarolina),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let c = Period {
|
||||||
|
start: Quarter::Second,
|
||||||
|
end: None,
|
||||||
|
events: vec![
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Turnover(Team::Nebraska),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
let d = Period {
|
||||||
|
start: Quarter::Second,
|
||||||
|
end: None,
|
||||||
|
events: vec![Event::Play(Play::default())],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
a.team_events(Team::Nebraska, None).unwrap()
|
||||||
|
== vec![
|
||||||
|
Event::Kickoff(Team::Nebraska),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Turnover(Team::ArizonaState),
|
||||||
|
Event::Kickoff(Team::Nebraska),
|
||||||
|
Event::Score(ScorePoints::Touchdown),
|
||||||
|
Event::Kickoff(Team::SouthCarolina),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
b.team_events(Team::Nebraska, None).unwrap()
|
||||||
|
== vec![
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Turnover(Team::SouthCarolina)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
c.team_events(Team::Nebraska, None).unwrap() == vec![Event::Turnover(Team::Nebraska)]
|
||||||
|
);
|
||||||
|
assert!(true == d.team_events(Team::Nebraska, None).is_err());
|
||||||
|
assert!(false == d.team_events(Team::Nebraska, Some(true)).is_err())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn team_plays() {
|
||||||
|
let period = Period {
|
||||||
|
start: Quarter::First,
|
||||||
|
end: None,
|
||||||
|
events: vec![
|
||||||
|
Event::Kickoff(Team::Nebraska),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Turnover(Team::ArizonaState),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Kickoff(Team::Nebraska),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Score(ScorePoints::default()),
|
||||||
|
Event::Kickoff(Team::SouthCarolina),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
Event::Turnover(Team::Nebraska),
|
||||||
|
Event::Play(Play::default()),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
period.team_plays(Team::Nebraska, None).unwrap()
|
||||||
|
== vec![Play::default(), Play::default(), Play::default()]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quarters() {
|
||||||
|
let first = Period {
|
||||||
|
start: Quarter::First,
|
||||||
|
end: None,
|
||||||
|
events: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let second_fourth = Period {
|
||||||
|
start: Quarter::Second,
|
||||||
|
end: Some(Quarter::Fourth),
|
||||||
|
events: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let third_ot_three = Period {
|
||||||
|
start: Quarter::Third,
|
||||||
|
end: Some(Quarter::Overtime(3)),
|
||||||
|
events: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let ot_one_three = Period {
|
||||||
|
start: Quarter::Overtime(1),
|
||||||
|
end: Some(Quarter::Overtime(3)),
|
||||||
|
events: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(first.quarters() == vec![Quarter::First]);
|
||||||
|
assert!(second_fourth.quarters() == vec![Quarter::Second, Quarter::Third, Quarter::Fourth]);
|
||||||
|
assert!(
|
||||||
|
third_ot_three.quarters()
|
||||||
|
== vec![
|
||||||
|
Quarter::Third,
|
||||||
|
Quarter::Fourth,
|
||||||
|
Quarter::Overtime(1),
|
||||||
|
Quarter::Overtime(2),
|
||||||
|
Quarter::Overtime(3)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
ot_one_three.quarters()
|
||||||
|
== vec![
|
||||||
|
Quarter::Overtime(1),
|
||||||
|
Quarter::Overtime(2),
|
||||||
|
Quarter::Overtime(3)
|
||||||
|
]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
mod action;
|
mod action;
|
||||||
mod error;
|
mod error;
|
||||||
|
#[allow(deprecated)]
|
||||||
mod event;
|
mod event;
|
||||||
mod file;
|
mod file;
|
||||||
mod game;
|
mod game;
|
||||||
mod period;
|
mod period;
|
||||||
#[allow(deprecated)]
|
|
||||||
mod play;
|
mod play;
|
||||||
mod terrain;
|
mod terrain;
|
||||||
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub const MIN_VER: semver::Version = semver::Version::new(0, 5, 0);
|
pub const MIN_VER: semver::Version = semver::Version::new(0, 7, 0);
|
||||||
|
|
||||||
// I'm lazy.
|
// I'm lazy.
|
||||||
pub use action::*;
|
pub use action::*;
|
||||||
|
|||||||
@@ -1,129 +1,7 @@
|
|||||||
use crate::{Event, Play, Team, error};
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use strum::EnumIter;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone, PartialEq, EnumIter)]
|
||||||
pub struct Period {
|
|
||||||
pub start: Quarter,
|
|
||||||
pub end: Option<Quarter>,
|
|
||||||
pub events: Vec<Event>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Period {
|
|
||||||
pub fn team_events(
|
|
||||||
&self,
|
|
||||||
team: Team,
|
|
||||||
assume_team_known: Option<bool>,
|
|
||||||
) -> Result<Vec<Event>, error::CannotDetermineTeams> {
|
|
||||||
let mut events: Vec<Event> = vec![];
|
|
||||||
let mut first = true;
|
|
||||||
let mut record: bool = true;
|
|
||||||
let assume_team_known = assume_team_known.unwrap_or(false);
|
|
||||||
|
|
||||||
for event in self.events.iter() {
|
|
||||||
if let Event::Kickoff(_) | Event::Turnover(_) = event {
|
|
||||||
record = {
|
|
||||||
if team == event.team().unwrap() {
|
|
||||||
// Wipe events vec if the start of quarter was opposition
|
|
||||||
// on offence.
|
|
||||||
if first {
|
|
||||||
events = vec![];
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
events.push(event.to_owned());
|
|
||||||
false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if record {
|
|
||||||
events.push(event.to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If already handled or assumption override applicable
|
|
||||||
if !first || (first && assume_team_known) {
|
|
||||||
Ok(events)
|
|
||||||
} else {
|
|
||||||
Err(error::CannotDetermineTeams)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn team_plays(
|
|
||||||
&self,
|
|
||||||
team: Team,
|
|
||||||
assume_team_known: Option<bool>,
|
|
||||||
) -> Result<Vec<Play>, error::CannotDetermineTeams> {
|
|
||||||
Ok(self
|
|
||||||
.team_events(team, assume_team_known)?
|
|
||||||
.iter()
|
|
||||||
.filter_map(|event| {
|
|
||||||
if let Event::Play(play) = event {
|
|
||||||
Some(play.to_owned())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn quarters(&self) -> Vec<Quarter> {
|
|
||||||
let mut quarters: Vec<Quarter> = vec![self.start.to_owned()];
|
|
||||||
|
|
||||||
if self.end.is_none() {
|
|
||||||
return quarters;
|
|
||||||
}
|
|
||||||
|
|
||||||
let order = vec![
|
|
||||||
Quarter::First,
|
|
||||||
Quarter::Second,
|
|
||||||
Quarter::Third,
|
|
||||||
Quarter::Fourth,
|
|
||||||
];
|
|
||||||
|
|
||||||
let start = if let Quarter::Overtime(x) = self.start {
|
|
||||||
(3 + x) as usize
|
|
||||||
} else {
|
|
||||||
order.iter().position(|q| q == &self.start).unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let end = if let Quarter::Overtime(x) = self.end.as_ref().unwrap() {
|
|
||||||
(3 + x) as usize
|
|
||||||
} else {
|
|
||||||
order
|
|
||||||
.iter()
|
|
||||||
.position(|q| q == self.end.as_ref().unwrap())
|
|
||||||
.unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let range: Vec<usize> = ((start + 1)..=end).collect();
|
|
||||||
|
|
||||||
for i in range {
|
|
||||||
quarters.push(match i {
|
|
||||||
0 => Quarter::First,
|
|
||||||
1 => Quarter::Second,
|
|
||||||
2 => Quarter::Third,
|
|
||||||
3 => Quarter::Fourth,
|
|
||||||
_ => Quarter::Overtime((i - 3) as u8),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
quarters
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_overtime(&self) -> bool {
|
|
||||||
if self.start.is_overtime() || self.end.as_ref().is_some_and(|some| some.is_overtime()) {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
|
||||||
pub enum Quarter {
|
pub enum Quarter {
|
||||||
First,
|
First,
|
||||||
Second,
|
Second,
|
||||||
@@ -131,159 +9,3 @@ pub enum Quarter {
|
|||||||
Fourth,
|
Fourth,
|
||||||
Overtime(u8),
|
Overtime(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Quarter {
|
|
||||||
pub fn is_overtime(&self) -> bool {
|
|
||||||
if let Self::Overtime(_) = self {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn team_events() {
|
|
||||||
let a = Period {
|
|
||||||
start: Quarter::First,
|
|
||||||
end: None,
|
|
||||||
events: vec![
|
|
||||||
Event::Kickoff(Team::Nebraska),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Turnover(Team::ArizonaState),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Kickoff(Team::Nebraska),
|
|
||||||
Event::Score(ScorePoints::Touchdown),
|
|
||||||
Event::Kickoff(Team::SouthCarolina),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
let b = Period {
|
|
||||||
start: Quarter::Second,
|
|
||||||
end: None,
|
|
||||||
events: vec![
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Turnover(Team::SouthCarolina),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
let c = Period {
|
|
||||||
start: Quarter::Second,
|
|
||||||
end: None,
|
|
||||||
events: vec![
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Turnover(Team::Nebraska),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
let d = Period {
|
|
||||||
start: Quarter::Second,
|
|
||||||
end: None,
|
|
||||||
events: vec![Event::Play(Play::default())],
|
|
||||||
};
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
a.team_events(Team::Nebraska, None).unwrap()
|
|
||||||
== vec![
|
|
||||||
Event::Kickoff(Team::Nebraska),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Turnover(Team::ArizonaState),
|
|
||||||
Event::Kickoff(Team::Nebraska),
|
|
||||||
Event::Score(ScorePoints::Touchdown),
|
|
||||||
Event::Kickoff(Team::SouthCarolina),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
b.team_events(Team::Nebraska, None).unwrap()
|
|
||||||
== vec![
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Turnover(Team::SouthCarolina)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
c.team_events(Team::Nebraska, None).unwrap() == vec![Event::Turnover(Team::Nebraska)]
|
|
||||||
);
|
|
||||||
assert!(true == d.team_events(Team::Nebraska, None).is_err());
|
|
||||||
assert!(false == d.team_events(Team::Nebraska, Some(true)).is_err())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn team_plays() {
|
|
||||||
let period = Period {
|
|
||||||
start: Quarter::First,
|
|
||||||
end: None,
|
|
||||||
events: vec![
|
|
||||||
Event::Kickoff(Team::Nebraska),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Turnover(Team::ArizonaState),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Kickoff(Team::Nebraska),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Score(ScorePoints::default()),
|
|
||||||
Event::Kickoff(Team::SouthCarolina),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
Event::Turnover(Team::Nebraska),
|
|
||||||
Event::Play(Play::default()),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
period.team_plays(Team::Nebraska, None).unwrap()
|
|
||||||
== vec![Play::default(), Play::default(), Play::default()]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn quarters() {
|
|
||||||
let first = Period {
|
|
||||||
start: Quarter::First,
|
|
||||||
end: None,
|
|
||||||
events: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
let second_fourth = Period {
|
|
||||||
start: Quarter::Second,
|
|
||||||
end: Some(Quarter::Fourth),
|
|
||||||
events: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
let third_ot_three = Period {
|
|
||||||
start: Quarter::Third,
|
|
||||||
end: Some(Quarter::Overtime(3)),
|
|
||||||
events: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
let ot_one_three = Period {
|
|
||||||
start: Quarter::Overtime(1),
|
|
||||||
end: Some(Quarter::Overtime(3)),
|
|
||||||
events: vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
assert!(first.quarters() == vec![Quarter::First]);
|
|
||||||
assert!(second_fourth.quarters() == vec![Quarter::Second, Quarter::Third, Quarter::Fourth]);
|
|
||||||
assert!(
|
|
||||||
third_ot_three.quarters()
|
|
||||||
== vec![
|
|
||||||
Quarter::Third,
|
|
||||||
Quarter::Fourth,
|
|
||||||
Quarter::Overtime(1),
|
|
||||||
Quarter::Overtime(2),
|
|
||||||
Quarter::Overtime(3)
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
ot_one_three.quarters()
|
|
||||||
== vec![
|
|
||||||
Quarter::Overtime(1),
|
|
||||||
Quarter::Overtime(2),
|
|
||||||
Quarter::Overtime(3)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -26,16 +26,3 @@ pub enum Down {
|
|||||||
Third,
|
Third,
|
||||||
Fourth,
|
Fourth,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, PartialEq)]
|
|
||||||
pub enum Team {
|
|
||||||
ArizonaState,
|
|
||||||
#[deprecated(since = "0.2.0", note = "Team left the project.")]
|
|
||||||
BoiseState,
|
|
||||||
Colorado,
|
|
||||||
Iowa,
|
|
||||||
Nebraska,
|
|
||||||
SouthCarolina,
|
|
||||||
Syracuse,
|
|
||||||
TexasAnM,
|
|
||||||
}
|
|
||||||
|
|||||||
535
miller/Cargo.lock
generated
535
miller/Cargo.lock
generated
@@ -2,12 +2,24 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "allocator-api2"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle"
|
name = "anstyle"
|
||||||
version = "1.0.10"
|
version = "1.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.22.1"
|
version = "0.22.1"
|
||||||
@@ -23,6 +35,27 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cassowary"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "castaway"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
|
||||||
|
dependencies = [
|
||||||
|
"rustversion",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.32"
|
version = "4.5.32"
|
||||||
@@ -62,14 +95,133 @@ version = "0.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "compact_str"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32"
|
||||||
|
dependencies = [
|
||||||
|
"castaway",
|
||||||
|
"cfg-if",
|
||||||
|
"itoa",
|
||||||
|
"rustversion",
|
||||||
|
"ryu",
|
||||||
|
"static_assertions",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossterm"
|
||||||
|
version = "0.28.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"crossterm_winapi",
|
||||||
|
"mio",
|
||||||
|
"parking_lot",
|
||||||
|
"rustix",
|
||||||
|
"signal-hook",
|
||||||
|
"signal-hook-mio",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossterm_winapi"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gamelog"
|
name = "gamelog"
|
||||||
version = "0.5.0"
|
version = "0.7.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ron",
|
"ron",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"strum",
|
"strum 0.27.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||||
|
dependencies = [
|
||||||
|
"allocator-api2",
|
||||||
|
"equivalent",
|
||||||
|
"foldhash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -78,14 +230,133 @@ version = "0.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indoc"
|
||||||
|
version = "2.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instability"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"indoc",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.171"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.4.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.27"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lru"
|
||||||
|
version = "0.12.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||||
|
dependencies = [
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miller"
|
name = "miller"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"gamelog",
|
"gamelog",
|
||||||
|
"ratatui",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mio"
|
||||||
|
version = "1.0.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"wasi",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.9.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.94"
|
version = "1.0.94"
|
||||||
@@ -104,6 +375,36 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ratatui"
|
||||||
|
version = "0.29.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cassowary",
|
||||||
|
"compact_str",
|
||||||
|
"crossterm",
|
||||||
|
"indoc",
|
||||||
|
"instability",
|
||||||
|
"itertools",
|
||||||
|
"lru",
|
||||||
|
"paste",
|
||||||
|
"strum 0.26.3",
|
||||||
|
"unicode-segmentation",
|
||||||
|
"unicode-truncate",
|
||||||
|
"unicode-width 0.2.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.5.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ron"
|
name = "ron"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -117,12 +418,37 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.38.44"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ryu"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.26"
|
version = "1.0.26"
|
||||||
@@ -152,19 +478,83 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"signal-hook-registry",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-mio"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"mio",
|
||||||
|
"signal-hook",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signal-hook-registry"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "static_assertions"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum"
|
||||||
|
version = "0.26.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
|
||||||
|
dependencies = [
|
||||||
|
"strum_macros 0.26.4",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum"
|
name = "strum"
|
||||||
version = "0.27.1"
|
version = "0.27.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
|
checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"strum_macros",
|
"strum_macros 0.27.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strum_macros"
|
||||||
|
version = "0.26.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -196,3 +586,142 @@ name = "unicode-ident"
|
|||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-segmentation"
|
||||||
|
version = "1.12.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-truncate"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
|
||||||
|
dependencies = [
|
||||||
|
"itertools",
|
||||||
|
"unicode-segmentation",
|
||||||
|
"unicode-width 0.1.14",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.59.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_gnullvm",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.52.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ratatui = "0.29"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "4.5"
|
version = "4.5"
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
mod tui;
|
||||||
|
|
||||||
use clap::{ArgAction, Parser};
|
use clap::{ArgAction, Parser};
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use gamelog::{Action, Flags, Key, LogFile, Team};
|
use gamelog::{Action, Down, Flags, Key, LogFile, Team};
|
||||||
use std::path::PathBuf;
|
use std::{io, path::PathBuf, sync::mpsc, thread};
|
||||||
|
use tui::App;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[clap(author, version, about)]
|
#[clap(author, version, about)]
|
||||||
@@ -11,22 +14,19 @@ struct Args {
|
|||||||
short,
|
short,
|
||||||
long,
|
long,
|
||||||
value_hint = clap::ValueHint::DirPath,
|
value_hint = clap::ValueHint::DirPath,
|
||||||
default_value = format!("{}/../templates/logfile.ron", std::env::current_dir()
|
default_value = format!("../templates/logfile.ron")
|
||||||
.expect("Failed to get current working dir.")
|
|
||||||
.into_os_string()
|
|
||||||
.to_str()
|
|
||||||
.unwrap())
|
|
||||||
)]
|
)]
|
||||||
logfile_path: PathBuf,
|
logfile_path: PathBuf,
|
||||||
|
|
||||||
// Behaviour is backwards.
|
// Behaviour is backwards.
|
||||||
// ArgAction::SetFalse by default evaluates to true,
|
// ArgAction::SetFalse by default evaluates to true,
|
||||||
// ArgAction::SetTrue by default evaluates to false.
|
// ArgAction::SetTrue by default evaluates to false.
|
||||||
#[arg(short, long, action=ArgAction::SetFalse)]
|
/// Provide flag to disable tui and dump info via Debug pretty printing.
|
||||||
display_results: bool,
|
#[arg(short, long, action=ArgAction::SetTrue)]
|
||||||
|
no_tui: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> io::Result<()> {
|
||||||
let config = Args::parse();
|
let config = Args::parse();
|
||||||
|
|
||||||
let log: LogFile = match LogFile::try_from(config.logfile_path) {
|
let log: LogFile = match LogFile::try_from(config.logfile_path) {
|
||||||
@@ -34,67 +34,85 @@ fn main() {
|
|||||||
Err(err) => panic!("Error: Failed to open logfile: {:?}", err),
|
Err(err) => panic!("Error: Failed to open logfile: {:?}", err),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut stats = vec![
|
if config.no_tui {
|
||||||
TeamStats::new(Team::ArizonaState),
|
let mut stats = vec![
|
||||||
#[allow(deprecated)]
|
TeamStats::new(Team::ArizonaState),
|
||||||
TeamStats::new(Team::BoiseState),
|
#[allow(deprecated)]
|
||||||
TeamStats::new(Team::Colorado),
|
TeamStats::new(Team::BoiseState),
|
||||||
TeamStats::new(Team::Iowa),
|
TeamStats::new(Team::Colorado),
|
||||||
TeamStats::new(Team::Nebraska),
|
TeamStats::new(Team::Iowa),
|
||||||
TeamStats::new(Team::Syracuse),
|
TeamStats::new(Team::Nebraska),
|
||||||
TeamStats::new(Team::SouthCarolina),
|
TeamStats::new(Team::Syracuse),
|
||||||
TeamStats::new(Team::TexasAnM),
|
TeamStats::new(Team::SouthCarolina),
|
||||||
];
|
TeamStats::new(Team::TexasAnM),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Work on knocking down the nesting here?
|
||||||
|
for game in log.0.iter() {
|
||||||
|
let teams = match game.teams() {
|
||||||
|
Ok(teams) => teams,
|
||||||
|
Err(_) => continue,
|
||||||
|
};
|
||||||
|
|
||||||
// Work on knocking down the nesting here?
|
|
||||||
for game in log.0.iter() {
|
|
||||||
if let Ok(teams) = game.teams() {
|
|
||||||
for team in teams {
|
for team in teams {
|
||||||
if !game.flags.contains(&Flags::IgnoreTeam(team.to_owned())) {
|
// Skip team if they are to be ignored this game.
|
||||||
// Team is to have their stats recorded this game of file.
|
if game.flags.contains(&Flags::IgnoreTeam(team.to_owned())) {
|
||||||
let team_idx = stats
|
continue;
|
||||||
.iter()
|
|
||||||
.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()));
|
|
||||||
|
|
||||||
stats[team_idx]
|
|
||||||
.plays_per_game
|
|
||||||
.push(game.team_plays(team.to_owned()));
|
|
||||||
|
|
||||||
stats[team_idx]
|
|
||||||
.penalties_per_game
|
|
||||||
.push(game.penalties(team.to_owned()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let team_idx = stats
|
||||||
|
.iter()
|
||||||
|
.position(|stat| stat.team == team.to_owned())
|
||||||
|
.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()));
|
||||||
|
|
||||||
|
stats[team_idx]
|
||||||
|
.plays_per_game
|
||||||
|
.push(game.team_plays(team.to_owned()));
|
||||||
|
|
||||||
|
stats[team_idx]
|
||||||
|
.penalties_per_game
|
||||||
|
.push(game.penalties(team.to_owned()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if dbg!(config.display_results) {
|
|
||||||
// :#? for pretty-printing.
|
// :#? for pretty-printing.
|
||||||
stats.iter().for_each(|team| println!("{:#?}", team));
|
stats.iter().for_each(|team| println!("{:#?}", team));
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut app = App { exit: false };
|
||||||
|
|
||||||
|
// Enter Raw terminal mode.
|
||||||
|
let mut terminal = ratatui::init();
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel::<tui::Event>();
|
||||||
|
|
||||||
|
let tx_input_fetcher = tx.clone();
|
||||||
|
thread::spawn(move || tui::input_fetcher(tx_input_fetcher));
|
||||||
|
|
||||||
|
let app_result = app.run(&mut terminal, rx);
|
||||||
|
|
||||||
|
// Exit Raw terminal mode.
|
||||||
|
ratatui::restore();
|
||||||
|
|
||||||
|
app_result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -117,6 +135,9 @@ struct TeamStats {
|
|||||||
least_common_play: Option<Action>,
|
least_common_play: Option<Action>,
|
||||||
most_common_key: Option<Key>,
|
most_common_key: Option<Key>,
|
||||||
least_common_key: Option<Key>,
|
least_common_key: Option<Key>,
|
||||||
|
// Traits
|
||||||
|
// Typical number of downs to achieve 10 yards.
|
||||||
|
time_to_first_down: Option<Down>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TeamStats {
|
impl TeamStats {
|
||||||
@@ -135,6 +156,7 @@ impl TeamStats {
|
|||||||
least_common_play: None,
|
least_common_play: None,
|
||||||
most_common_key: None,
|
most_common_key: None,
|
||||||
least_common_key: None,
|
least_common_key: None,
|
||||||
|
time_to_first_down: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
173
miller/src/tui.rs
Normal file
173
miller/src/tui.rs
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
use std::{io, sync::mpsc};
|
||||||
|
|
||||||
|
use ratatui::{
|
||||||
|
DefaultTerminal, Frame,
|
||||||
|
crossterm::{
|
||||||
|
self,
|
||||||
|
event::{KeyCode, KeyEventKind},
|
||||||
|
},
|
||||||
|
layout::{Constraint, Layout},
|
||||||
|
style::Color as Colour,
|
||||||
|
symbols::border,
|
||||||
|
text::Line,
|
||||||
|
widgets::{Block, Widget},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum Event {
|
||||||
|
Input(crossterm::event::KeyEvent),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct App {
|
||||||
|
pub exit: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn run(
|
||||||
|
&mut self,
|
||||||
|
terminal: &mut DefaultTerminal,
|
||||||
|
rx: mpsc::Receiver<Event>,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
while !self.exit {
|
||||||
|
// Render frame.
|
||||||
|
terminal.draw(|frame| self.draw(frame))?;
|
||||||
|
|
||||||
|
// Event handler
|
||||||
|
// unwraps, bc what could go wrong?
|
||||||
|
match rx.recv().unwrap() {
|
||||||
|
Event::Input(key_event) => self.handle_key_event(key_event)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&self, frame: &mut Frame) {
|
||||||
|
frame.render_widget(self, frame.area());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_key_event(&mut self, key_event: crossterm::event::KeyEvent) -> io::Result<()> {
|
||||||
|
if key_event.kind == KeyEventKind::Press && key_event.code == KeyCode::Char('q') {
|
||||||
|
self.exit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl on ref to avoid accidentally mutating the struct.
|
||||||
|
impl Widget for &App {
|
||||||
|
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let [teams_area, main_area, instruction_area] =
|
||||||
|
Layout::vertical([Constraint::Max(3), Constraint::Fill(1), Constraint::Max(1)])
|
||||||
|
.areas(area);
|
||||||
|
|
||||||
|
let [left_area, right_area] =
|
||||||
|
Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||||
|
.areas(main_area);
|
||||||
|
|
||||||
|
let [upper_left_area, common_play_area, common_config_area] = Layout::vertical([
|
||||||
|
Constraint::Percentage(60),
|
||||||
|
Constraint::Percentage(20),
|
||||||
|
Constraint::Percentage(20),
|
||||||
|
])
|
||||||
|
.areas(left_area);
|
||||||
|
|
||||||
|
let [quicks_area, pattern_area] =
|
||||||
|
Layout::horizontal([Constraint::Percentage(60), Constraint::Percentage(40)])
|
||||||
|
.areas(upper_left_area);
|
||||||
|
|
||||||
|
let [trends_area, graph_area, lower_right_area] = Layout::vertical([
|
||||||
|
Constraint::Percentage(20),
|
||||||
|
Constraint::Percentage(55),
|
||||||
|
Constraint::Percentage(25),
|
||||||
|
])
|
||||||
|
.areas(right_area);
|
||||||
|
|
||||||
|
let [legend_area, _, right_lower_right_area] = Layout::horizontal([
|
||||||
|
Constraint::Percentage(40),
|
||||||
|
Constraint::Percentage(30),
|
||||||
|
Constraint::Percentage(30),
|
||||||
|
])
|
||||||
|
.areas(lower_right_area);
|
||||||
|
|
||||||
|
let [_, compare_area] =
|
||||||
|
Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)])
|
||||||
|
.areas(right_lower_right_area);
|
||||||
|
|
||||||
|
let teams_block = Block::bordered()
|
||||||
|
.title(Line::from(" Teams "))
|
||||||
|
.border_set(border::THICK);
|
||||||
|
teams_block.render(teams_area, buf);
|
||||||
|
|
||||||
|
let instructions = Line::from(vec![
|
||||||
|
" ".into(),
|
||||||
|
"Quit <q>".into(),
|
||||||
|
" | ".into(),
|
||||||
|
"Function <a>".into(),
|
||||||
|
" | ".into(),
|
||||||
|
"Function <b>".into(),
|
||||||
|
" | ".into(),
|
||||||
|
"Function <c>".into(),
|
||||||
|
" | ".into(),
|
||||||
|
"Function <d>".into(),
|
||||||
|
" | ".into(),
|
||||||
|
"Function <e>".into(),
|
||||||
|
" | ".into(),
|
||||||
|
"Function <f>".into(),
|
||||||
|
" | ".into(),
|
||||||
|
"Function <g>".into(),
|
||||||
|
]);
|
||||||
|
instructions.render(instruction_area, buf);
|
||||||
|
|
||||||
|
let quicks_block = Block::bordered()
|
||||||
|
.title(" Quicks ")
|
||||||
|
.border_set(border::THICK);
|
||||||
|
quicks_block.render(quicks_area, buf);
|
||||||
|
|
||||||
|
let pattern_block = Block::bordered()
|
||||||
|
.title(" Pattern ")
|
||||||
|
.border_set(border::THICK);
|
||||||
|
pattern_block.render(pattern_area, buf);
|
||||||
|
|
||||||
|
let common_play_block = Block::bordered()
|
||||||
|
.title(" Most Freq. Play ")
|
||||||
|
.border_set(border::THICK);
|
||||||
|
common_play_block.render(common_play_area, buf);
|
||||||
|
|
||||||
|
let common_config_block = Block::bordered()
|
||||||
|
.title(" Most Freq. Configuration ")
|
||||||
|
.border_set(border::THICK);
|
||||||
|
common_config_block.render(common_config_area, buf);
|
||||||
|
|
||||||
|
let trends_block = Block::bordered()
|
||||||
|
.title(" Trends ")
|
||||||
|
.border_set(border::THICK);
|
||||||
|
trends_block.render(trends_area, buf);
|
||||||
|
|
||||||
|
let graph_block = Block::bordered().title(" Graph ").border_set(border::THICK);
|
||||||
|
graph_block.render(graph_area, buf);
|
||||||
|
|
||||||
|
let legend_block = Block::bordered()
|
||||||
|
.title(" Legend ")
|
||||||
|
.border_set(border::THICK);
|
||||||
|
legend_block.render(legend_area, buf);
|
||||||
|
|
||||||
|
let compare_block = Block::bordered()
|
||||||
|
.title(" Compare ")
|
||||||
|
.border_set(border::THICK);
|
||||||
|
compare_block.render(compare_area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input_fetcher(tx: mpsc::Sender<Event>) {
|
||||||
|
loop {
|
||||||
|
// unwraps, bc what could go wrong?
|
||||||
|
match crossterm::event::read().unwrap() {
|
||||||
|
crossterm::event::Event::Key(key_event) => tx.send(Event::Input(key_event)).unwrap(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
zed_settings.jsonc
Normal file
52
zed_settings.jsonc
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Zed settings
|
||||||
|
//
|
||||||
|
// For information on how to configure Zed, see the Zed
|
||||||
|
// documentation: https://zed.dev/docs/configuring-zed
|
||||||
|
//
|
||||||
|
// To see all of Zed's default settings without changing your
|
||||||
|
// custom settings, run `zed: open default settings` from the
|
||||||
|
// command palette (cmd-shift-p / ctrl-shift-p)
|
||||||
|
{
|
||||||
|
"telemetry": {
|
||||||
|
"diagnostics": true,
|
||||||
|
"metrics": false,
|
||||||
|
},
|
||||||
|
"ui_font_size": 16,
|
||||||
|
"buffer_font_size": 13,
|
||||||
|
"icon_theme": "Colored Zed Icons Theme Dark",
|
||||||
|
"theme": {
|
||||||
|
"mode": "system",
|
||||||
|
"light": "One Light",
|
||||||
|
"dark": "One Dark",
|
||||||
|
},
|
||||||
|
"restore_on_startup": "last_workspace",
|
||||||
|
"soft_wrap": "preferred_line_length",
|
||||||
|
|
||||||
|
// Remove AI Crap
|
||||||
|
"features": {
|
||||||
|
"edit_prediction_provider": "none",
|
||||||
|
"copilot": false,
|
||||||
|
},
|
||||||
|
"assistant": {
|
||||||
|
"version": "1",
|
||||||
|
"enabled": false,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Language Overrides
|
||||||
|
"languages": {
|
||||||
|
"Python": {
|
||||||
|
"show_wrap_guides": true,
|
||||||
|
"preferred_line_length": 80,
|
||||||
|
},
|
||||||
|
"Rust": {
|
||||||
|
"show_wrap_guides": true,
|
||||||
|
"preferred_line_length": 100,
|
||||||
|
},
|
||||||
|
"JSON": {
|
||||||
|
"tab_size": 4,
|
||||||
|
},
|
||||||
|
"JSONC": {
|
||||||
|
"tab_size": 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user