relax

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a new bowling game.
5 """
6 self.rolls = []
7 self.current_frame = 1
8 self.frame_rolls = []
9 self.frames = []
10
511 def roll(self, pins):
6 pass
7
12 """
13 Record a roll in the game.
14
15 Args:
16 pins (int): Number of pins knocked down in this roll
17
18 Raises:
19 ValueError: If pins is negative or greater than 10
20 ValueError: If trying to roll after the game is over
21 """
22 # Edge Case: Invalid number of pins
23 if pins < 0:
24 raise ValueError("Negative roll is invalid")
25 if pins > 10:
26 raise ValueError("Pin count exceeds pins on the lane")
27
28 # Edge Case: Game already completed
29 if len(self.frames) == 10:
30 raise ValueError("Cannot roll after game is over")
31
32 self.frame_rolls.append(pins)
33 self.rolls.append(pins)
34
35 # Handle regular frames (1-9)
36 if self.current_frame < 10:
37 # Strike case - frame ends immediately
38 if pins == 10 and len(self.frame_rolls) == 1:
39 self.frames.append(self.frame_rolls[:])
40 self.frame_rolls = []
41 self.current_frame += 1
42 # Two rolls completed
43 elif len(self.frame_rolls) == 2:
44 # Edge Case: Frame total exceeds 10 (except for strikes which are handled above)
45 if sum(self.frame_rolls) > 10:
46 raise ValueError("Pin count exceeds pins on the lane")
47 self.frames.append(self.frame_rolls[:])
48 self.frame_rolls = []
49 self.current_frame += 1
50 # Handle 10th frame
51 else:
52 # First roll is a strike
53 if len(self.frame_rolls) == 1 and self.frame_rolls[0] == 10:
54 # Need two more rolls
55 if len(self.frame_rolls) == 3:
56 # Edge Case: Invalid fill balls - second and third rolls exceed 10
57 if self.frame_rolls[1] < 10 and self.frame_rolls[1] + self.frame_rolls[2] > 10:
58 raise ValueError("Pin count exceeds pins on the lane")
59 self.frames.append(self.frame_rolls[:])
60 self.frame_rolls = []
61 # First roll not a strike, second roll makes a spare
62 elif len(self.frame_rolls) == 2 and sum(self.frame_rolls) == 10:
63 # Need one more roll
64 if len(self.frame_rolls) == 3:
65 self.frames.append(self.frame_rolls[:])
66 self.frame_rolls = []
67 # Open frame (less than 10 pins in first two rolls)
68 elif len(self.frame_rolls) == 2 and sum(self.frame_rolls) < 10:
69 self.frames.append(self.frame_rolls[:])
70 self.frame_rolls = []
71 # Regular case with 3 rolls
72 elif len(self.frame_rolls) == 3:
73 # Edge Case: Invalid fill balls - check if rolls are valid
74 if self.frame_rolls[0] != 10: # First roll wasn't a strike
75 if self.frame_rolls[0] + self.frame_rolls[1] > 10 and self.frame_rolls[0] != 10:
76 raise ValueError("Pin count exceeds pins on the lane")
77 if self.frame_rolls[0] + self.frame_rolls[1] < 10 and len(self.frame_rolls) == 3:
78 raise ValueError("Should not have 3 rolls in 10th frame with open frame")
79 if self.frame_rolls[0] + self.frame_rolls[1] == 10 and self.frame_rolls[2] > 10:
80 raise ValueError("Pin count exceeds pins on the lane")
81 else: # First roll was a strike
82 if self.frame_rolls[1] != 10 and self.frame_rolls[1] + self.frame_rolls[2] > 10:
83 raise ValueError("Pin count exceeds pins on the lane")
84 self.frames.append(self.frame_rolls[:])
85 self.frame_rolls = []
86
887 def score(self):
9 pass
88 """
89 Calculate the total score for the game.
90
91 Returns:
92 int: The total score for the game
93
94 Raises:
95 ValueError: If the game is not yet complete
96 """
97 # Edge Case: Game not complete
98 if len(self.frames) < 10:
99 raise ValueError("Score cannot be taken until the end of the game")
100
101 total_score = 0
102 roll_index = 0
103
104 for frame_index in range(10):
105 frame = self.frames[frame_index]
106
107 # First 9 frames
108 if frame_index < 9:
109 if len(frame) == 1 and frame[0] == 10: # Strike
110 total_score += 10
111 # Add next two rolls
112 if len(self.frames[frame_index + 1]) >= 2:
113 total_score += self.frames[frame_index + 1][0] + self.frames[frame_index + 1][1]
114 elif len(self.frames[frame_index + 1]) == 1: # Next frame is also a strike
115 total_score += 10
116 if frame_index + 2 < len(self.frames):
117 if len(self.frames[frame_index + 2]) > 0:
118 total_score += self.frames[frame_index + 2][0]
119 elif len(frame) == 2 and sum(frame) == 10: # Spare
120 total_score += 10 + self.frames[frame_index + 1][0]
121 else: # Open frame
122 total_score += sum(frame)
123 # 10th frame
124 else:
125 total_score += sum(frame)
126
127 return total_score
128
129 # Handled Edge Cases: Invalid number of pins, game already completed, frame total exceeds 10,
130 # invalid fill balls, game not complete
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.