tobe

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 # Edge Case: In any frame except the 10th, a player cannot knock down more than 10 pins
16 if len(self.rolls) < 18 or (len(self.rolls) == 18 and len(self.rolls) % 2 == 0):
17 # Not in 10th frame or starting a new throw in 10th frame
18 if len(self.rolls) % 2 == 1 and self.rolls[-1] + pins > 10:
19 raise ValueError("Cannot knock down more than 10 pins in a frame")
20
21 # Edge Case: In the 10th frame, special rules apply for fill balls
22 if len(self.rolls) >= 18:
23 # We're in the 10th frame
24 # If it's the third roll, check if previous two were strikes or if second was a spare
25 if len(self.rolls) == 19:
26 # Second roll in 10th frame was just made
27 # If first two rolls were strikes, third is allowed
28 # If first was strike and second completed a spare, third is allowed
29 # If first was strike and second was not a strike, sum must not exceed 10
30 if self.rolls[18] == 10: # First roll was a strike
31 if self.rolls[19] != 10 and self.rolls[18] + self.rolls[19] > 10:
32 raise ValueError("Cannot knock down more than 10 pins in a frame")
33 else: # First roll was not a strike
34 if self.rolls[18] + self.rolls[19] > 10:
35 raise ValueError("Cannot knock down more than 10 pins in a frame")
36 elif len(self.rolls) == 20:
37 # Third roll in 10th frame
38 # If first two were strikes, third can be 0-10
39 # If first was strike and second completed spare, third can be 0-10
40 # If first was strike and second was not strike, third must not make frame exceed limits
41 # If first was not strike and second completed spare, third can be 0-10
42 if self.rolls[18] != 10 and self.rolls[18] + self.rolls[19] != 10:
43 # This shouldn't happen as game should be over
44 raise ValueError("Cannot roll after game is over")
45
46 # If we have a strike in 19th position (second roll), check constraints
47 if self.rolls[18] == 10 and self.rolls[19] != 10:
48 if self.rolls[19] + pins > 10:
49 raise ValueError("Cannot knock down more than 10 pins in a frame")
50
51 self.rolls.append(pins)
52
853 def score(self):
9 pass
54 # Edge Case: Cannot score incomplete game
55 if not self.is_game_over():
56 raise ValueError("Score cannot be taken until the end of the game")
57
58 score = 0
59 roll_index = 0
60
61 for frame in range(10):
62 # Edge Case: Strike in regular frames
63 if self.is_strike(roll_index) and frame < 9:
64 score += 10 + self.strike_bonus(roll_index)
65 roll_index += 1
66 # Edge Case: Spare in regular frames
67 elif self.is_spare(roll_index) and frame < 9:
68 score += 10 + self.spare_bonus(roll_index)
69 roll_index += 2
70 # Edge Case: Open frame in regular frames
71 elif frame < 9:
72 score += self.sum_of_balls_in_frame(roll_index)
73 roll_index += 2
74 # Edge Case: 10th frame scoring
75 else: # 10th frame
76 score += self.sum_of_balls_in_frame(roll_index)
77 # If there are more rolls (fill balls), add them
78 if len(self.rolls) > roll_index + 2:
79 score += self.rolls[roll_index + 2]
80 if len(self.rolls) > roll_index + 3:
81 score += self.rolls[roll_index + 3]
82 roll_index += 2
83
84 return score
85
86 def is_game_over(self):
87 if len(self.rolls) < 18:
88 return False
89
90 if len(self.rolls) == 18:
91 # 9 frames completed, 10th frame has 2 rolls
92 # Game is over if 10th frame is open
93 return self.rolls[18] + self.rolls[19] < 10
94
95 if len(self.rolls) == 19:
96 # 10th frame had a strike or spare, one fill ball thrown
97 # Game is over if 10th frame was a spare or if it was a strike but not followed by another strike
98 # that would require a second fill ball
99 tenth_frame_first = self.rolls[18]
100 tenth_frame_second = self.rolls[19]
101
102 # If 10th frame was spare, game is over
103 if tenth_frame_first + tenth_frame_second == 10:
104 return True
105
106 # If 10th frame was strike, need to check if second fill ball is needed
107 # Second fill ball is needed only if first fill ball was a strike
108 return tenth_frame_second != 10
109
110 if len(self.rolls) >= 20:
111 return True
112
113 return False
114
115 def is_strike(self, roll_index):
116 return self.rolls[roll_index] == 10
117
118 def is_spare(self, roll_index):
119 return self.rolls[roll_index] + self.rolls[roll_index + 1] == 10
120
121 def sum_of_balls_in_frame(self, roll_index):
122 return self.rolls[roll_index] + self.rolls[roll_index + 1]
123
124 def spare_bonus(self, roll_index):
125 return self.rolls[roll_index + 2]
126
127 def strike_bonus(self, roll_index):
128 return self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
129
130 # Handled Edge Cases: Number of pins must be between 0 and 10, Cannot roll after game is over, In any frame except the 10th a player cannot knock down more than 10 pins, In the 10th frame special rules apply for fill balls, Cannot score incomplete game, Strike in regular frames, Spare in regular frames, Open frame in regular frames, 10th frame scoring
Test NameStatus
test_a_spare_followed_by_zeros_is_worth_ten_points
Fail
test_a_spare_in_the_last_frame_gets_a_one_roll_bonus_that_is_counted_once
Fail
test_a_strike_earns_ten_points_in_a_frame_with_a_single_roll
Fail
test_a_strike_in_the_last_frame_gets_a_two_roll_bonus_that_is_counted_once
Fail
test_a_strike_with_the_one_roll_bonus_after_a_spare_in_the_last_frame_does_not_get_a_bonus
Fail
test_all_strikes_is_a_perfect_game
Fail
test_bonus_roll_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points
Fail
test_bonus_roll_for_a_spare_in_the_last_frame_must_be_rolled_before_score_can_be_calculated
Fail
test_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated
Fail
test_both_bonus_rolls_for_a_strike_in_the_last_frame_must_be_rolled_before_score_can_be_calculated
Fail
test_cannot_roll_after_bonus_roll_for_spare
Fail
test_cannot_roll_after_bonus_rolls_for_strike
Fail
test_cannot_roll_if_game_already_has_ten_frames
Fail
test_consecutive_spares_each_get_a_one_roll_bonus
Fail
test_consecutive_strikes_each_get_the_two_roll_bonus
Fail
test_last_two_strikes_followed_by_only_last_bonus_with_non_strike_points
Fail
test_points_scored_in_the_roll_after_a_spare_are_counted_twice
Fail
test_points_scored_in_the_two_rolls_after_a_strike_are_counted_twice_as_a_bonus
Fail
test_rolling_a_spare_with_the_two_roll_bonus_does_not_get_a_bonus_roll
Fail
test_second_bonus_roll_after_a_strike_in_the_last_frame_cannot_score_more_than_10_points
Fail
test_should_be_able_to_score_a_game_with_all_zeros
Fail
test_should_be_able_to_score_a_game_with_no_strikes_or_spares
Fail
test_strikes_with_the_two_roll_bonus_do_not_get_bonus_rolls
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_can_score_more_than_10_points_if_one_is_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_an_incomplete_game_cannot_be_scored
Pass
test_an_unstarted_game_cannot_be_scored
Pass
test_rolls_cannot_score_negative_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.