Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 self.rolls = []
4 self.current_roll = 0
5
56 def roll(self, pins):
6 pass
7
7 # Edge Case: Number of pins must be between 0 and 10
8 if pins < 0 or pins > 10:
9 raise ValueError("Pins must be between 0 and 10")
10
11 # Edge Case: Cannot roll after game is over
12 if self.is_game_over():
13 raise ValueError("Cannot roll after game is over")
14
15 # Check if this roll would make the frame total exceed 10 (except for strikes)
16 if len(self.rolls) % 2 == 1 and self.rolls[-1] != 10: # Second roll of a frame, and first roll wasn't a strike
17 if self.rolls[-1] + pins > 10:
18 raise ValueError("Pin count exceeds pins on the lane")
19
20 self.rolls.append(pins)
21 self.current_roll += 1
22
823 def score(self):
9 pass
24 # Edge Case: Initial game with no rolls should return 0
25 if len(self.rolls) == 0:
26 return 0
27
28 # Edge Case: Cannot score incomplete game
29 if not self.is_game_over():
30 raise IndexError("Score cannot be taken until the end of the game")
31
32 score = 0
33 roll_index = 0
34
35 for frame in range(10):
36 # Edge Case: Incomplete game (should not happen due to check above, but added for safety)
37 if roll_index >= len(self.rolls):
38 raise IndexError("Incomplete game")
39
40 if self.is_strike(roll_index): # Strike
41 # Edge Case: Not enough rolls for strike bonus
42 if roll_index + 2 >= len(self.rolls):
43 raise IndexError("Incomplete game")
44
45 score += 10 + self.strike_bonus(roll_index)
46 roll_index += 1
47 elif self.is_spare(roll_index): # Spare
48 # Edge Case: Not enough rolls for spare bonus
49 if roll_index + 2 >= len(self.rolls):
50 raise IndexError("Incomplete game")
51
52 score += 10 + self.spare_bonus(roll_index)
53 roll_index += 2
54 else: # Open frame
55 # Edge Case: Not enough rolls for open frame
56 if roll_index + 1 >= len(self.rolls):
57 raise IndexError("Incomplete game")
58
59 score += self.sum_of_balls_in_frame(roll_index)
60 roll_index += 2
61
62 return score
63
64 def is_game_over(self):
65 # A game is over when we have completed 10 frames
66 # For frames 1-9: each frame takes 1 or 2 rolls
67 # For frame 10: can take 2 or 3 rolls depending on strike/spare
68
69 if len(self.rolls) < 10:
70 return False
71
72 frame_count = 0
73 roll_index = 0
74
75 # Count completed frames (1-9)
76 while frame_count < 9 and roll_index < len(self.rolls):
77 if self.is_strike(roll_index):
78 roll_index += 1
79 else:
80 roll_index += 2
81 frame_count += 1
82
83 # If we haven't completed 9 frames, game is not over
84 if frame_count < 9:
85 return False
86
87 # Handle 10th frame
88 if roll_index >= len(self.rolls):
89 return False
90
91 # Check if first roll of 10th frame is a strike
92 if self.rolls[roll_index] == 10: # First roll is strike
93 # Need two more rolls
94 if roll_index + 2 >= len(self.rolls):
95 return False
96 # Game is over after these three rolls
97 return roll_index + 3 == len(self.rolls)
98 else:
99 # Check if second roll exists
100 if roll_index + 1 >= len(self.rolls):
101 return False
102
103 # Check if first two rolls make a spare
104 if self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare
105 # Need one more roll
106 if roll_index + 2 >= len(self.rolls):
107 return False
108 # Game is over after these three rolls
109 return roll_index + 3 == len(self.rolls)
110 else: # Open frame
111 # Game is over after these two rolls
112 return roll_index + 2 == len(self.rolls)
113
114 def is_strike(self, roll_index):
115 return self.rolls[roll_index] == 10
116
117 def is_spare(self, roll_index):
118 return self.rolls[roll_index] + self.rolls[roll_index + 1] == 10
119
120 def sum_of_balls_in_frame(self, roll_index):
121 return self.rolls[roll_index] + self.rolls[roll_index + 1]
122
123 def spare_bonus(self, roll_index):
124 return self.rolls[roll_index + 2]
125
126 def strike_bonus(self, roll_index):
127 return self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
128
129 # Handled Edge Cases: Number of pins must be between 0 and 10, Cannot roll after game is over, Cannot score incomplete game, Incomplete game, Not enough rolls for strike bonus, Not enough rolls for spare bonus, Not enough rolls for open frame, Too many rolls
Test NameStatus
test_an_unstarted_game_cannot_be_scored
Fail
test_the_second_bonus_rolls_after_a_strike_in_the_last_frame_cannot_be_a_strike_if_the_first_one_is_not_a_strike
Fail
test_two_bonus_rolls_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points
Fail
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_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_two_bonus_rolls_after_a_strike_in_the_last_frame_can_score_more_than_10_points_if_one_is_a_strike
Pass
test_two_rolls_in_a_frame_cannot_score_more_than_10_points
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.