Skip to content

Implement Bowling #213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Oct 26, 2016
Merged
1 change: 1 addition & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"robot-simulator",
"bracket-push",
"queen-attack",
"bowling",
"sublist",
"space-age",
"allergies",
Expand Down
7 changes: 7 additions & 0 deletions exercises/bowling/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
3 changes: 3 additions & 0 deletions exercises/bowling/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[package]
name = "bowling"
version = "0.0.0"
134 changes: 134 additions & 0 deletions exercises/bowling/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@

pub struct BowlingGame {
frames: Vec<Frame>,
}

struct Frame {
rolls: Vec<u16>,
bonus: Vec<u16>,
}

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 {
Copy link
Member

@petertseng petertseng Oct 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you expressed discontent about it, are you looking for ideas? I could suggest either early return, or transformations of the form if A then B else true to !A || B

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 mut frame in self.frames.iter_mut() {
frame.add_roll(pins)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

big hammer, adding it to all the frames instead of just the ones that need it. But ultimately I don't mind

}

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<u16, &'static str> {
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())
}
}
Loading