unicode

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a new bowling game.
5 """
6 self.rolls = []
7 self.current_roll = 0
8
59 def roll(self, pins):
6 pass
7
10 """
11 Record a roll in the game.
12
13 Args:
14 pins (int): Number of pins knocked down in this roll.
15
16 Raises:
17 ValueError: If the number of pins is invalid.
18 """
19 # Edge Case: Invalid pin count (negative or more than 10)
20 if pins < 0 or pins > 10:
21 raise ValueError("Pins must be between 0 and 10")
22
23 # Edge Case: Game already completed
24 if self._is_game_completed():
25 raise ValueError("Game is already finished")
26
27 # Edge Case: Too many pins in a frame (for frames 1-9)
28 if len(self.rolls) >= 1 and not self._is_in_tenth_frame():
29 frame_start = (len(self.rolls) // 2) * 2
30 if frame_start < len(self.rolls):
31 frame_pins = self.rolls[frame_start]
32 if frame_pins < 10 and frame_pins + pins > 10:
33 raise ValueError("Cannot knock down more than 10 pins in a frame")
34
35 # Edge Case: Too many pins in 10th frame first two rolls
36 if self._is_in_tenth_frame() and len(self.rolls) >= 18:
37 tenth_frame_rolls = self.rolls[18:]
38 if len(tenth_frame_rolls) == 0:
39 # First roll of 10th frame - no validation needed
40 pass
41 elif len(tenth_frame_rolls) == 1:
42 # Second roll of 10th frame
43 if tenth_frame_rolls[0] < 10 and tenth_frame_rolls[0] + pins > 10:
44 raise ValueError("Cannot knock down more than 10 pins in a frame")
45 elif len(tenth_frame_rolls) == 2:
46 # Third roll of 10th frame - only allowed if first was strike or first two were spare
47 if tenth_frame_rolls[0] < 10 and tenth_frame_rolls[0] + tenth_frame_rolls[1] < 10:
48 raise ValueError("Game is already finished")
49
50 self.rolls.append(pins)
51 self.current_roll += 1
52
53 def _is_in_tenth_frame(self):
54 """
55 Check if we are currently in the tenth frame.
56
57 Returns:
58 bool: True if we are in the tenth frame, False otherwise.
59 """
60 return len(self.rolls) >= 18
61
862 def score(self):
9 pass
63 """
64 Calculate the total score for the game.
65
66 Returns:
67 int: The total score of the game.
68
69 Raises:
70 ValueError: If the game is not yet completed.
71 """
72 # Edge Case: Game not completed
73 if not self._is_game_completed():
74 raise ValueError("Game is not yet finished")
75
76 total_score = 0
77 roll_index = 0
78
79 for frame in range(10):
80 # Edge Case: Strike in regular frames (0-8)
81 if frame < 9 and self.rolls[roll_index] == 10: # Strike
82 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
83 roll_index += 1
84 # Edge Case: Strike in 10th frame
85 elif frame == 9 and self.rolls[roll_index] == 10: # Strike in 10th frame
86 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
87 roll_index += 3
88 # Edge Case: Spare in regular frames (0-8)
89 elif frame < 9 and self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare
90 total_score += 10 + self.rolls[roll_index + 2]
91 roll_index += 2
92 # Edge Case: Spare in 10th frame
93 elif frame == 9 and self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare in 10th frame
94 total_score += 10 + self.rolls[roll_index + 2]
95 roll_index += 3
96 # Edge Case: Open frame
97 else: # Open frame
98 total_score += self.rolls[roll_index] + self.rolls[roll_index + 1]
99 roll_index += 2
100
101 return total_score
102
103 def _is_game_completed(self):
104 """
105 Check if the game is completed.
106
107 Returns:
108 bool: True if the game is completed, False otherwise.
109 """
110 # Need at least 12 rolls for a complete game (all strikes)
111 if len(self.rolls) < 12:
112 return False
113
114 # Count frames completed
115 frame_count = 0
116 roll_index = 0
117
118 for frame in range(10):
119 if roll_index >= len(self.rolls):
120 return False
121
122 if frame < 9: # Frames 1-9
123 if self.rolls[roll_index] == 10: # Strike
124 roll_index += 1
125 frame_count += 1
126 else: # Not a strike
127 if roll_index + 1 >= len(self.rolls):
128 return False
129 roll_index += 2
130 frame_count += 1
131 else: # Frame 10
132 if roll_index >= len(self.rolls):
133 return False
134 if self.rolls[roll_index] == 10: # Strike in 10th
135 # Need 2 more rolls
136 if roll_index + 2 >= len(self.rolls):
137 return False
138 return True
139 elif roll_index + 1 < len(self.rolls) and self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare in 10th
140 # Need 1 more roll
141 if roll_index + 2 >= len(self.rolls):
142 return False
143 return True
144 else: # Open frame in 10th
145 if roll_index + 1 >= len(self.rolls):
146 return False
147 return True
148
149 return frame_count >= 10
150 # Handled Edge Cases: Invalid pin count, too many pins in a frame, game already completed, extra roll after strike in 10th frame without spare, too many rolls in 10th frame
151 # Handled Edge Cases: Game not completed, strike in regular frames, strike in 10th frame, spare in regular frames, spare in 10th frame, open frame
152 # Handled Edge Cases: Not enough rolls, open 10th frame, spare in 10th frame but no third roll recorded, strike in 10th frame but not enough rolls, strike in 10th frame but only one additional roll, strike in 10th frame and spare or open in 11th, strike in 10th frame and 11th, all necessary rolls completed
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.