-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbowling.rb
219 lines (157 loc) · 4.1 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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
require 'rspec'
class Game
def self.score_for(gamecard)
self.new(gamecard).score
end
def initialize(gamecard)
@frames = extract_frames_from(gamecard)
@pending_bonus_count = 0
#elim
@frames_with_pending_score = 0
end
def score
@frames.inject(0) do |accumulator, frame|
number_of_bonuses = bonuses_to_use(frame)
#unir
accumulator += frame.score
accumulator += frame.bonificable_score(number_of_bonuses)
#segregar resp. mantenimiento de bonus fuera de score
update_bonus_count(number_of_bonuses, frame)
accumulator
end
end
private
def bonuses_to_use(frame)
[@frames_with_pending_score * frame.number_of_rolls, @pending_bonus_count].min
end
# refactor
def update_bonus_count(amount, frame)
@pending_bonus_count -= amount
if @pending_bonus_count < 0
@pending_bonus_count = 0
end
if frame.strike?
@pending_bonus_count += 2
@frames_with_pending_score += 1
elsif frame.spare?
@pending_bonus_count += 1
@frames_with_pending_score += 1
end
end
def extract_frames_from(gamecard)
# eliminar ñapa
regular_frames = gamecard.gsub("X", "X-")
.chars[0..18]
.each_slice(2)
.map {|rolls| Frame.new(rolls.join) }
last_frame = Frame.new(gamecard.gsub("X", "X-")
.chars[18..-1]
.join)
regular_frames << last_frame
end
end
# check methods visibility
class Frame
SPARE = '/'
STRIKE = 'X'
MAX_POINTS = 10
def initialize(roll_list)
@rolls = roll_list.gsub('X-', 'X').chars
end
def score
return MAX_POINTS if all_pins_down?
@rolls.map(&:to_i).inject(&:+)
end
def first_roll_score
return MAX_POINTS if strike?
@rolls[0].to_i
end
def second_roll_score
return MAX_POINTS - first_roll_score if spare?
return nil if strike?
@rolls[1].to_i
end
def bonificable_score(bonus_count)
roll_scores = [first_roll_score, second_roll_score].compact
result = 0
bonus_count.times do |i|
result += roll_scores[i % number_of_rolls].to_i
end
result
end
def all_pins_down?
spare? || strike?
end
def number_of_rolls
@rolls.size
end
def spare?
@rolls.include?(SPARE)
end
def strike?
@rolls.include?(STRIKE)
end
end
#####################
def calculate_score(gamecard)
Game.score_for(gamecard)
end
#####################
describe 'Bowling' do
it "all misses score 0" do
# arrange
game = "--------------------"
# act
score = calculate_score(game)
# assert
expect(score).to eq(0)
end
it "seven pins down on the first try scores 7" do
# arrange
game = "7-------------------"
# act
score = calculate_score(game)
# assert
expect(score).to eq(7)
end
it "nine pins down on the first frame score 9" do
game = "72------------------"
score = calculate_score(game)
expect(score).to eq(9)
end
it "spare in the first frame score 10" do
game = "7/------------------"
score = calculate_score(game)
expect(score).to eq(10)
end
it "strike in the first frame score 10" do
game = "X------------------"
score = calculate_score(game)
expect(score).to eq(10)
end
it "spare in the first frame and 5 pins down in the first roll of the second frame score 20" do
game = "5/5-----------------"
score = calculate_score(game)
expect(score).to eq(20)
end
it "strike in the first frame and 5 pins down scores 20" do
game = "X5-----------------"
score = calculate_score(game)
expect(score).to eq(20)
end
it "strike in the two first frames and 3+4 pins down scores 47" do
game = "XX34--------------"
score = calculate_score(game)
expect(score).to eq(47) #27 + (13 + 7)
end
it "all spares and 5 pins down in extra roll score 150" do
game = "5/5/5/5/5/5/5/5/5/5/5"
score = calculate_score(game)
expect(score).to eq(150)
end
it "perfect game score 300" do
game = "XXXXXXXXXXXX"
score = calculate_score(game)
expect(score).to eq(300)
end
end