JiaYou

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 complete
21 """
22 # Edge Case: Invalid pin count (negative or more than 10)
23 if pins < 0 or pins > 10:
24 raise ValueError("Pins must be between 0 and 10")
25
26 # Edge Case: Game already completed
27 if len(self.frames) == 10 and not self._needs_fill_balls():
28 raise ValueError("Game is already finished")
29
30 # Edge Case: Trying to roll when current frame already has maximum pins
31 if self.frame_rolls and sum(self.frame_rolls) == 10 and len(self.frames) < 10:
32 raise ValueError("Cannot roll after bonus in regular frame")
33
34 # Edge Case: Too many pins in two rolls (regular frames)
35 if self.frame_rolls and len(self.frames) < 10:
36 if sum(self.frame_rolls) + pins > 10:
37 raise ValueError("Cannot knock down more than 10 pins in a frame")
38
39 # Edge Case: First roll in frame exceeds 10 pins
40 if not self.frame_rolls and pins == 10 and len(self.frames) < 10:
41 # Strike in regular frame
42 self.frames.append([10])
43 self.current_frame += 1
44 self.frame_rolls = []
45 elif len(self.frames) < 10: # Regular frames (1-9)
46 self.frame_rolls.append(pins)
47 if len(self.frame_rolls) == 2 or sum(self.frame_rolls) == 10:
48 self.frames.append(self.frame_rolls[:])
49 self.current_frame += 1
50 self.frame_rolls = []
51 else: # Tenth frame
52 if len(self.frames) == 10: # We already have the 10th frame, adding fill balls
53 self.frames[9].append(pins)
54 else: # First roll of 10th frame
55 self.frame_rolls.append(pins)
56
57 # Check if we should complete the 10th frame
58 if len(self.frame_rolls) == 2:
59 # If it's not a strike or spare, we're done
60 if self.frame_rolls[0] != 10 and sum(self.frame_rolls) < 10:
61 self.frames.append(self.frame_rolls[:])
62 self.frame_rolls = []
63 # If it's a strike or spare, we need more rolls, but still add the frame
64 else:
65 self.frames.append(self.frame_rolls[:])
66 self.frame_rolls = []
67 elif len(self.frame_rolls) == 1 and self.frame_rolls[0] != 10:
68 # First roll not a strike, need second roll
69 pass
70
71 def _needs_fill_balls(self):
72 """
73 Check if the game needs fill balls in the tenth frame.
74
75 Returns:
76 bool: True if fill balls are needed, False otherwise
77 """
78 if len(self.frames) < 10:
79 return False
80 tenth_frame = self.frames[9]
81
82 # Strike in 10th frame needs 2 more rolls (total 3 rolls)
83 if tenth_frame[0] == 10:
84 return len(tenth_frame) < 3
85 # Spare in 10th frame needs 1 more roll (total 3 rolls)
86 elif len(tenth_frame) >= 2 and sum(tenth_frame[:2]) == 10:
87 return len(tenth_frame) < 3
88 # Open frame in 10th frame is complete (2 rolls)
89 elif len(tenth_frame) == 2:
90 return False
91 # Incomplete cases
92 else:
93 return True
94
895 def score(self):
9 pass
96 """
97 Calculate the total score for the game.
98
99 Returns:
100 int: The total score of the game
101
102 Raises:
103 ValueError: If the game is not yet complete
104 """
105 # Edge Case: Game not complete
106 if len(self.frames) < 10:
107 raise ValueError("Score cannot be taken until the end of the game")
108
109 # Edge Case: Tenth frame incomplete
110 if len(self.frames) == 10 and self._needs_fill_balls():
111 raise ValueError("Score cannot be taken until the end of the game")
112
113 # Flatten all rolls into a single list for easier scoring
114 all_rolls = []
115 for frame in self.frames:
116 all_rolls.extend(frame)
117
118 total_score = 0
119 roll_index = 0
120
121 for frame_num in range(10):
122 if roll_index >= len(all_rolls):
123 raise ValueError("Score cannot be taken until the end of the game")
124
125 if all_rolls[roll_index] == 10: # Strike
126 if frame_num == 9: # 10th frame
127 total_score += sum(all_rolls[roll_index:roll_index + 3])
128 else:
129 if roll_index + 2 >= len(all_rolls):
130 raise ValueError("Score cannot be taken until the end of the game")
131 total_score += 10 + all_rolls[roll_index + 1] + all_rolls[roll_index + 2]
132 roll_index += 1
133 elif roll_index + 1 < len(all_rolls) and all_rolls[roll_index] + all_rolls[roll_index + 1] == 10: # Spare
134 if frame_num == 9: # 10th frame
135 total_score += 10 + all_rolls[roll_index + 2]
136 else:
137 if roll_index + 2 >= len(all_rolls):
138 raise ValueError("Score cannot be taken until the end of the game")
139 total_score += 10 + all_rolls[roll_index + 2]
140 roll_index += 2
141 else: # Open frame
142 if roll_index + 1 >= len(all_rolls):
143 raise ValueError("Score cannot be taken until the end of the game")
144 total_score += all_rolls[roll_index] + all_rolls[roll_index + 1]
145 roll_index += 2
146
147 return total_score
148
149 # Handled Edge Cases: Invalid pin count, game already completed, trying to roll after bonus,
150 # first roll exceeding 10 pins, tenth frame completion conditions, strike in tenth frame,
151 # second roll after strike in tenth frame, game not complete, tenth frame incomplete,
152 # incomplete frames, not enough rolls for strike calculation, not enough rolls for spare calculation
Test NameStatus
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_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_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.