let it go

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a new bowling game.
5 """
6 self.rolls = []
7 self.frame_scores = []
8 self.current_frame = 0
9 self.frame_rolls = []
10
11 def is_game_complete(self):
12 """
13 Check if the game is complete.
14
15 Returns:
16 bool: True if the game is complete, False otherwise
17 """
18 # For the 10th frame (current_frame == 9), check if all required rolls are done
19 if self.current_frame == 9:
20 # If we have 3 rolls in the 10th frame, game is complete
21 if len(self.frame_rolls) == 3:
22 return True
23 # If we have 2 rolls and it's not a spare or strike, game is complete
24 elif len(self.frame_rolls) == 2:
25 if self.frame_rolls[0] != 10 and sum(self.frame_rolls) != 10:
26 return True
27 # If it's a spare or strike, we need more rolls
28 else:
29 return False
30 # If we have 1 roll, we need more rolls (either 1 more for open frame or 2 more for strike)
31 elif len(self.frame_rolls) == 1:
32 return False
33 # If we have 0 rolls but 10 frame scores, it means 10th frame was completed
34 elif len(self.frame_rolls) == 0 and len(self.frame_scores) == 10:
35 return True
36
37 # If we have 10 frame scores and we've moved past the 10th frame, the game is complete
38 elif len(self.frame_scores) == 10 and self.current_frame >= 10:
39 return True
40
41 return False
42
543 def roll(self, pins):
6 pass
7
44 """
45 Record a roll in the game.
46
47 Args:
48 pins (int): Number of pins knocked down in this roll
49
50 Raises:
51 ValueError: If pins is negative or greater than 10
52 IndexError: If game is already over
53 """
54 # Edge Case: Invalid number of pins
55 if pins < 0:
56 raise ValueError("Pins cannot be negative")
57
58 # Edge Case: Too many pins in a single roll
59 if pins > 10:
60 raise ValueError("Pins cannot be more than 10")
61
62 # Edge Case: Game already completed
63 if self.is_game_complete():
64 raise IndexError("Game has already ended")
65
66 # Edge Case: Tenth frame special rules
67 if self.current_frame == 9: # Tenth frame
68 # Add roll to current frame
69 self.frame_rolls.append(pins)
70
71 # If it's the first roll of the tenth frame
72 if len(self.frame_rolls) == 1:
73 self.rolls.append(pins)
74 return
75
76 # If it's the second roll of the tenth frame
77 elif len(self.frame_rolls) == 2:
78 # Validate that the frame total doesn't exceed 10 (unless first roll was a strike)
79 if self.frame_rolls[0] != 10 and (self.frame_rolls[0] + pins) > 10:
80 raise ValueError("Frame cannot have more than 10 pins")
81
82 self.rolls.append(pins)
83 # Check if we need a third roll (spare or strike)
84 if self.frame_rolls[0] == 10 or sum(self.frame_rolls) == 10:
85 # Need a third roll for spare or second strike
86 return
87 else:
88 # Open frame, game over
89 self.frame_scores.append(sum(self.frame_rolls))
90 self.frame_rolls = [] # Clear the frame rolls
91 self.current_frame += 1 # Move past the 10th frame
92 return
93
94 # If it's the third roll of the tenth frame
95 elif len(self.frame_rolls) == 3:
96 # Validate the third roll based on what the second roll was
97 # If first roll was a strike, we need to validate second + third rolls
98 if self.frame_rolls[0] == 10:
99 # If second roll was also a strike, third roll can be anything up to 10
100 if self.frame_rolls[1] == 10:
101 if pins > 10:
102 raise ValueError("Pins cannot be more than 10")
103 # If second roll was not a strike, validate that second + third <= 10
104 else:
105 if self.frame_rolls[1] + pins > 10:
106 raise ValueError("Frame cannot have more than 10 pins")
107 # If first roll was not a strike but we got a spare, third roll can be anything up to 10
108 else:
109 if pins > 10:
110 raise ValueError("Pins cannot be more than 10")
111
112 self.rolls.append(pins)
113 self.frame_scores.append(sum(self.frame_rolls))
114 self.frame_rolls = [] # Clear the frame rolls
115 self.current_frame += 1 # Move past the 10th frame
116 return
117
118 # Regular frames (1-9)
119 self.frame_rolls.append(pins)
120 self.rolls.append(pins)
121
122 # If we have a strike
123 if pins == 10 and len(self.frame_rolls) == 1:
124 self.frame_scores.append(10)
125 self.current_frame += 1
126 self.frame_rolls = []
127 return
128
129 # If we have two rolls in a frame
130 if len(self.frame_rolls) == 2:
131 frame_total = sum(self.frame_rolls)
132
133 # Edge Case: Invalid frame total
134 if frame_total > 10 and self.frame_rolls[0] != 10:
135 raise ValueError("Frame cannot have more than 10 pins")
136
137 self.frame_scores.append(frame_total)
138 self.current_frame += 1
139 self.frame_rolls = []
140
8141 def score(self):
9 pass
142 """
143 Calculate the total score for the game.
144
145 Returns:
146 int: The total score for the game
147
148 Raises:
149 IndexError: If the game is not yet complete
150 """
151 # Edge Case: Game not complete
152 if not self.is_game_complete():
153 raise IndexError("Game is not yet complete")
154
155 total_score = 0
156 roll_index = 0
157
158 # Score first 9 frames
159 frame = 0
160 while frame < 9 and roll_index < len(self.rolls):
161 if self.rolls[roll_index] == 10: # Strike
162 # Add 10 plus next two rolls
163 if roll_index + 2 < len(self.rolls):
164 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
165 roll_index += 1
166 elif roll_index + 1 < len(self.rolls) and self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare
167 # Add 10 plus next roll
168 if roll_index + 2 < len(self.rolls):
169 total_score += 10 + self.rolls[roll_index + 2]
170 roll_index += 2
171 else: # Open frame
172 if roll_index + 1 < len(self.rolls):
173 total_score += self.rolls[roll_index] + self.rolls[roll_index + 1]
174 roll_index += 2
175 frame += 1
176
177 # Score tenth frame - add all rolls in the tenth frame
178 # The tenth frame score is already calculated and stored in frame_scores[9]
179 if len(self.frame_scores) > 9:
180 total_score += self.frame_scores[9]
181 else:
182 # This shouldn't happen if game is complete, but just in case
183 for i in range(roll_index, len(self.rolls)):
184 total_score += self.rolls[i]
185
186 return total_score
187
188 # Handled Edge Cases: Invalid number of pins, too many pins, game already completed, tenth frame special rules, invalid frame total, game not complete, tenth frame incomplete
Test NameStatus
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_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_can_score_more_than_10_points_if_one_is_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.