Skip to content
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

Sarah - Bowling Challenge #405

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--require spec_helper
7 changes: 7 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

source "https://rubygems.org"

# gem "rails"

gem "rspec", "~> 3.12"
26 changes: 26 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.5.0)
rspec (3.12.0)
rspec-core (~> 3.12.0)
rspec-expectations (~> 3.12.0)
rspec-mocks (~> 3.12.0)
rspec-core (3.12.2)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.3)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-support (3.12.0)

PLATFORMS
x86_64-darwin-20

DEPENDENCIES
rspec (~> 3.12)

BUNDLED WITH
2.4.13
39 changes: 23 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
Bowling Challenge in Ruby
=================
# Bowling Challenge in Ruby

* Feel free to use google, your notes, books, etc. but work on your own
* If you refer to the solution of another coach or student, please put a link to that in your README
* If you have a partial solution, **still check in a partial solution**
* You must submit a pull request to this repo with your code by 9am Monday week
Initially I struggled to understand what was being asked in this task, and what the inputs and outputs should be. The Scorecard class works alone but I have added a Bowling class and Application class as this helped me better understand the functionality of the Scorecard.

I found this link useful to understand what should happen step by step: [How Is Bowling Scored?](https://bowlingforbeginners.com/how-is-bowling-scored/)

I wanted my challenge to reflect a real life bowling situation to produce a scorecard that could look something like this:
![bowling scorecard](images/example-scorecard.png)

This was my initial design of the steps. I have decided to create a running total for each frame, and if there is a bonus updates once the next balls have been played.

![my design](images/bowling-design.jpg)

## The Task

Expand All @@ -16,22 +21,24 @@ A bowling game consists of 10 frames in which the player tries to knock down the

As usual please start by

* Forking this repo
- Forking this repo

* Finally submit a pull request before Monday week at 9am with your solution or partial solution. However much or little amount of code you wrote please please please submit a pull request before Monday week at 9am.
- Finally submit a pull request before Monday week at 9am with your solution or partial solution. However much or little amount of code you wrote please please please submit a pull request before Monday week at 9am.

___STRONG HINT, IGNORE AT YOUR PERIL:___ Bowling is a deceptively complex game. Careful thought and thorough diagramming — both before and throughout — will save you literal hours of your life.
**STRONG HINT, IGNORE AT YOUR PERIL:** Bowling is a deceptively complex game. Careful thought and thorough diagramming — both before and throughout — will save you literal hours of your life.

## Focus for this challenge

The focus for this challenge is to write high-quality code.

In order to do this, you may pay particular attention to the following:
* Using diagramming to plan your approach to the challenge
* TDD your code
* Focus on testing behaviour rather than state
* Commit often, with good commit messages
* Single Responsibility Principle and encapsulation
* Clear and readable code

- Using diagramming to plan your approach to the challenge
- TDD your code
- Focus on testing behaviour rather than state
- Commit often, with good commit messages
- Single Responsibility Principle and encapsulation
- Clear and readable code

## Bowling — how does it work?

Expand Down Expand Up @@ -60,6 +67,6 @@ A Perfect Game is when the player rolls 12 strikes (10 regular strikes and 2 str

In the image below you can find some score examples.

More about ten pin bowling here: http://en.wikipedia.org/wiki/Ten-pin_bowling
More about ten pin bowling here: [http://en.wikipedia.org/wiki/Ten-pin_bowling](http://en.wikipedia.org/wiki/Ten-pin_bowling)

![Ten Pin Score Example](images/example_ten_pin_scoring.png)
26 changes: 26 additions & 0 deletions app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require_relative 'lib/bowling'
require_relative 'lib/scorecard'

class Application

Frames = 10

def play
bowling = Bowling.new(Kernel)
scorecard = Scorecard.new

9.times do |i|
frame = bowling.frame
scorecard.add_frame(frame)
end

# 10th frame?
frame_10 = bowling.frame
scorecard.add_final_frame(frame_10)

p scorecard.scores
end
end

app = Application.new
app.play
Binary file added images/bowling-design.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/example-scorecard.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions lib/bowling.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Bowling
def initialize(io)
@io = io
end

def frame
roll_1 = roll(1)
return [roll_1] if roll_1 == 10
roll_2 = roll(2)
return [roll_1, roll_2]
end

def final_frame
score = frame

return if score.sum != 10
score << roll("bonus 1")
score << roll("bonus 2") if score.include?(10)
return score
end

def roll(number)
@io.puts "Roll #{number} - number of pins down: "
return @io.gets.chomp.to_i
end
end
66 changes: 66 additions & 0 deletions lib/scorecard.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
class Scorecard
def initialize
@scores = []
end

def scores
@scores
end

def add_frame(pins_down)
calculate_bonus(pins_down) unless @scores.empty? || @scores.last[:rolls].sum != 10

return @scores << { rolls: pins_down } if pins_down.sum == 10

# Not a spare or strike
total = @scores.empty? ? pins_down.sum : @scores.last[:score] + pins_down.sum
@scores << { rolls: pins_down, score: total }
end

def add_final_frame(pins_down)

if @scores[-2][:rolls].include?(10)
get_prev = @scores[-3][:score]
@scores[-2][:score] = get_prev + 20 + pins_down[0]
end

if @scores[-1][:rolls].include?(10)
add_strike_bonus(pins_down.slice(0, 2))
elsif @scores[-1][:rolls].sum == 10
add_spare_bonus(pins_down[0])
end

total = @scores.last[:score] + pins_down.sum
@scores << { rolls: pins_down, score: total }
end

private

def calculate_bonus(pins_down)
# last roll was spare
if [email protected][:rolls].include?(10)
add_spare_bonus(pins_down[0])
else
# last roll was strike
# check if previous was also strike
if @scores[-2] && @scores[-2][:rolls].include?(10)
get_prev = @scores[-3] ? @scores[-3][:score] : 0
@scores[-2][:score] = get_prev + 20 + pins_down[0]
end

add_strike_bonus(pins_down) if !pins_down.include?(10)
end
end

def add_spare_bonus(bonus_1)
@scores.last[:score] = previous_score + 10 + bonus_1
end

def add_strike_bonus(bonus_2)
@scores.last[:score] = previous_score + 10 + bonus_2.sum
end

def previous_score
return @scores[-2] ? @scores[-2][:score] : 0
end
end
54 changes: 54 additions & 0 deletions spec/bowling_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require 'bowling'

describe Bowling do
context '#roll' do
it "gets the number of pins down on one roll" do
io = double :io

expect(io).to receive(:puts).with("Roll 1 - number of pins down: ")
expect(io).to receive(:gets).and_return("4")

bowling = Bowling.new(io)
bowling.roll(1)
end
end

context '#frame' do
it 'returns an array containing 10 if roll a strike' do
io = double :io

expect(io).to receive(:puts).with("Roll 1 - number of pins down: ")
expect(io).to receive(:gets).and_return("10")

bowling = Bowling.new(io)
result = bowling.frame
expect(result).to eq [10]
end

it 'returns an array of two rolls' do
io = double :io

expect(io).to receive(:puts).with("Roll 1 - number of pins down: ")
expect(io).to receive(:gets).and_return("3")
expect(io).to receive(:puts).with("Roll 2 - number of pins down: ")
expect(io).to receive(:gets).and_return("4")

bowling = Bowling.new(io)
result = bowling.frame
expect(result).to eq [3, 4]
end

it 'returns an array of 0s if no pins knocked down' do
io = double :io

expect(io).to receive(:puts).with("Roll 1 - number of pins down: ")
expect(io).to receive(:gets).and_return("0")
expect(io).to receive(:puts).with("Roll 2 - number of pins down: ")
expect(io).to receive(:gets).and_return("0")

bowling = Bowling.new(io)
result = bowling.frame
expect(result).to eq [0, 0]
end
end
end
Loading