pub type PlayerId = String;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Player {
pub id: PlayerId,
pub name: String,
pub team: Team,
pub batting_pos: u8,
pub fielding_pos: u8,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Team {
Visiting = 0,
Home = 1,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Info {
VisitingTeam,
HomeTeam,
Site,
Date,
Number,
StartTime,
DayNight,
DesignatedHitter,
Pitches,
UmpireHome,
Umpire1B,
Umpire2B,
Umpire3B,
FieldCondition,
Precipitation,
Sky,
Temperature,
WindDirection,
WindSpeed,
GameLength,
Attendance,
WinningPitcher,
LosingPitcher,
SavePitcher,
GameWinningRBI,
EditTime,
ScoreMethod,
InputProgramVersion,
Inputter,
InputTime,
Scorer,
Translator,
Unknown,
}
impl From<&str> for Info {
fn from(bytes: &str) -> Info {
match bytes {
"visteam" => Info::VisitingTeam,
"hometeam" => Info::HomeTeam,
"date" => Info::Date,
"number" => Info::Number,
"pitches" => Info::Pitches,
"umphome" => Info::UmpireHome,
"ump1b" => Info::Umpire1B,
"ump2b" => Info::Umpire2B,
"ump3b" => Info::Umpire3B,
"fieldcond" => Info::FieldCondition,
"precip" => Info::Precipitation,
"sky" => Info::Sky,
"temp" => Info::Temperature,
"winddir" => Info::WindDirection,
"windspeed" => Info::WindSpeed,
"timeofgame" => Info::GameLength,
"attendence" => Info::Attendance,
"wp" => Info::WinningPitcher,
"lp" => Info::LosingPitcher,
"save" => Info::SavePitcher,
"gwrbi" => Info::GameWinningRBI,
"edittime" => Info::EditTime,
"howscored" => Info::ScoreMethod,
"inputprogvers" => Info::InputProgramVersion,
"inputter" => Info::Inputter,
"inputtime" => Info::InputTime,
"scorer" => Info::Scorer,
"translator" => Info::Translator,
_ => Info::Unknown,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Pitch {
PickoffThrowCatcher,
BlockedByCatcher,
NonBatterPlay,
PickoffFirst,
PickoffSecond,
PickoffThird,
RunnerGoingOnPitch,
Ball,
CalledStrike,
Foul,
HitBatter,
IntentionalBall,
UnknownStrike,
FoulBunt,
MissedBunt,
NoPitch,
FoulTipBunt,
Pitchout,
SwingOnPitchout,
FoulOnPitchout,
SwingingStrike,
FoulTip,
Unknown,
BallPitcherWentToMouth,
BallInPlayBatter,
BallInPlayPitchout,
}
impl From<char> for Pitch {
fn from(c: char) -> Pitch {
match c {
'+' => Pitch::PickoffThrowCatcher,
'*' => Pitch::BlockedByCatcher,
'.' => Pitch::NonBatterPlay,
'1' => Pitch::PickoffFirst,
'2' => Pitch::PickoffSecond,
'3' => Pitch::PickoffThird,
'>' => Pitch::RunnerGoingOnPitch,
'B' => Pitch::Ball,
'C' => Pitch::CalledStrike,
'F' => Pitch::Foul,
'H' => Pitch::HitBatter,
'I' => Pitch::IntentionalBall,
'K' => Pitch::UnknownStrike,
'L' => Pitch::FoulBunt,
'M' => Pitch::MissedBunt,
'N' => Pitch::NoPitch,
'O' => Pitch::FoulTipBunt,
'P' => Pitch::Pitchout,
'Q' => Pitch::SwingOnPitchout,
'R' => Pitch::FoulOnPitchout,
'S' => Pitch::SwingingStrike,
'T' => Pitch::FoulTip,
'V' => Pitch::BallPitcherWentToMouth,
'X' => Pitch::BallInPlayBatter,
'Y' => Pitch::BallInPlayPitchout,
'U' | _ => Pitch::Unknown,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Base {
First,
Second,
Third,
Home,
}
pub type Fielder = u8;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum FieldParameter {
Play(Fielder),
Error(Fielder),
Unknown,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum PlayDescription {
Balk,
FielderSequence(Vec<(Fielder, bool)>, Option<Base>),
GIDP(Vec<Fielder>, Base),
GITP {
first_assists: Vec<Fielder>,
first_out: Base,
second_assists: Vec<Fielder>,
second_out: Base,
putout: Fielder,
},
FieldersChoice(Fielder),
Error(Fielder),
FoulFlyBallError(Fielder),
Strikeout(Option<Box<PlayDescription>>, Vec<(Fielder, bool)>),
Walk(Option<Box<PlayDescription>>),
PassedBall,
WildPitch,
Single(Vec<Fielder>),
Double(Vec<Fielder>),
Triple(Vec<Fielder>),
HomeRun,
InsideTheParkHomeRun(Vec<Fielder>),
NoPlay,
StolenBase(Vec<(Base, bool)>),
HitByPitch,
CatcherInterference(Fielder),
GroundRuleDouble,
IntentionalWalk,
DefensiveIndifference,
OtherAdvance,
PickOff(Base, Vec<FieldParameter>),
PickOffCaughtStealing(Base, Vec<Fielder>),
CaughtStealing(Base, Vec<Fielder>),
LinedIntoDoublePlay {
first_out: Fielder,
second_out: Vec<Fielder>,
second_out_runner: Base,
},
LinedIntoTriplePlay {
first_out: Fielder,
second_out: Vec<Fielder>,
second_out_runner: Base,
third_out: Vec<Fielder>,
third_out_runner: Base,
},
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum HitType {
PopFly,
PopUpBunt,
Fly,
GroundBall,
GroundBallBunt,
LineDrive,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum HitLocation {
_2F,
_2,
_25F,
_25,
_1S,
_23,
_23F,
_15,
_1,
_13,
_5S,
_56S,
_6S,
_6MS,
_4MS,
_4S,
_34S,
_3S,
_5F,
_5,
_56,
_6,
_6M,
_4M,
_4,
_34,
_3,
_3F,
_5DF,
_5D,
_56D,
_6D,
_6MD,
_4MD,
_4D,
_34D,
_3D,
_3DF,
_7LSF,
_7LS,
_7S,
_78S,
_8S,
_89S,
_9S,
_9LS,
_9LSF,
_7LF,
_7L,
_7,
_78,
_8,
_89,
_9,
_9L,
_9LF,
_7LDF,
_7LD,
_7D,
_78D,
_8D,
_89D,
_9D,
_9LD,
_9LDF,
_78XD,
_8XD,
_89XD,
_5L,
}
impl From<&str> for HitLocation {
fn from(bytes: &str) -> HitLocation {
match bytes {
"2F" => HitLocation::_2F,
"2" => HitLocation::_2,
"25F" => HitLocation::_25F,
"25" => HitLocation::_25,
"1S" => HitLocation::_1S,
"23" => HitLocation::_23,
"23F" => HitLocation::_23F,
"15" => HitLocation::_15,
"1" => HitLocation::_1,
"13" => HitLocation::_13,
"5S" => HitLocation::_5S,
"56S" => HitLocation::_56S,
"6S" => HitLocation::_6S,
"6MS" => HitLocation::_6MS,
"4MS" => HitLocation::_4MS,
"4S" => HitLocation::_4S,
"34S" => HitLocation::_34S,
"3S" => HitLocation::_3S,
"5F" => HitLocation::_5F,
"5" => HitLocation::_5,
"56" => HitLocation::_56,
"6" => HitLocation::_6,
"6M" => HitLocation::_6M,
"4M" => HitLocation::_4M,
"4" => HitLocation::_4,
"34" => HitLocation::_34,
"3" => HitLocation::_3,
"3F" => HitLocation::_3F,
"5DF" => HitLocation::_5DF,
"5D" => HitLocation::_5D,
"56D" => HitLocation::_56D,
"6D" => HitLocation::_6D,
"6MD" => HitLocation::_6MD,
"4MD" => HitLocation::_4MD,
"4D" => HitLocation::_4D,
"34D" => HitLocation::_34D,
"3D" => HitLocation::_3D,
"3DF" => HitLocation::_3DF,
"7LSF" => HitLocation::_7LSF,
"7LS" => HitLocation::_7LS,
"7S" => HitLocation::_7S,
"78S" => HitLocation::_78S,
"8S" => HitLocation::_8S,
"89S" => HitLocation::_89S,
"9S" => HitLocation::_9S,
"9LS" => HitLocation::_9LS,
"9LSF" => HitLocation::_9LSF,
"7LF" => HitLocation::_7LF,
"7L" => HitLocation::_7L,
"7" => HitLocation::_7,
"78" => HitLocation::_78,
"8" => HitLocation::_8,
"89" => HitLocation::_89,
"9" => HitLocation::_9,
"9L" => HitLocation::_9L,
"9LF" => HitLocation::_9LF,
"7LDF" => HitLocation::_7LDF,
"7LD" => HitLocation::_7LD,
"7D" => HitLocation::_7D,
"78D" => HitLocation::_78D,
"8D" => HitLocation::_8D,
"89D" => HitLocation::_89D,
"9D" => HitLocation::_9D,
"9LD" => HitLocation::_9LD,
"9LDF" => HitLocation::_9LDF,
"78XD" => HitLocation::_78XD,
"8XD" => HitLocation::_8XD,
"89XD" => HitLocation::_89XD,
"5L" => HitLocation::_5L,
_ => unreachable!(bytes),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum PlayModifier {
HitWithLocation(HitType, Option<HitLocation>),
HitLocation(HitLocation),
AppealPlay,
BuntFoul,
BuntGroundedIntoDoublePlay,
BatterInterference,
LineDriveBunt,
BattingOutOfTurn,
BuntPoppedIntoDoublePlay,
RunnerHitByBattedBall,
CalledThirdStrike,
CourtesyBatter,
CourtesyFielder,
CourtesyRunner,
UnspecifiedDoublePlay,
Error(u8),
FlyBallDoublePlay,
FanInterference,
Foul,
ForceOut,
GroundBallDoublePlay,
GroundBallTriplePlay,
InfieldFlyRule,
Interference,
InsideTheParkHR,
LinedIntoDoublePlay,
LinedIntoTriplePlay,
ManagerChallenge,
NoDoublePlay,
Obstruction,
RunnerPassedAnotherRunner,
Relay(u8),
RunnerInterference,
SacrificeFly,
SacrificeHit,
Throw,
ThrowToBase(u8),
UnspecifiedTriplePlay,
UmpireInterference,
UmpireReview,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum AdvanceParameter {
ThrowingError(Fielder, Option<Base>),
FieldingPlay(Vec<FieldParameter>),
UnearnedRun,
TeamUnearnedRun,
RBI,
Interference(Fielder),
NoRBI,
WithThrow,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Advance {
pub from: Base,
pub to: Base,
pub success: bool,
pub parameters: Vec<AdvanceParameter>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PlayEvent {
pub description: PlayDescription,
pub modifiers: Vec<PlayModifier>,
pub advances: Vec<Advance>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum DataEventType {
EarnedRuns,
}
impl From<&str> for DataEventType {
fn from(bytes: &str) -> DataEventType {
match bytes {
"er" => DataEventType::EarnedRuns,
_ => unreachable!(),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Hand {
Left,
Right,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Event {
GameId {
id: String,
},
Version {
version: u8,
},
Info {
key: Info,
data: String,
},
Start {
player: Player,
},
Sub {
player: Player,
},
Play {
inning: u8,
team: Team,
player: PlayerId,
count: Option<(u8, u8)>,
pitches: Vec<Pitch>,
event: PlayEvent,
},
Data {
data_type: DataEventType,
player: PlayerId,
value: String,
},
Comment {
comment: String,
},
BattingAdjustment {
player: PlayerId,
hand: Hand,
},
PitchingAdjustment {
player: PlayerId,
hand: Hand,
},
LineupAdjustment {
team: Team,
position: u8,
},
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_info_parse() {
assert_eq!(Info::VisitingTeam, "visteam".into());
assert_eq!(Info::HomeTeam, "hometeam".into());
assert_eq!(Info::Date, "date".into());
assert_eq!(Info::Number, "number".into());
assert_eq!(Info::Pitches, "pitches".into());
assert_eq!(Info::UmpireHome, "umphome".into());
assert_eq!(Info::Umpire1B, "ump1b".into());
assert_eq!(Info::Umpire2B, "ump2b".into());
assert_eq!(Info::Umpire3B, "ump3b".into());
assert_eq!(Info::FieldCondition, "fieldcond".into());
assert_eq!(Info::Precipitation, "precip".into());
assert_eq!(Info::Sky, "sky".into());
assert_eq!(Info::Temperature, "temp".into());
assert_eq!(Info::WindDirection, "winddir".into());
assert_eq!(Info::WindSpeed, "windspeed".into());
assert_eq!(Info::GameLength, "timeofgame".into());
assert_eq!(Info::Attendance, "attendence".into());
assert_eq!(Info::WinningPitcher, "wp".into());
assert_eq!(Info::LosingPitcher, "lp".into());
assert_eq!(Info::SavePitcher, "save".into());
assert_eq!(Info::GameWinningRBI, "gwrbi".into());
assert_eq!(Info::EditTime, "edittime".into());
assert_eq!(Info::ScoreMethod, "howscored".into());
assert_eq!(Info::InputProgramVersion, "inputprogvers".into());
assert_eq!(Info::Inputter, "inputter".into());
assert_eq!(Info::InputTime, "inputtime".into());
assert_eq!(Info::Scorer, "scorer".into());
assert_eq!(Info::Translator, "translator".into());
assert_eq!(Info::Unknown, "foobar".into());
assert_eq!(Info::Unknown, "asdfasdf".into());
}
#[test]
fn test_data_event_parse() {
assert_eq!(DataEventType::EarnedRuns, "er".into());
}
#[test]
#[should_panic]
fn test_data_event_panic() {
let _: DataEventType = ("foo").into();
}
#[test]
#[should_panic]
fn test_hit_location_panic() {
let _: HitLocation = "foocmfadksl".into();
}
#[test]
fn test_pitch_parse() {
assert_eq!(Pitch::PickoffThrowCatcher, '+'.into());
assert_eq!(Pitch::BlockedByCatcher, '*'.into());
assert_eq!(Pitch::NonBatterPlay, '.'.into());
assert_eq!(Pitch::PickoffFirst, '1'.into());
assert_eq!(Pitch::PickoffSecond, '2'.into());
assert_eq!(Pitch::PickoffThird, '3'.into());
assert_eq!(Pitch::RunnerGoingOnPitch, '>'.into());
assert_eq!(Pitch::Ball, 'B'.into());
assert_eq!(Pitch::CalledStrike, 'C'.into());
assert_eq!(Pitch::Foul, 'F'.into());
assert_eq!(Pitch::HitBatter, 'H'.into());
assert_eq!(Pitch::IntentionalBall, 'I'.into());
assert_eq!(Pitch::UnknownStrike, 'K'.into());
assert_eq!(Pitch::FoulBunt, 'L'.into());
assert_eq!(Pitch::MissedBunt, 'M'.into());
assert_eq!(Pitch::NoPitch, 'N'.into());
assert_eq!(Pitch::FoulTipBunt, 'O'.into());
assert_eq!(Pitch::Pitchout, 'P'.into());
assert_eq!(Pitch::SwingOnPitchout, 'Q'.into());
assert_eq!(Pitch::FoulOnPitchout, 'R'.into());
assert_eq!(Pitch::SwingingStrike, 'S'.into());
assert_eq!(Pitch::FoulTip, 'T'.into());
assert_eq!(Pitch::BallPitcherWentToMouth, 'V'.into());
assert_eq!(Pitch::BallInPlayBatter, 'X'.into());
assert_eq!(Pitch::BallInPlayPitchout, 'Y'.into());
assert_eq!(Pitch::Unknown, 'U'.into());
assert_eq!(Pitch::Unknown, 'Z'.into());
assert_eq!(Pitch::Unknown, 'A'.into());
}
}