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

Caroline Evans - Ruby Bowling Score Sheet #406

Open
wants to merge 5 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
9 changes: 9 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

source 'https://rubygems.org'

# gem "rails"

gem 'rspec', '~> 3.12'

gem 'rubocop', '~> 1.51'
49 changes: 49 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
diff-lcs (1.5.0)
json (2.6.3)
parallel (1.23.0)
parser (3.2.2.1)
ast (~> 2.4.1)
rainbow (3.1.1)
regexp_parser (2.8.0)
rexml (3.2.5)
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)
rubocop (1.51.0)
json (~> 2.3)
parallel (~> 1.10)
parser (>= 3.2.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.28.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.28.1)
parser (>= 3.2.1.0)
ruby-progressbar (1.13.0)
unicode-display_width (2.4.2)

PLATFORMS
x86_64-darwin-20

DEPENDENCIES
rspec (~> 3.12)
rubocop (~> 1.51)

BUNDLED WITH
2.4.13
51 changes: 51 additions & 0 deletions app.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# frozen_string_literal: true

require_relative './lib/bowling_score_sheet'

class BowlingApp
def initialize(io, score_sheet)
@io = io
@score_sheet = score_sheet
end

def run
while @score_sheet.complete == false
@io.puts 'Enter number of knocked down pins separated by commas (eg 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1):'
user_input = @io.gets.chomp
roll(user_input)
print_score_sheet
@io.puts "Total: #{score}"
end
end

def roll(string_of_pins)
rolls = string_of_pins.split(',').map(&:to_i)
i = 0
while i < rolls.length
@score_sheet.add_roll(rolls[i])
i += 1
end
end

def score
@score_sheet.all_frames.sum do |frame|
frame.round <= 10 ? frame.total_score : 0
end
end

def print_score_sheet
@score_sheet.all_frames.each do |frame|
if frame.round.positive? && frame.round <= 10
@io.puts "Frame: #{frame.round}, scores: #{frame.score}, total score: #{frame.total_score}, notes: #{frame.status}"
end
end
end
end

if __FILE__ == $PROGRAM_NAME
app = BowlingApp.new(
Kernel,
BowlingScoreSheet.new
)
app.run
end
76 changes: 76 additions & 0 deletions lib/bowling_score_sheet.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# frozen_string_literal: true

require_relative 'frame'

class BowlingScoreSheet
def initialize
@frames = [Frame.new]
end

def add_roll(pins)
add_bonus_to_previous_frames(pins)
add_score_to_current_frame(pins)
end

def all_frames
@frames
end

def complete
frame_10 = @frames.filter { |frame| frame.round == 10 }
if frame_10 == []
false
elsif frame_10[0].complete == true && frame_10[0].bonuses.zero?
true
else
false
end
end

private

def add_bonus_to_previous_frames(pins)
@frames.each do |frame|
if frame.bonuses.positive? && frame.complete
frame.total_score += pins
frame.bonuses -= 1
end
end
end

def add_score_to_current_frame(pins)
current_frame = @frames.last
if current_frame.complete
new_frame = create_new_frame(current_frame, pins)
@frames << new_frame
else
current_frame.score << pins
current_frame.total_score += pins
set_frame_status(current_frame)
current_frame.complete = true
end
end

def create_new_frame(current_frame, pins)
new_frame = Frame.new
new_frame.round = current_frame.round + 1
new_frame.score = [pins]
new_frame.total_score = pins
new_frame.complete = false if pins != 10
set_frame_status(new_frame)

new_frame
end

def set_frame_status(frame)
return unless frame.total_score == 10

if frame.score[0] == 10
frame.status = 'strike'
frame.bonuses = 2
else
frame.status = 'spare'
frame.bonuses = 1
end
end
end
13 changes: 13 additions & 0 deletions lib/frame.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

class Frame
attr_accessor :round, :score, :total_score, :status, :complete, :bonuses

def initialize
@complete = true
@round = 0
@score = 0
@total_score = 0
@bonuses = 0
end
end
38 changes: 38 additions & 0 deletions spec/app_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

require_relative '../app'
require_relative '../lib/bowling_score_sheet'

RSpec.describe BowlingApp do
it 'calculates the running score of a game with no strikes or spares' do
io = double :io
game = BowlingApp.new(io, BowlingScoreSheet.new)
game.roll('1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1')
expect(game.score).to eq 20

game = BowlingApp.new(io, BowlingScoreSheet.new)
game.roll('2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2')
expect(game.score).to eq 40

