agent

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a new bowling game.
5 """
6 self.rolls = []
7 self.current_roll = 0
8
59 def roll(self, pins):
6 pass
7
10 """
11 Record a roll in the game.
12
13 Args:
14 pins (int): Number of pins knocked down in this roll.
15
16 Raises:
17 ValueError: If the number of pins is invalid.
18 """
19 # Edge Case: Invalid number of pins (negative or more than 10)
20 if pins < 0 or pins > 10:
21 raise ValueError("Pins must be between 0 and 10")
22
23 # Edge Case: Game already has 10 frames and no more rolls are allowed
24 if self.is_game_complete():
25 raise ValueError("Game is already complete")
26
27 # Edge Case: In regular frames, check if frame would exceed 10 pins
28 if len(self.rolls) < 18: # Before 10th frame
29 # Determine if this is the first or second roll of a frame
30 frame_start = self._find_frame_start(len(self.rolls))
31 if frame_start is not None and frame_start < len(self.rolls):
32 # This is the second roll of a frame
33 if self.rolls[frame_start] != 10 and self.rolls[frame_start] + pins > 10:
34 raise ValueError("Pin count exceeds pins on the lane")
35 elif len(self.rolls) >= 18: # We're in the 10th frame or fill balls
36 # If this is the second roll of the 10th frame
37 if len(self.rolls) == 19:
38 # If first roll was a strike, any second roll is valid (0-10)
39 # If first roll was not a strike, sum must be <= 10
40 if self.rolls[18] != 10 and self.rolls[18] + pins > 10:
41 raise ValueError("Pin count exceeds pins on the lane")
42 # If this is a fill ball (20th or later roll)
43 elif len(self.rolls) >= 20:
44 # Check if we're allowed to roll based on 10th frame
45 if not self.can_roll_fill_ball():
46 raise ValueError("Game is already complete")
47
48 self.rolls.append(pins)
49
850 def score(self):
9 pass
51 """
52 Calculate the total score for the game.
53
54 Returns:
55 int: The total score of the game.
56
57 Raises:
58 ValueError: If the game is not yet complete.
59 """
60 # Edge Case: Game is not complete
61 if not self.is_game_complete():
62 raise ValueError("Game is not yet complete")
63
64 total_score = 0
65 roll_index = 0
66
67 for frame in range(10):
68 # Edge Case: Strike (first roll of frame is 10)
69 if self.is_strike(roll_index):
70 total_score += 10 + self.strike_bonus(roll_index)
71 roll_index += 1
72 # Edge Case: Spare (sum of two rolls in frame is 10)
73 elif self.is_spare(roll_index):
74 total_score += 10 + self.spare_bonus(roll_index)
75 roll_index += 2
76 # Edge Case: Open frame (sum of two rolls < 10)
77 else:
78 total_score += self.sum_of_balls_in_frame(roll_index)
79 roll_index += 2
80
81 return total_score
82
83 def is_game_complete(self):
84 """
85 Check if the game is complete (10 frames have been played).
86
87 Returns:
88 bool: True if the game is complete, False otherwise.
89 """
90 # Count frames by processing rolls
91 frame_count = 0
92 roll_index = 0
93
94 # Count complete frames
95 while roll_index < len(self.rolls) and frame_count < 10:
96 # If this is a strike
97 if roll_index < len(self.rolls) and self.rolls[roll_index] == 10:
98 frame_count += 1
99 roll_index += 1
100 else:
101 # Need two rolls for a non-strike frame
102 if roll_index + 1 >= len(self.rolls):
103 # Incomplete frame, game not complete
104 break
105 frame_count += 1
106 roll_index += 2
107
108 # If we haven't completed 10 frames, game is not complete
109 if frame_count < 10:
110 return False
111
112 # If we have more than 10 frames (shouldn't happen), game is complete
113 if frame_count > 10:
114 return True
115
116 # We have exactly 10 frames, check if the 10th frame is complete
117 # Find the start of the 10th frame
118 tenth_frame_start = self._find_tenth_frame_start()
119 if tenth_frame_start is None:
120 return False
121
122 # If we don't have enough rolls to determine the 10th frame, game not complete
123 if len(self.rolls) <= tenth_frame_start:
124 return False
125
126 tenth_frame_first = self.rolls[tenth_frame_start]
127
128 # If 10th frame was a strike, need 2 fill balls (total 3 rolls for 10th frame)
129 if tenth_frame_first == 10:
130 return len(self.rolls) >= tenth_frame_start + 3
131 # If we don't have second roll of 10th frame yet
132 elif len(self.rolls) < tenth_frame_start + 2:
133 return False
134 # If 10th frame was a spare, need 1 fill ball (total 3 rolls for 10th frame)
135 elif tenth_frame_first + self.rolls[tenth_frame_start + 1] == 10:
136 return len(self.rolls) >= tenth_frame_start + 3
137 # Open frame, no fill balls needed (total 2 rolls for 10th frame)
138 else:
139 return len(self.rolls) >= tenth_frame_start + 2
140
141 def _find_frame_start(self, roll_position):
142 """
143 Find the starting index of the frame that contains the given roll position.
144
145 Args:
146 roll_position (int): The position we want to find the frame start for.
147
148 Returns:
149 int: Index of the first roll of the frame, or None if not found.
150 """
151 frame_count = 0
152 roll_index = 0
153
154 while roll_index < roll_position and frame_count < 10:
155 if roll_index >= len(self.rolls):
156 break
157
158 if self.rolls[roll_index] == 10:
159 frame_count += 1
160 roll_index += 1
161 else:
162 if roll_index + 1 >= len(self.rolls):
163 break
164 frame_count += 1
165 roll_index += 2
166
167 return roll_index if roll_index < roll_position else None
168
169 def _find_tenth_frame_start(self):
170 """
171 Find the starting index of the 10th frame.
172
173 Returns:
174 int: Index of the first roll of the 10th frame, or None if not found.
175 """
176 frame_count = 0
177 roll_index = 0
178
179 while roll_index < len(self.rolls) and frame_count < 9:
180 if self.rolls[roll_index] == 10:
181 frame_count += 1
182 roll_index += 1
183 else:
184 if roll_index + 1 >= len(self.rolls):
185 return None
186 frame_count += 1
187 roll_index += 2
188
189 return roll_index if frame_count == 9 else None
190
191 def is_strike(self, roll_index):
192 """
193 Check if the roll at roll_index is a strike.
194
195 Args:
196 roll_index (int): Index of the roll to check.
197
198 Returns:
199 bool: True if the roll is a strike, False otherwise.
200 """
201 return self.rolls[roll_index] == 10
202
203 def is_spare(self, roll_index):
204 """
205 Check if the frame starting at roll_index is a spare.
206
207 Args:
208 roll_index (int): Index of the first roll of the frame.
209
210 Returns:
211 bool: True if the frame is a spare, False otherwise.
212 """
213 return self.rolls[roll_index] + self.rolls[roll_index + 1] == 10
214
215 def sum_of_balls_in_frame(self, roll_index):
216 """
217 Calculate the sum of pins knocked down in a frame.
218
219 Args:
220 roll_index (int): Index of the first roll of the frame.
221
222 Returns:
223 int: Sum of pins knocked down in the frame.
224 """
225 return self.rolls[roll_index] + self.rolls[roll_index + 1]
226
227 def spare_bonus(self, roll_index):
228 """
229 Calculate the bonus for a spare.
230
231 Args:
232 roll_index (int): Index of the first roll of the spare frame.
233
234 Returns:
235 int: The bonus points for the spare.
236 """
237 return self.rolls[roll_index + 2]
238
239 def strike_bonus(self, roll_index):
240 """
241 Calculate the bonus for a strike.
242
243 Args:
244 roll_index (int): Index of the strike roll.
245
246 Returns:
247 int: The bonus points for the strike.
248 """
249 return self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
250
251 def can_roll_fill_ball(self):
252 """
253 Determine if a fill ball can be rolled based on the 10th frame.
254
255 Returns:
256 bool: True if a fill ball can be rolled, False otherwise.
257 """
258 # Game must have at least 12 rolls to need fill balls
259 if len(self.rolls) < 12:
260 return False
261
262 # Find the start of the 10th frame
263 tenth_frame_start = self._find_tenth_frame_start()
264 if tenth_frame_start is None:
265 return False
266
267 # Check if we're in a position to roll fill balls
268 if len(self.rolls) < tenth_frame_start + 2:
269 return False
270
271 tenth_frame_first = self.rolls[tenth_frame_start]
272
273 # If 10th frame was a strike, we need two fill balls
274 if tenth_frame_first == 10:
275 return len(self.rolls) < tenth_frame_start + 3
276
277 # If 10th frame was a spare, we need one fill ball
278 elif (tenth_frame_start + 1 < len(self.rolls) and
279 tenth_frame_first + self.rolls[tenth_frame_start + 1] == 10):
280 return len(self.rolls) < tenth_frame_start + 3
281
282 # If 10th frame was open, no fill balls needed
283 else:
284 return False
285
286 # Handled Edge Cases: Invalid number of pins (negative), Invalid number of pins (more than 10), Game already has 10 frames and no more rolls are allowed, In last frame check if roll is valid, In regular frames check if frame would exceed 10 pins
287 # Handled Edge Cases: Game is not complete, Not enough rolls, Exactly 9 frames but 9th frame is a strike, 10 frames but need fill balls, 10 frames with fill balls
Test NameStatus
test_the_second_bonus_rolls_after_a_strike_in_the_last_frame_cannot_be_a_strike_if_the_first_one_is_not_a_strike
Fail
test_two_bonus_rolls_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points
Fail
test_a_roll_cannot_score_more_than_10_points
Pass
test_a_spare_followed_by_zeros_is_worth_ten_points
Pass
test_a_spare_in_the_last_frame_gets_a_one_roll_bonus_that_is_counted_once
Pass
test_a_strike_earns_ten_points_in_a_frame_with_a_single_roll
Pass
test_a_strike_in_the_last_frame_gets_a_two_roll_bonus_that_is_counted_once
Pass
test_a_strike_with_the_one_roll_bonus_after_a_spare_in_the_last_frame_does_not_get_a_bonus
Pass
test_all_strikes_is_a_perfect_game
Pass
test_an_incomplete_game_cannot_be_scored
Pass
test_an_unstarted_game_cannot_be_scored
Pass
test_bonus_roll_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points
Pass
test_bonus_roll_for_a_spare_in_the_last_frame_must_be_rolled_before_score_can_be_calculated
Pass
test_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated
Pass
test_both_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated
Pass
test_cannot_roll_after_bonus_roll_for_spare
Pass
test_cannot_roll_after_bonus_rolls_for_strike
Pass
test_cannot_roll_if_game_already_has_ten_frames
Pass
test_consecutive_spares_each_get_a_one_roll_bonus
Pass
test_consecutive_strikes_each_get_the_two_roll_bonus
Pass
test_last_two_strikes_followed_by_only_last_bonus_with_non_strike_points
Pass
test_points_scored_in_the_roll_after_a_spare_are_counted_twice
Pass
test_points_scored_in_the_two_rolls_after_a_strike_are_counted_twice_as_a_bonus
Pass
test_rolling_a_spare_with_the_two_roll_bonus_does_not_get_a_bonus_roll
Pass
test_rolls_cannot_score_negative_points
Pass
test_second_bonus_roll_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points
Pass
test_should_be_able_to_score_a_game_with_all_zeros
Pass
test_should_be_able_to_score_a_game_with_no_strikes_or_spares
Pass
test_strikes_with_the_two_roll_bonus_do_not_get_bonus_rolls
Pass
test_two_bonus_rolls_after_a_strike_in_the_last_frame_can_score_more_than_10_points_if_one_is_a_strike
Pass
test_two_rolls_in_a_frame_cannot_score_more_than_10_points
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.