let it go

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a new bowling game.
5
6 Creates a game with 10 frames, tracking rolls and whether the game is complete.
7 """
8 self.frames = [[] for _ in range(10)] # 10 frames
9 self.current_frame = 0
10 self.game_complete = False
11
512 def roll(self, pins):
6 pass
7
13 """
14 Record a roll in the current frame.
15
16 Args:
17 pins (int): Number of pins knocked down in this roll (0-10)
18
19 Raises:
20 ValueError: If pins is negative, greater than 10, or if game is already complete
21 IndexError: If attempting invalid rolls in the 10th frame
22 """
23 # Edge Case: Game already complete
24 if self.game_complete:
25 raise ValueError("game already complete")
26
27 # Edge Case: Invalid pin count
28 if pins < 0:
29 raise ValueError("pins cannot be negative")
30 if pins > 10:
31 raise ValueError("pin count exceeds pins on the lane")
32
33 # Edge Case: Attempting to roll when game is already complete
34 if self.current_frame >= 10:
35 raise ValueError("game already complete")
36
37 current_frame_rolls = self.frames[self.current_frame]
38
39 # Edge Case: First roll of a frame
40 if len(current_frame_rolls) == 0:
41 current_frame_rolls.append(pins)
42 # If it's a strike and not in the 10th frame, move to next frame
43 if pins == 10 and self.current_frame < 9:
44 self.current_frame += 1
45 return
46
47 # Edge Case: Second roll of a frame
48 if len(current_frame_rolls) == 1:
49 # Edge Case: Total pins in frame exceed 10 (except 10th frame)
50 if self.current_frame < 9 and current_frame_rolls[0] + pins > 10:
51 raise ValueError("pin count exceeds pins on the lane")
52
53 current_frame_rolls.append(pins)
54 # Move to next frame if not the 10th frame
55 if self.current_frame < 9:
56 self.current_frame += 1
57 else:
58 # Edge Case: 10th frame management
59 # If it's a spare or strike, we might need more rolls
60 if sum(current_frame_rolls) >= 10:
61 # We need fill balls
62 if len(self.frames[9]) < 3:
63 return
64 # Otherwise, the game is complete
65 self.game_complete = True
66 return
67
68 # Edge Case: Third roll (only possible in 10th frame)
69 if len(current_frame_rolls) == 2:
70 # Edge Case: Invalid fill balls
71 if self.current_frame != 9:
72 raise ValueError("game already complete")
73
74 # Edge Case: Invalid fill ball values
75 # First fill ball after strike can be anything
76 # Second fill ball has constraints
77 if len(current_frame_rolls) == 2:
78 # If first two rolls are a strike followed by non-strike
79 if current_frame_rolls[0] == 10 and current_frame_rolls[1] < 10:
80 if current_frame_rolls[1] + pins > 10:
81 raise ValueError("pin count exceeds pins on the lane")
82
83 current_frame_rolls.append(pins)
84 self.game_complete = True
85 return
86
887 def score(self):
9 pass
88 """
89 Calculate the total score for the game.
90
91 Returns:
92 int: The total score of the game
93
94 Raises:
95 IndexError: If the game is not yet complete
96 """
97 # Edge Case: Game not complete
98 if not self.game_complete:
99 raise IndexError("game not complete")
100
101 total_score = 0
102
103 # Edge Case: Calculate scores for frames 1-9
104 for frame_index in range(9): # Frames 0-8
105 frame_rolls = self.frames[frame_index]
106 frame_score = sum(frame_rolls)
107
108 # Edge Case: Strike scoring
109 if len(frame_rolls) == 1 and frame_rolls[0] == 10: # Strike
110 # Add next two rolls
111 if self.frames[frame_index + 1]: # Next frame has rolls
112 next_frame_rolls = self.frames[frame_index + 1]
113 if len(next_frame_rolls) >= 2:
114 # Normal case: next frame has two rolls
115 frame_score += next_frame_rolls[0] + next_frame_rolls[1]
116 elif len(next_frame_rolls) == 1:
117 # Next frame has only one roll (it's a strike)
118 frame_score += next_frame_rolls[0]
119 # Need to look at the frame after that
120 if frame_index + 2 < 10 and self.frames[frame_index + 2]:
121 frame_score += self.frames[frame_index + 2][0]
122
123 # Edge Case: Spare scoring
124 elif len(frame_rolls) == 2 and frame_score == 10: # Spare
125 # Add next roll
126 if frame_index + 1 < 10 and self.frames[frame_index + 1]:
127 frame_score += self.frames[frame_index + 1][0]
128
129 total_score += frame_score
130
131 # Edge Case: Calculate score for 10th frame
132 tenth_frame_rolls = self.frames[9]
133 tenth_frame_score = sum(tenth_frame_rolls)
134 total_score += tenth_frame_score
135
136 return total_score
137 # Handled Edge Cases: Game not complete, strike scoring with various combinations,
138 # spare scoring, normal frame scoring
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.