let it go

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
3 """
4 Initialize a new bowling game.
5 """
6 self.rolls = []
47
58 def roll(self, pins):
6 pass
7
9 """
10 Record a roll in the game.
11
12 Args:
13 pins (int): Number of pins knocked down in this roll
14
15 Raises:
16 ValueError: If the number of pins is invalid
17 IndexError: If game is already finished
18 """
19 # Edge Case: Game already finished
20 if self.is_finished():
21 raise IndexError("Game has already ended")
22
23 # Edge Case: Invalid pin count (negative)
24 if pins < 0:
25 raise ValueError("Pins must be between 0 and 10")
26
27 # Edge Case: Invalid pin count (more than 10)
28 if pins > 10:
29 raise ValueError("Pin count exceeds pins on the lane")
30
31 # Edge Case: Too many pins in a frame (not tenth frame)
32 if not self._is_tenth_frame() and len(self.rolls) > 0:
33 # Check if this is the second roll of a frame and the first wasn't a strike
34 if len(self.rolls) % 2 == 1 and self.rolls[-1] != 10 and self.rolls[-1] + pins > 10:
35 raise ValueError("Cannot knock down more than 10 pins in a frame")
36
37 # Edge Case: Invalid fill balls in tenth frame
38 if self._is_tenth_frame():
39 # Check if we already have the maximum allowed rolls in 10th frame
40 tenth_frame_rolls = self._tenth_frame_roll_count()
41 if tenth_frame_rolls >= 3:
42 raise ValueError("invalid fill balls")
43
44 # Add the roll
45 self.rolls.append(pins)
46
847 def score(self):
9 pass
48 """
49 Calculate the total score for the game.
50
51 Returns:
52 int: The total score for the game
53
54 Raises:
55 IndexError: If the game is not yet complete
56 """
57 # Edge Case: Game not finished
58 if not self.is_finished():
59 raise IndexError("Game is not yet complete")
60
61 total_score = 0
62 roll_index = 0
63
64 # Score frames 1-10
65 for frame in range(10):
66 # Strike (first roll of frame is 10)
67 if self._is_strike(roll_index):
68 total_score += 10 + self._next_two_balls(roll_index)
69 roll_index += 1
70 # Spare (sum of two rolls in frame is 10)
71 elif self._is_spare(roll_index):
72 total_score += 10 + self._next_ball(roll_index + 2)
73 roll_index += 2
74 # Open frame
75 else:
76 total_score += self.rolls[roll_index] + self.rolls[roll_index + 1]
77 roll_index += 2
78
79 return total_score
80
81 def _is_strike(self, roll_index):
82 """Check if the roll at roll_index is a strike"""
83 return self.rolls[roll_index] == 10
84
85 def _is_spare(self, roll_index):
86 """Check if the frame starting at roll_index is a spare"""
87 # Make sure we have two rolls for this frame
88 if roll_index + 1 >= len(self.rolls):
89 return False
90 return self.rolls[roll_index] + self.rolls[roll_index + 1] == 10
91
92 def _next_ball(self, roll_index):
93 """Get the value of the ball at roll_index"""
94 if roll_index >= len(self.rolls):
95 return 0
96 return self.rolls[roll_index]
97
98 def _next_two_balls(self, roll_index):
99 """Get the sum of the next two balls after roll_index"""
100 total = 0
101 if roll_index + 1 < len(self.rolls):
102 total += self.rolls[roll_index + 1]
103 if roll_index + 2 < len(self.rolls):
104 total += self.rolls[roll_index + 2]
105 return total
106
107 def _tenth_frame_roll_count(self):
108 """Count how many rolls have been made in the tenth frame"""
109 if not self._is_tenth_frame():
110 return 0
111
112 # Count frames to find where 10th frame starts
113 frame_count = 0
114 roll_index = 0
115
116 while roll_index < len(self.rolls) and frame_count < 9:
117 if roll_index < len(self.rolls) and self.rolls[roll_index] == 10:
118 roll_index += 1
119 else:
120 roll_index += 2
121 frame_count += 1
122
123 # Return the number of rolls in the 10th frame
124 return len(self.rolls) - roll_index
125
126 def _is_tenth_frame(self):
127 """Check if we're currently in the tenth frame"""
128 # Count complete frames
129 frame_count = 0
130 roll_index = 0
131
132 while roll_index < len(self.rolls) and frame_count < 9:
133 if self.rolls[roll_index] == 10:
134 roll_index += 1
135 else:
136 roll_index += 2
137 frame_count += 1
138
139 # If we've completed 9 frames, we're in the 10th frame
140 return frame_count == 9
141
142 def is_finished(self):
143 """Check if the game is finished"""
144 # Count frames
145 frame_count = 0
146 roll_index = 0
147
148 while roll_index < len(self.rolls) and frame_count < 10:
149 # Frames 1-9
150 if frame_count < 9:
151 if self.rolls[roll_index] == 10:
152 roll_index += 1
153 else:
154 roll_index += 2
155 # Tenth frame special handling
156 else:
157 # Strike gets 2 bonus rolls
158 if self.rolls[roll_index] == 10:
159 # Need 2 more rolls (total of 3 for 10th frame)
160 return len(self.rolls) >= roll_index + 3
161 # Spare gets 1 bonus roll
162 elif roll_index + 1 < len(self.rolls) and self.rolls[roll_index] + self.rolls[roll_index + 1] == 10:
163 # Need 1 more roll (total of 3 for 10th frame)
164 return len(self.rolls) >= roll_index + 3
165 # Open frame
166 else:
167 # Need exactly 2 rolls for 10th frame
168 return len(self.rolls) >= roll_index + 2
169
170 frame_count += 1
171
172 return frame_count >= 10
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.