perfect

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 pin count (negative)
20 if pins < 0:
21 raise ValueError("Pins must be between 0 and 10")
22
23 # Edge Case: Invalid pin count (more than 10)
24 if pins > 10:
25 raise ValueError("Pins must be between 0 and 10")
26
27 # Edge Case: Check if game is already complete
28 if self._is_game_complete():
29 raise IndexError("Game is already complete")
30
31 # Edge Case: In a frame, the sum of pins from two rolls exceeds 10
32 # This only applies to non-strike frames
33 if self.current_roll % 2 == 1: # Second roll of a frame
34 # But not in the 10th frame, where special rules apply
35 frame_index = self.current_roll // 2
36 if frame_index < 9: # Not the 10th frame
37 # Only check if the first roll wasn't a strike
38 if self.rolls[-1] != 10 and self.rolls[-1] + pins > 10:
39 raise ValueError("Cannot knock down more pins than remaining")
40
41 # Edge Case: Special validation for 10th frame fill balls
42 if len(self.rolls) >= 18: # We're in the 10th frame
43 tenth_frame_rolls = self.rolls[18:]
44
45 # If first roll was a strike and we have a second roll
46 if len(tenth_frame_rolls) == 1 and tenth_frame_rolls[0] == 10:
47 # Second roll after strike can be 0-10
48 pass # No validation needed here
49
50 # If first roll was a strike and we have a second roll, now adding third
51 elif len(tenth_frame_rolls) == 2 and tenth_frame_rolls[0] == 10:
52 # If second roll was also a strike, third roll can be 0-10
53 if tenth_frame_rolls[1] == 10:
54 pass # No validation needed
55 # If second roll wasn't a strike, third roll can't exceed remaining pins
56 else:
57 if tenth_frame_rolls[1] + pins > 10:
58 raise ValueError("Cannot knock down more pins than remaining")
59
60 # If we have two rolls that make a spare, adding third roll
61 elif len(tenth_frame_rolls) == 2 and tenth_frame_rolls[0] + tenth_frame_rolls[1] == 10:
62 # Third roll after spare can be 0-10
63 pass # No validation needed
64
65 self.rolls.append(pins)
66 self.current_roll += 1
67
868 def score(self):
9 pass
69 """
70 Calculate the total score for the game.
71
72 Returns:
73 int: The total score of the game.
74
75 Raises:
76 IndexError: If the game is not yet complete.
77 """
78 # Edge Case: Game is not complete
79 if not self._is_game_complete():
80 raise IndexError("Game is not yet complete")
81
82 total_score = 0
83 roll_index = 0
84
85 for frame in range(10):
86 # Edge Case: Strike in frames 1-9
87 if frame < 9 and roll_index < len(self.rolls) and self.rolls[roll_index] == 10: # Strike
88 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
89 roll_index += 1
90 # Edge Case: Spare in frames 1-9
91 elif frame < 9 and roll_index + 1 < len(self.rolls) and self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare
92 total_score += 10 + self.rolls[roll_index + 2]
93 roll_index += 2
94 # Edge Case: Open frame in frames 1-9
95 elif frame < 9: # Open frame
96 total_score += self.rolls[roll_index] + self.rolls[roll_index + 1]
97 roll_index += 2
98 # Edge Case: 10th frame - special handling
99 else:
100 # Handle the 10th frame differently
101 if roll_index < len(self.rolls):
102 # If we have enough rolls for the 10th frame
103 if frame == 9:
104 # 10th frame scoring - just sum all remaining rolls
105 while roll_index < len(self.rolls):
106 total_score += self.rolls[roll_index]
107 roll_index += 1
108 else:
109 # Regular frame
110 total_score += self.rolls[roll_index] + self.rolls[roll_index + 1]
111 roll_index += 2
112
113 return total_score
114
115 def _is_game_complete(self):
116 """
117 Check if the game is complete.
118
119 Returns:
120 bool: True if the game is complete, False otherwise.
121 """
122 # Need at least 10 frames
123 if len(self.rolls) < 10:
124 return False
125
126 # Count frames properly
127 frame_count = 0
128 roll_index = 0
129
130 # Count the first 9 frames
131 while frame_count < 9 and roll_index < len(self.rolls):
132 if self.rolls[roll_index] == 10: # Strike
133 frame_count += 1
134 roll_index += 1
135 elif roll_index + 1 < len(self.rolls): # Regular frame
136 frame_count += 1
137 roll_index += 2
138 else: # Incomplete frame
139 return False
140
141 # If we haven't completed 9 frames, game is not complete
142 if frame_count < 9:
143 return False
144
145 # Now handle the 10th frame
146 if roll_index >= len(self.rolls):
147 return False # No rolls for 10th frame yet
148
149 tenth_frame_first = self.rolls[roll_index]
150
151 # Strike in 10th frame - need 2 fill balls
152 if tenth_frame_first == 10:
153 if roll_index + 2 >= len(self.rolls):
154 return False # Need 2 more rolls
155 elif roll_index + 2 == len(self.rolls) - 1:
156 # Have first roll and one fill ball
157 return False
158 else:
159 # Have first roll and 2 fill balls
160 return roll_index + 3 == len(self.rolls)
161
162 # Need second roll for 10th frame
163 if roll_index + 1 >= len(self.rolls):
164 return False
165
166 tenth_frame_second = self.rolls[roll_index + 1]
167
168 # Spare in 10th frame - need 1 fill ball
169 if tenth_frame_first + tenth_frame_second == 10:
170 return roll_index + 3 == len(self.rolls)
171
172 # Open frame in 10th frame - no fill balls needed
173 else:
174 return roll_index + 2 == len(self.rolls)
175
176 def _is_valid_fill_ball(self):
177 """
178 Check if a roll is a valid fill ball.
179
180 Returns:
181 bool: True if the roll is a valid fill ball, False otherwise.
182 """
183 # This method is no longer needed since we check game completion first
184 return False
185
186 # Handled Edge Cases: Invalid pin count (negative or more than 10), Game already has 20 rolls (10 frames completed), In a frame, the sum of pins from two rolls exceeds 10, Game is not complete, Less than 10 frames played, Strike in frames 1-9, Spare in frames 1-9, Open frame in frames 1-9, Trying to roll after game is complete but it's a valid fill ball, Must have at least 18 rolls to be in the 10th frame, If we have exactly 18 rolls we're starting the 10th frame, If we have 19 rolls check if we need a fill ball, If we have 20 rolls check if we need another fill ball, If we have 21 rolls we're done
Test NameStatus
test_a_strike_in_the_last_frame_gets_a_two_roll_bonus_that_is_counted_once
Fail
test_all_strikes_is_a_perfect_game
Fail
test_cannot_roll_after_bonus_rolls_for_strike
Fail
test_last_two_strikes_followed_by_only_last_bonus_with_non_strike_points
Fail
test_rolling_a_spare_with_the_two_roll_bonus_does_not_get_a_bonus_roll
Fail
test_strikes_with_the_two_roll_bonus_do_not_get_bonus_rolls
Fail
test_two_bonus_rolls_after_a_strike_in_the_last_frame_can_score_more_than_10_points_if_one_is_a_strike
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_with_the_one_roll_bonus_after_a_spare_in_the_last_frame_does_not_get_a_bonus
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_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_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_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_the_second_bonus_rolls_after_a_strike_in_the_last_frame_cannot_be_a_strike_if_the_first_one_is_not_a_strike
Pass
test_two_bonus_rolls_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points
Pass
test_two_rolls_in_a_frame_cannot_score_more_than_10_points
Pass

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