game = BowlingApp.new(io, BowlingScoreSheet.new)
game.roll('2,2,2,2,2,2,2,2,2,2')
game.roll('2,2,2,2,2,2,2,2,2,2')
expect(game.score).to eq 40
end

it 'calculates the running score of a game with one spare (not in final frame)' do
io = double :io
game = BowlingApp.new(io, BowlingScoreSheet.new)
game.roll('1,1,2,8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1')
expect(game.score).to eq 29
end

it 'calculates the running score of a game with a mix of spares and stikes' do
io = double :io
BowlingScoreSheet.new

game = BowlingApp.new(io, BowlingScoreSheet.new)
game.roll('1,1,1,1,1,1,1,1,1,1,10,10,2,8,8,2,10,4,5')
expect(game.score).to eq 109
end
end
140 changes: 140 additions & 0 deletions spec/bowling_score_sheet_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# frozen_string_literal: true

require 'bowling_score_sheet'

RSpec.describe BowlingScoreSheet do
it 'calculates the running score of a game with no strikes or spares' do
double :io
score_sheet = BowlingScoreSheet.new
20.times do
score_sheet.add_roll(1)
end

total_score = score_sheet.all_frames.sum(&:total_score)
expect(total_score).to eq 20
end

it 'calculates the running score of a game with a spare (not in final frame) and no strikes' do
double :io
score_sheet = BowlingScoreSheet.new

score_sheet.add_roll(2)
score_sheet.add_roll(8)

18.times do
score_sheet.add_roll(1)
end

total_score = score_sheet.all_frames.sum(&:total_score)
expect(total_score).to eq 29
end

it 'calculates the running score of a game with a strike (not in final frame) and no spares' do
double :io
score_sheet = BowlingScoreSheet.new

score_sheet.add_roll(10)
score_sheet.add_roll(2)
score_sheet.add_roll(3)
16.times do
score_sheet.add_roll(1)
end

total_score = score_sheet.all_frames.sum(&:total_score)
expect(total_score).to eq 36
end

it 'calculates the running score of a game with multiple strikes (not in final frame) and no spares' do
double :io
score_sheet = BowlingScoreSheet.new

score_sheet.add_roll(10)
score_sheet.add_roll(10)
score_sheet.add_roll(2)
score_sheet.add_roll(3)

14.times do
score_sheet.add_roll(1)
end

total_score = score_sheet.all_frames.sum(&:total_score)
expect(total_score).to eq 56
end

it 'calculates the running score of a game with multiple strikes and spares (not in final frame)' do
double :io
score_sheet = BowlingScoreSheet.new

score_sheet.add_roll(10)
score_sheet.add_roll(10)
score_sheet.add_roll(2)
score_sheet.add_roll(8)
score_sheet.add_roll(8)
score_sheet.add_roll(2)
score_sheet.add_roll(10)

10.times do
score_sheet.add_roll(1)
end

total_score = score_sheet.all_frames.sum(&:total_score)
expect(total_score).to eq 102
end

it 'calculates the running score of a game with a strike in final frame' do
double :io
score_sheet = BowlingScoreSheet.new

18.times do
score_sheet.add_roll(1)
end
score_sheet.add_roll(10)
score_sheet.add_roll(2)
score_sheet.add_roll(3)

total_score = score_sheet.all_frames.sum do |frame|
frame.round <= 10 ? frame.total_score : 0
end
expect(total_score).to eq 33
end

it 'calculates the running score of a game with a spare in final frame' do
double :io
score_sheet = BowlingScoreSheet.new

19.times do
score_sheet.add_roll(1)
end
score_sheet.add_roll(9)
score_sheet.add_roll(2)

total_score = score_sheet.all_frames.sum do |frame|
frame.round <= 10 ? frame.total_score : 0
end
expect(total_score).to eq 30
end

it 'calculates the running score of a game with a mix of spares and stikes' do
double :io
score_sheet = BowlingScoreSheet.new

10.times do
score_sheet.add_roll(1)
end

score_sheet.add_roll(10)
score_sheet.add_roll(10)
score_sheet.add_roll(2)
score_sheet.add_roll(8)
score_sheet.add_roll(8)
score_sheet.add_roll(2)
score_sheet.add_roll(10)
score_sheet.add_roll(4)
score_sheet.add_roll(5)

total_score = score_sheet.all_frames.sum do |frame|
frame.round <= 10 ? frame.total_score : 0
end
expect(total_score).to eq 109
end
end
Loading