use std::fmt::Display;
use advent_of_code::errors::{Error, Result};
use super::{rps::RPS, state::GameState};
pub struct Round(RPS, RPS);
impl Round {
pub fn new(player1: RPS, player2: RPS) -> Self {
Round(player1, player2)
}
pub fn new_decided(player1: RPS, outcome: GameState) -> Self {
let player2 = (-outcome).against(&player1);
Round(player1, player2)
}
pub fn compete(&self) -> usize {
self.1.points() + (-(self.0 + self.1)).points()
}
pub fn try_from_players_line(line: &str) -> Result<Self> {
let (p1, p2) = split_line(line)?;
Ok(Self(p1, p2))
}
pub fn try_from_decided_line(line: &str) -> Result<Self> {
let (p1, outcome) = split_line(line)?;
Ok(Self::new_decided(p1, outcome))
}
}
impl Display for Round {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "P1: {:?}, P2: {:?}", self.0, self.1)
}
}
fn split_line<'a, I1, I2>(line: &'a str) -> Result<(I1, I2)>
where
I1: TryFrom<&'a str, Error = Error>,
I2: TryFrom<&'a str, Error = Error>,
{
let mut round_splits = line.trim().split(' ');
let i1 = round_splits
.next()
.ok_or(Error::InvalidStruct(
"Invalid Input One of Round".to_owned(),
))?
.try_into()?;
let i2 = round_splits
.next()
.ok_or(Error::InvalidStruct(
"Invalid Input Two of Round".to_owned(),
))?
.try_into()?;
Ok((i1, i2))
}