uv

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 is already over (10 frames completed)
24 if self.is_game_over():
25 raise ValueError("Game is already finished")
26
27 # Edge Case: Invalid frame - sum of pins in a frame exceeds 10 (except for strikes)
28 if (len(self.rolls) % 2 == 1 and not self.is_strike(len(self.rolls) - 1) and
29 self.rolls[-1] + pins > 10):
30 raise ValueError("Cannot knock down more pins than remaining")
31
32 self.rolls.append(pins)
33
834 def score(self):
9 pass
35 """
36 Calculate the total score for the game.
37
38 Returns:
39 int: The total score of the game.
40
41 Raises:
42 ValueError: If the game is not yet complete.
43 """
44 # Edge Case: Game is not complete yet
45 if not self.is_game_over():
46 raise ValueError("game not complete")
47
48 score = 0
49 roll_index = 0
50
51 for frame in range(10):
52 # Edge Case: Strike in regular frames (1-9)
53 if self.is_strike(roll_index) and frame < 9:
54 score += 10 + self.strike_bonus(roll_index)
55 roll_index += 1
56 # Edge Case: Spare in regular frames (1-9)
57 elif self.is_spare(roll_index) and frame < 9:
58 score += 10 + self.spare_bonus(roll_index)
59 roll_index += 2
60 # Edge Case: Open frame in regular frames (1-9)
61 elif frame < 9:
62 score += self.sum_of_balls_in_frame(roll_index)
63 roll_index += 2
64 # Edge Case: Tenth frame handling
65 else: # 10th frame
66 # Edge Case: Strike in 10th frame
67 if self.is_strike(roll_index):
68 # Edge Case: Second strike in 10th frame
69 if self.is_strike(roll_index + 1):
70 # Edge Case: Third strike in 10th frame
71 score += 10 + 10 + self.rolls[roll_index + 2]
72 else:
73 score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
74 # Edge Case: Spare in 10th frame
75 elif self.is_spare(roll_index):
76 score += 10 + self.rolls[roll_index + 2]
77 # Edge Case: Open 10th frame
78 else:
79 score += self.sum_of_balls_in_frame(roll_index)
80 break
81
82 return score
83
84 def is_game_over(self):
85 """
86 Check if the game is over (10 frames have been played).
87
88 Returns:
89 bool: True if the game is over, False otherwise.
90 """
91 if len(self.rolls) < 12: # Minimum rolls needed (9 open frames + 3 rolls in 10th)
92 return False
93
94 roll_index = 0
95 frame_count = 0
96
97 # Count complete frames
98 while frame_count < 10 and roll_index < len(self.rolls):
99 frame_count += 1
100
101 # Edge Case: Strike in regular frames
102 if frame_count < 10 and self.is_strike(roll_index):
103 roll_index += 1
104 # Edge Case: Any frame in 10th position
105 elif frame_count == 10:
106 # Edge Case: Strike in 10th frame
107 if self.is_strike(roll_index):
108 # Need two more rolls
109 if roll_index + 2 < len(self.rolls):
110 return True
111 else:
112 return False
113 # Edge Case: Spare in 10th frame
114 elif roll_index + 1 < len(self.rolls) and self.is_spare(roll_index):
115 # Need one more roll
116 if roll_index + 2 < len(self.rolls):
117 return True
118 else:
119 return False
120 # Edge Case: Open 10th frame
121 else:
122 # Need two rolls
123 if roll_index + 1 < len(self.rolls):
124 return True
125 else:
126 return False
127 else:
128 roll_index += 2
129
130 return frame_count >= 10
131
132 def is_strike(self, roll_index):
133 """
134 Check if a roll is a strike.
135
136 Args:
137 roll_index (int): Index of the roll to check.
138
139 Returns:
140 bool: True if the roll is a strike, False otherwise.
141 """
142 # Edge Case: Index out of bounds
143 if roll_index >= len(self.rolls):
144 return False
145 return self.rolls[roll_index] == 10
146
147 def is_spare(self, roll_index):
148 """
149 Check if two rolls form a spare.
150
151 Args:
152 roll_index (int): Index of the first roll to check.
153
154 Returns:
155 bool: True if the two rolls form a spare, False otherwise.
156 """
157 # Edge Case: Index out of bounds
158 if roll_index + 1 >= len(self.rolls):
159 return False
160 return self.rolls[roll_index] + self.rolls[roll_index + 1] == 10
161
162 def strike_bonus(self, roll_index):
163 """
164 Calculate the bonus for a strike.
165
166 Args:
167 roll_index (int): Index of the strike roll.
168
169 Returns:
170 int: The bonus points for the strike.
171 """
172 # Edge Case: Not enough rolls for bonus calculation
173 if roll_index + 2 >= len(self.rolls):
174 return 0
175 return self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
176
177 def spare_bonus(self, roll_index):
178 """
179 Calculate the bonus for a spare.
180
181 Args:
182 roll_index (int): Index of the first roll in the spare.
183
184 Returns:
185 int: The bonus points for the spare.
186 """
187 # Edge Case: Not enough rolls for bonus calculation
188 if roll_index + 2 >= len(self.rolls):
189 return 0
190 return self.rolls[roll_index + 2]
191
192 def sum_of_balls_in_frame(self, roll_index):
193 """
194 Calculate the sum of pins knocked down in a frame.
195
196 Args:
197 roll_index (int): Index of the first roll in the frame.
198
199 Returns:
200 int: The sum of pins knocked down in the frame.
201 """
202 # Edge Case: Not enough rolls in frame
203 if roll_index + 1 >= len(self.rolls):
204 return self.rolls[roll_index] if roll_index < len(self.rolls) else 0
205 return self.rolls[roll_index] + self.rolls[roll_index + 1]
206
207# Handled Edge Cases: Invalid number of pins, game already over, game not complete, strike in regular frames, spare in regular frames, open frame in regular frames, strike in 10th frame, second strike in 10th frame, third strike in 10th frame, spare in 10th frame, open 10th frame, index out of bounds, not enough rolls for bonus calculation, not enough rolls in frame
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.