Skip to content

Instantly share code, notes, and snippets.

@bbasata
Created December 20, 2011 05:40
Show Gist options
  • Save bbasata/1500429 to your computer and use it in GitHub Desktop.
Save bbasata/1500429 to your computer and use it in GitHub Desktop.
A bowling game
module Enumerable
def sum(identity=0)
inject(identity) { |sum,each| sum + each }
end
end
class BowlingGame
class Frame
def initialize
@rolls = []
@bonuses = []
end
def hit(pins)
@rolls << pins
end
def bonus(pins)
@bonuses << pins
end
def open?
!closed?
end
def closed?
strike? || @rolls.size == 2
end
def strike?
first_roll == 10
end
def spare?
score == 10 && !strike?
end
def score
@rolls.sum + @bonuses.sum
end
def first_roll
@rolls.first
end
def waiting_for_bonus
(strike? && @bonuses.size < 2) || (spare? && @bonuses.size < 1)
end
end
def initialize
@frames = Array.new(10) { Frame.new }
end
def hit(pins)
@frames.select(&:waiting_for_bonus).each { |frame| frame.bonus(pins) }
current_frame.hit(pins)
end
def score
@frames.collect(&:score).sum
end
private
def current_frame
@frames.find(&:open?) || Frame.new
end
end
describe BowlingGame do
RSpec::Matchers.define :give_score do |expected|
match do |rolls|
rolls.flatten.reject(&:nil?).each { |roll| game.hit(roll) }
game.score == expected
end
end
let(:x) { nil }
let(:game) { BowlingGame.new }
it "scores zero for an all-gutter game" do
([0] * 20).should give_score(0)
end
it "scores 20 for a game of all ones" do
([1] * 20).should give_score(20)
end
it "scores a one-roll bonus after a spare" do
[5, 5, 3, 3, [0] * 16].should give_score(19)
end
context "with a strike" do
it "scores a two-roll bonus after a strike" do
[10, x, 3, 3, 3, 3, [0] * 14].should give_score(28)
end
end
context "perfect game" do
example { ([10] * 12).should give_score(300) }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment