#!/usr/bin/env ruby # This code comes from http://ruby-it.org/pages/Bowling # Check the page for copyright notice and explanations class TestBowling < Test::Unit::TestCase def setup @game = GAME.new end def test_all_gutters 20.times { @game.roll 0 } assert_equal(0, @game.score) end def test_all_open 10.times { @game.roll 5; @game.roll 4 } assert_equal(90, @game.score) end def test_spare @game.roll 4 @game.roll 6 @game.roll 5 @game.roll 4 8.times { @game.roll 0; @game.roll 0 } assert_equal(24, @game.score) end def test_strike @game.roll 10 @game.roll 5 @game.roll 4 @game.roll 3 @game.roll 0 7.times { @game.roll 0; @game.roll 0 } assert_equal(31, @game.score) end def test_perfect 12.times { @game.roll 10 } assert_equal(300, @game.score) end def test_alternating 5.times { @game.roll 10; @game.roll 6; @game.roll 4 } @game.roll 10 assert_equal(200, @game.score) end def test_complex_open rolls = [1, 1, 1, 2, 2, 1, 2, 3, 3, 2, 1, 4, 4, 1, 1, 5, 5, 1, 1, 6] rollSum = rolls.inject(0) {|sum, each| sum + each} rolls.each {|i| @game.roll i} assert_equal(rollSum, @game.score) end end require 'test/unit' require 'test_bowling' class BowlingGame def initialize @rolls = [] end def roll(pins) @rolls.push pins end def score frames.total_score end def frames firstFrame = RackFrame.ten_frame_list @rolls.each { |pins| firstFrame.roll pins} firstFrame end end class RackFrame def initialize @state = :first_roll @next = nil end def RackFrame.ten_frame_list frame = RackFrame.new 9.times { frame = RackFrame.another(frame) } frame end attr_reader :score attr_accessor :next def roll(pins) send(@state, pins) end def RackFrame.another(aFrame) frame = RackFrame.new frame.next = aFrame frame end def total_score score + (@next.nil? ? 0 : @next.total_score) end private def first_roll(pins) @score = pins if @score == 10 @state = :first_strike_bonus else @state = :second_roll end end def first_strike_bonus(pins) @score += pins next_roll pins @state = :second_strike_bonus end def second_roll(pins) @score += pins if @score == 10 @state = :spare_bonus else @state = :satisfied end end def second_strike_bonus(pins) @score += pins next_roll pins @state = :satisfied end def spare_bonus(pins) @score += pins next_roll pins @state = :satisfied end def satisfied(pins) next_roll pins end def next_roll pins @next.roll pins unless @next.nil? end end class TestFrame < Test::Unit::TestCase def setup @frame = RackFrame.ten_frame_list end def test_open @frame.roll 4 @frame.roll 5 @frame.roll 1 @frame.roll 2 assert_equal(9, @frame.score) end def test_spare @frame.roll 9 @frame.roll 1 @frame.roll 5 @frame.roll 4 assert_equal(15, @frame.score) end def test_spare_with_zero @frame.roll 9 @frame.roll 1 @frame.roll 0 @frame.roll 4 assert_equal(10, @frame.score) end def test_strike @frame.roll 10 @frame.roll 10 @frame.roll 10 @frame.roll 5 assert_equal(30, @frame.score) end def test_frame_string count = 0 currentFrame = @frame until currentFrame.nil? count += 1 currentFrame = currentFrame.next end assert_equal(10, count) end def test_ten_open_frames 10.times { @frame.roll 4; @frame.roll 3 } assert_equal(70, @frame.total_score) end def test_second_frame @frame.roll 5 @frame.roll 4 @frame.roll 3 @frame.roll 2 assert_equal(9, @frame.score) assert_equal(5, @frame.next.score) end def test_perfect 12.times { @frame.roll 10 } assert_equal(300, @frame.total_score) end end TestBowling.const_set :GAME, BowlingGame require 'test/unit' require 'test_bowling' class BowlingGame2 def initialize @rolls = [] @score = 0 @frameStart = 0 end def roll(pins) @rolls.push pins end def score number_of_frames.times { @score += frame_score update_frame_start } @score end private def number_of_frames 10 end def all_pins_down 10 end def frame_score frame_score = roll1 + roll2 frame_score += roll3 if bonus_frame? frame_score end def update_frame_start @frameStart += strike? ? 1 : 2 end def bonus_frame? spare? || strike? end def roll1 @rolls[@frameStart] end def roll2 @rolls[@frameStart+1] end def roll3 @rolls[@frameStart+2] end def strike? roll1 == all_pins_down end def spare? roll1 < all_pins_down && roll1+roll2 == all_pins_down end end TestBowling.const_set :GAME, BowlingGame2 require 'test/unit' require 'test_bowling' class StreamBowlingGame def initialize @rolls = [] end def roll(pins) @rolls.push pins end def score @index = -1 total = 0 10.times { total += score_frame } total end def next @index += 1 @rolls[@index] end private def score_frame if spare? self.next + self.next + peek elsif strike? self.next + peek + peek_second else self.next + self.next end end def spare? peek + peek_second == 10 end def strike? peek == 10 end def peek @rolls[@index+1] end def peek_second @rolls[@index+2] end end TestBowling.const_set :GAME, StreamBowlingGame