pub struct BowlingGame { frames: Vec, } struct Frame { rolls: Vec, bonus: Vec, } impl Frame { fn score(&self) -> u16 { self.roll_score() + self.bonus_score() } fn roll_score(&self) -> u16 { self.rolls.iter().sum() } fn bonus_score(&self) -> u16 { self.bonus.iter().sum() } fn is_valid(&self) -> bool { self.rolls_valid() && self.bonus_valid() } fn rolls_valid(&self) -> bool { self.roll_score() <= 10 } fn bonus_valid(&self) -> bool { if self.is_open() || !self.bonus_done() { return true; } if self.is_spare() { return self.bonus_score() <= 10; } if let Some(first) = self.bonus.iter().next() { if *first == 10 { self.bonus_score() <= 20 } else { self.bonus_score() <= 10 } } else { unreachable!(); } } fn is_complete(&self) -> bool { self.is_open() || self.bonus_done() } fn rolls_done(&self) -> bool { self.rolls.len() == 2 || self.is_strike() } fn bonus_done(&self) -> bool { (self.is_spare() && self.bonus.len() == 1) || (self.is_strike() && self.bonus.len() == 2) } fn is_open(&self) -> bool { self.rolls.len() == 2 && self.roll_score() < 10 } fn is_spare(&self) -> bool { self.rolls.len() == 2 && self.roll_score() == 10 } fn is_strike(&self) -> bool { self.rolls.len() == 1 && self.roll_score() == 10 } fn add_roll(&mut self, roll: u16) { if !self.is_complete() { if self.is_spare() || self.is_strike() { self.bonus.push(roll) } else { self.rolls.push(roll) } } } fn new() -> Self { Frame { rolls: vec![], bonus: vec![], } } } impl BowlingGame { pub fn new() -> Self { BowlingGame { frames: vec![Frame::new()] } } pub fn roll(&mut self, pins: u16) -> Result<(), &'static str> { if pins > 10 { Err("Greater than 10 pins") } else { if self.score().is_ok() { return Err("Game Finished. No more rolls."); } for frame in self.frames.iter_mut() { frame.add_roll(pins) } if self.frames.iter().any(|f| !f.is_valid()) { return Err("Invalid Roll"); } if self.frames.iter().last().unwrap().rolls_done() && self.frames.len() < 10 { self.frames.push(Frame::new()); } Ok(()) } } pub fn score(&self) -> Result { if !self.is_done() { Err("Game Incomplete") } else { Ok(self.frames.iter().fold(0, |acc, r| acc + r.score())) } } fn is_done(&self) -> bool { self.frames.len() == 10 && self.frames.iter().all(|f| f.is_complete()) } }