@ngel

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a new bowling game.
5
6 Sets up the game state including rolls tracking, current frame, and game completion status.
7 """
8 self.rolls = []
9 self.current_frame = 0
10 self.frames = [[] for _ in range(10)]
11 self.game_over = False
12
513 def roll(self, pins):
6 pass
7
14 """
15 Record a roll in the bowling game.
16
17 Args:
18 pins (int): Number of pins knocked down in this roll (0-10)
19
20 Raises:
21 ValueError: If pins is negative, greater than 10, or if game is already over
22 IndexError: If attempting invalid rolls in tenth frame
23 """
24 # Edge Case: Game already completed
25 if self.game_over:
26 raise ValueError("Game is already complete")
27
28 # Edge Case: Invalid pin count (negative or more than 10)
29 if pins < 0 or pins > 10:
30 raise ValueError("Pins must be between 0 and 10")
31
32 # Edge Case: Attempting to roll after game should be over
33 if self.current_frame >= 10:
34 raise ValueError("Game is already complete")
35
36 # Add roll to current frame
37 self.frames[self.current_frame].append(pins)
38 self.rolls.append(pins)
39
40 # Edge Case: Too many pins in a frame (except 10th frame)
41 if self.current_frame < 9 and len(self.frames[self.current_frame]) == 2:
42 if sum(self.frames[self.current_frame]) > 10:
43 # Remove the invalid roll
44 self.frames[self.current_frame].pop()
45 self.rolls.pop()
46 raise ValueError("Cannot knock down more pins than remaining in frame")
47
48 # Handle tenth frame special cases
49 if self.current_frame == 9: # Tenth frame
50 # Edge Case: Invalid fill ball after spare
51 if len(self.frames[9]) == 2 and sum(self.frames[9][:2]) == 10 and self.frames[9][1] != 10:
52 # After a spare in tenth frame, only one additional roll allowed
53 if len(self.frames[9]) > 3:
54 raise ValueError("invalid fill balls")
55 if len(self.frames[9]) == 3:
56 self.game_over = True
57 return
58
59 # Edge Case: Invalid fill balls after strike
60 elif len(self.frames[9]) >= 2 and self.frames[9][0] == 10:
61 # After a strike in tenth frame, up to two additional rolls allowed
62 if len(self.frames[9]) > 3:
63 raise ValueError("invalid fill balls")
64 if len(self.frames[9]) == 3:
65 # Check if we have a valid second fill ball
66 if self.frames[9][1] != 10 and sum(self.frames[9][1:3]) > 10:
67 raise ValueError("pin count exceeds pins on the lane")
68 if len(self.frames[9]) == 3:
69 self.game_over = True
70 return
71
72 # Edge Case: Tenth frame completed normally (no spare/strike)
73 if len(self.frames[9]) == 2 and sum(self.frames[9]) < 10:
74 self.game_over = True
75 return
76
77 # Edge Case: Tenth frame completed with valid spare or strike sequence
78 if len(self.frames[9]) == 3:
79 self.game_over = True
80 return
81
82 # Handle regular frames (1-9)
83 else:
84 # Move to next frame if frame is complete
85 if len(self.frames[self.current_frame]) == 2 or pins == 10: # Strike or two rolls
86 self.current_frame += 1
87
888 def score(self):
9 pass
89 """
90 Calculate the total score for the bowling game.
91
92 Returns:
93 int: Total score for the game
94
95 Raises:
96 ValueError: If the game is not yet complete
97 """
98 # Edge Case: Attempting to score incomplete game
99 if not self.game_over and (self.current_frame < 9 or
100 (self.current_frame == 9 and len(self.frames[9]) < 2) or
101 (self.current_frame == 9 and len(self.frames[9]) == 2 and sum(self.frames[9]) >= 10)):
102 raise ValueError("Game is not complete")
103
104 # Edge Case: Incomplete tenth frame
105 if self.current_frame < 9 or (self.current_frame == 9 and len(self.frames[9]) < 2):
106 raise ValueError("Game is not complete")
107
108 # Edge Case: Tenth frame spare/strike but no fill balls
109 if self.current_frame == 9 and len(self.frames[9]) == 2 and sum(self.frames[9]) >= 10:
110 raise ValueError("Game is not complete")
111
112 total_score = 0
113 roll_index = 0
114
115 # Score frames 1-9
116 for frame in range(9):
117 # Edge Case: Incomplete frame
118 if roll_index >= len(self.rolls):
119 raise ValueError("Game is not complete")
120
121 frame_score = self.rolls[roll_index]
122
123 # Strike
124 if frame_score == 10:
125 # Edge Case: Not enough rolls for strike bonus
126 if roll_index + 2 >= len(self.rolls):
127 raise ValueError("Game is not complete")
128 frame_score += self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
129 roll_index += 1
130 else:
131 # Edge Case: Not enough rolls
132 if roll_index + 1 >= len(self.rolls):
133 raise ValueError("Game is not complete")
134 frame_score += self.rolls[roll_index + 1]
135
136 # Spare
137 if frame_score == 10:
138 # Edge Case: Not enough rolls for spare bonus
139 if roll_index + 2 >= len(self.rolls):
140 raise ValueError("Game is not complete")
141 frame_score += self.rolls[roll_index + 2]
142 roll_index += 2
143
144 total_score += frame_score
145
146 # Score tenth frame
147 # Edge Case: Missing tenth frame data
148 if len(self.frames[9]) < 2:
149 raise ValueError("Game is not complete")
150
151 tenth_frame_score = sum(self.frames[9])
152 total_score += tenth_frame_score
153
154 return total_score
155
156 # Handled Edge Cases: Game already completed, invalid pin count, attempting roll after game over,
157 # invalid fill ball after spare, invalid fill balls after strike, tenth frame completed normally,
158 # tenth frame completed with valid spare/strike sequence, incomplete game scoring, incomplete frame,
159 # not enough rolls for strike bonus, not enough rolls, not enough rolls for spare bonus, missing tenth frame data
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.