Finished
11class BowlingGame:
22 def __init__(self):
3 pass
3 self.rolls = []
4 self.frame_scores = []
5 self.current_frame = 0
6 self.frame_rolls = [[]]
7 self.game_over = False
48
59 def roll(self, pins):
6 pass
7
10 # Edge Case: Game is already over
11 if self.game_over:
12 raise ValueError("game already complete")
13
14 # Handle tenth frame specially
15 if self.current_frame == 9:
16 # Validate tenth frame rolls
17 if len(self.frame_rolls[9]) == 0:
18 # First roll - validate pin count
19 if pins < 0 or pins > 10:
20 raise ValueError("invalid pin count")
21 elif len(self.frame_rolls[9]) == 1:
22 # Second roll
23 if self.frame_rolls[9][0] == 10:
24 # First roll was strike, second roll is first fill ball
25 if pins < 0 or pins > 10:
26 raise ValueError("invalid fill balls")
27 elif self.frame_rolls[9][0] + pins > 10:
28 raise ValueError("Invalid roll: pins downed exceed 10 in a frame")
29 elif pins < 0 or pins > 10:
30 raise ValueError("invalid pin count")
31 elif len(self.frame_rolls[9]) == 2:
32 # Third roll (fill ball)
33 if self.frame_rolls[9][0] == 10:
34 # First roll was strike
35 if self.frame_rolls[9][1] == 10:
36 # Second roll was also strike, third roll is second fill ball
37 if pins < 0 or pins > 10:
38 raise ValueError("invalid fill balls")
39 elif self.frame_rolls[9][1] + pins > 10:
40 raise ValueError("invalid fill balls")
41 elif pins < 0 or pins > 10:
42 raise ValueError("invalid fill balls")
43 elif self.frame_rolls[9][0] + self.frame_rolls[9][1] == 10:
44 # First two rolls make a spare, third roll is fill ball
45 if pins < 0 or pins > 10:
46 raise ValueError("invalid fill balls")
47 else:
48 # First two rolls don't make a spare, no third roll allowed
49 raise ValueError("Cannot throw bonus with an open tenth frame")
50 else:
51 # Already have 3 rolls in 10th frame
52 raise ValueError("game already complete")
53 else:
54 # Edge Case: Invalid pin count (negative or more than 10)
55 if pins < 0 or pins > 10:
56 raise ValueError("invalid pin count")
57 # Edge Case: Too many pins on second roll of a frame (not tenth)
58 if (len(self.frame_rolls[self.current_frame]) == 1 and
59 self.frame_rolls[self.current_frame][0] + pins > 10):
60 raise ValueError("Invalid roll: pins downed exceed 10 in a frame")
61
62 self.rolls.append(pins)
63 self.frame_rolls[self.current_frame].append(pins)
64
65 # Handle frame progression
66 if self.current_frame == 9:
67 # Handle tenth frame specially
68 # Game is over after valid second roll if not a spare or strike
69 if (len(self.frame_rolls[9]) == 2 and
70 self.frame_rolls[9][0] + self.frame_rolls[9][1] < 10):
71 self.game_over = True
72 # Game is over after valid third roll
73 elif len(self.frame_rolls[9]) == 3:
74 self.game_over = True
75 else:
76 # For frames 0-8, move to next frame immediately if strike
77 # or after second roll for non-strike frames
78 if (len(self.frame_rolls[self.current_frame]) == 2 or
79 (len(self.frame_rolls[self.current_frame]) == 1 and
80 self.frame_rolls[self.current_frame][0] == 10)):
81 self.current_frame += 1
82 if self.current_frame < 10:
83 self.frame_rolls.append([])
84
885 def score(self):
9 pass
86 # Edge Case: Attempting to score before game is over
87 if not self.game_over:
88 raise ValueError("game not yet complete")
89
90 total_score = 0
91 roll_index = 0
92
93 for frame in range(10):
94 # Strike case
95 if self.rolls[roll_index] == 10:
96 # Edge Case: Incomplete game data for strike calculation
97 if roll_index + 2 >= len(self.rolls):
98 raise ValueError("game not yet complete")
99 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
100 roll_index += 1
101 else:
102 frame_score = self.rolls[roll_index] + self.rolls[roll_index + 1]
103 # Spare case
104 if frame_score == 10:
105 # Edge Case: Incomplete game data for spare calculation
106 if roll_index + 2 >= len(self.rolls):
107 raise ValueError("game not yet complete")
108 total_score += 10 + self.rolls[roll_index + 2]
109 # Open frame case
110 else:
111 total_score += frame_score
112 roll_index += 2
113
114 return total_score
115
116 # Handled Edge Cases: Game already over, invalid pin count, too many pins in frame, invalid fill balls, attempting to score before game over, incomplete game data for strike/spare calculation
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.