forked from engwebUM/homework-week4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bowling.rb
141 lines (114 loc) · 2.41 KB
/
bowling.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
class Bowling
attr_reader :frames
def initialize
@frames = Array.new(9) { Frame.new }
@frames << LastFrame.new
end
def roll(pins)
fail 'game over' if game_over?
fail 'impossible play' if pins < 0 || pins > pins_standing
playing_frame.roll(pins)
return if game_over?
if strike_on_regular_frame? || neither_strike_nor_spare_on_last_frame?
playing_frame.roll(0)
end
end
def score
points = 0
frames.each_with_index { |frame, index|
points += frame.points
if frame.strike? && index < 9
points += bonus_strike(index)
elsif frame.spare? && index < 9
points += bonus_spare(index)
end }
points
end
private
def bonus_spare(index)
frames[index + 1].first
end
def bonus_strike(index)
bonus_spare(index) + if frames[index + 1].strike? && index < 8
frames[index + 2].first
else
frames[index + 1].second
end
end
def game_over?
frames.each { |frame|
if !frame.over?
return false
end }
return true
end
def pins_standing
playing_frame.pins_standing
end
def playing_frame
frames.each { |frame|
if !frame.over?
return frame
end }
return nil
end
def strike_on_regular_frame?
if frames.find_index(playing_frame) < 9
playing_frame.nil? ? false : playing_frame.strike?
end
end
def neither_strike_nor_spare_on_last_frame?
playing_frame.playing_roll == 2 && !(playing_frame.strike? || playing_frame.spare?)
end
end
class Frame
attr_reader :rolls
def initialize
@rolls = [nil, nil]
end
def roll(pins)
@rolls[playing_roll] = pins
end
def over?
rolls.find_index(nil).nil?
end
def playing_roll
rolls.find_index(nil)
end
def first
rolls[0].to_i
end
def second
rolls[1].to_i
end
def points
first + second
end
def pins_standing
playing_roll == 0 ? 10 : 10 - first
end
def spare?
!strike? && (first + second == 10)
end
def strike?
first == 10
end
end
class LastFrame < Frame
def initialize
@rolls = [nil, nil, nil]
end
def third
rolls[2].to_i
end
def points
first + second + third
end
def pins_standing
if playing_roll == 0 || spare?
10
else
rolls[playing_roll - 1] == 10 ? 10 : 10 - rolls[playing_roll - 1]
end
end
end