John Cleary (@TheRealBifter) is doing a nice project -
The 12 TDD's of Xmas.
Day 9 was the Bowling Game problem. I did it in Ruby. Here's the code from traffic-light 100. Tests first:
require './score'
require 'test/unit'
class TestScore < Test::Unit::TestCase
def test_score_uninteresting_game
# 7 7 7 7 7 = 35
# 6 6 6 6 6 = 30
balls = "51|52|51|52|51|52|51|52|51|52"
assert_equal 65, score(balls)
end
def test_score_all_frames_5_spare
# 15 15 15 15 15 = 75
# 15 15 15 15 15 = 75
balls = "5/|5/|5/|5/|5/|5/|5/|5/|5/|5/|5"
assert_equal 150, score(balls)
end
def test_perfect_score
# 30 30 30 30 30 = 150
# 30 30 30 30 30 = 150
balls = "X|X|X|X|X|X|X|X|X|X|XX"
assert_equal 300, score(balls)
end
def test_10_strikes_then_33
# 30 30 30 30 16 = 136
# 30 30 30 30 23 = 143
balls = "X|X|X|X|X|X|X|X|X|X|33"
assert_equal 279, score(balls)
end
def test_game_with_spare_in_middle_of_strikes
# 20 30 30 30 30 = 140
# 25 20 30 30 30 = 135
balls = "X|X|5/|X|X|X|X|X|X|X|XX"
assert_equal 275, score(balls)
end
def test_game_with_strike_in_middle_of_spares
# 15 20 15 13 20 = 83
# 13 11 20 14 12 = 70
balls = "2/|3/|5/|1/|X|3/|5/|4/|3/|2/|X"
assert_equal 153, score(balls)
end
def test_game_with_zero_balls
# 8 7 7 7 7 = 36
# 6 5 6 6 6 = 29
balls = "51|62|50|52|51|52|51|52|51|52"
assert_equal 65, score(balls)
end
def test_game_with_dash_as_zero_balls
# 8 7 7 7 8 = 37
# 6 5 6 6 6 = 29
balls = "51|62|5-|52|51|52|51|52|51|62"
assert_equal 66, score(balls)
end
end
Code second:
def score(balls)
frames = (balls).split("|")
while frames.length != 12
frames << "0"
end
frames.each_cons(3).collect{ |frame|
frame_score(frame)
}.inject(:+)
end
def frame_score(frames)
if strike? frames[0]
10 + strike_bonus(frames[1..2])
elsif spare? frames[0]
10 + ball_score(frames[1][0])
else
frames[0].chars.collect{ |ball|
ball_score(ball)
}.inject(:+)
end
end
def strike_bonus(frames)
if frames[0] == "XX"
20
elsif strike? frames[0]
10 + ball_score(frames[1][0])
elsif spare? frames[0]
10
else
ball_score(frames[0][0]) + ball_score(frames[0][1])
end
end
def ball_score(ball)
if strike? ball
10
else
ball.to_i
end
end
def strike?(frame)
frame == "X"
end
def spare?(frame)
frame[-1] == "/"
end
It took me a while to realize that each_slice should have been each_cons.
You can
replay my entire progression (warts and all) on Cyber-Dojo (naturally).
No comments:
Post a Comment