agent

Finished
1
2import sys, pytest, collections, collections.abc, urllib3.exceptions, _pytest.pytester, numpy;
3collections.Mapping = collections.abc.Mapping;
4collections.MutableMapping = collections.abc.MutableMapping;
5collections.MutableSet = collections.abc.MutableSet;
6collections.Sequence = collections.abc.Sequence;
7collections.Callable = collections.abc.Callable;
8collections.Iterable = collections.abc.Iterable;
9collections.Iterator = collections.abc.Iterator;
10urllib3.exceptions.SNIMissingWarning = urllib3.exceptions.DependencyWarning;
11pytest.RemovedInPytest4Warning = DeprecationWarning;
12_pytest.pytester.Testdir = _pytest.pytester.Pytester;
13numpy.PINF = numpy.inf;
14numpy.unicode_ = numpy.str_;
15numpy.bytes_ = numpy.bytes_;
16numpy.float_ = numpy.float64;
17numpy.string_ = numpy.bytes_;
18numpy.NaN = numpy.nan;
19
20
121class BowlingGame:
222 def __init__(self):
3 pass
4
23 """
24 Initialize a new bowling game.
25 """
26 self.rolls = []
27
528 def roll(self, pins):
6 pass
7
29 """
30 Record a roll in the game.
31
32 Args:
33 pins (int): Number of pins knocked down in this roll
34
35 Raises:
36 ValueError: If pins is negative or greater than 10, or if too many pins are knocked down in a frame
37 IndexError: If game is already over
38 """
39 # Validate pins
40 if pins < 0 or pins > 10:
41 raise ValueError("Pins must be between 0 and 10")
42
43 # Check if game is already over
44 if self._is_game_over():
45 raise IndexError("Game is already complete")
46
47 # Add the roll temporarily to validate frame rules
48 self.rolls.append(pins)
49
50 # Validate frame rules
51 if not self._is_valid_frame_configuration():
52 # Remove the invalid roll and raise error
53 self.rolls.pop()
54 raise ValueError("Cannot knock down more than 10 pins in a frame")
55
856 def score(self):
9 pass
57 """
58 Calculate the total score for the game.
59
60 Returns:
61 int: Total score for the game
62
63 Raises:
64 IndexError: If game is not yet complete
65 """
66 # Check if game is complete
67 if not self._is_game_over():
68 raise IndexError("Game is not complete yet")
69
70 total_score = 0
71 roll_index = 0
72
73 # Score first 9 frames
74 for frame in range(9):
75 if roll_index >= len(self.rolls):
76 raise IndexError("Game is not complete yet")
77
78 if self.rolls[roll_index] == 10: # Strike
79 # Strike: 10 + next two rolls
80 if roll_index + 2 >= len(self.rolls):
81 raise IndexError("Game is not complete yet")
82 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
83 roll_index += 1
84 else:
85 if roll_index + 1 >= len(self.rolls):
86 raise IndexError("Game is not complete yet")
87 frame_score = self.rolls[roll_index] + self.rolls[roll_index + 1]
88 if frame_score == 10: # Spare
89 # Spare: 10 + next roll
90 if roll_index + 2 >= len(self.rolls):
91 raise IndexError("Game is not complete yet")
92 total_score += 10 + self.rolls[roll_index + 2]
93 else: # Open frame
94 total_score += frame_score
95 roll_index += 2
96
97 # Score tenth frame
98 if roll_index >= len(self.rolls):
99 raise IndexError("Game is not complete yet")
100
101 # Tenth frame is scored as the sum of all remaining rolls
102 while roll_index < len(self.rolls):
103 total_score += self.rolls[roll_index]
104 roll_index += 1
105
106 return total_score
107
108 def _is_game_over(self):
109 """Check if the game is over."""
110 # Need at least 10 frames worth of rolls
111 if len(self.rolls) < 10:
112 return False
113
114 roll_index = 0
115
116 # Process first 9 frames
117 for frame in range(9):
118 if roll_index >= len(self.rolls):
119 return False
120
121 if self.rolls[roll_index] == 10: # Strike
122 roll_index += 1
123 else:
124 if roll_index + 1 >= len(self.rolls):
125 return False
126 roll_index += 2
127
128 # Process tenth frame
129 if roll_index >= len(self.rolls):
130 return False
131
132 # Tenth frame rules:
133 # - If first roll is strike, need two more rolls
134 # - If first two rolls are spare, need one more roll
135 # - Otherwise, frame is complete with two rolls
136
137 tenth_frame_rolls = len(self.rolls) - roll_index
138
139 if self.rolls[roll_index] == 10: # First roll is strike
140 return tenth_frame_rolls == 3
141 elif roll_index + 1 < len(self.rolls) and self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare
142 return tenth_frame_rolls == 3
143 else: # Open frame
144 return tenth_frame_rolls == 2
145
146 def _is_valid_frame_configuration(self):
147 """Check if the current frame configuration is valid."""
148 if len(self.rolls) < 2:
149 return True
150
151 roll_index = 0
152
153 # Process first 9 frames
154 for frame in range(9):
155 if roll_index >= len(self.rolls):
156 return True
157
158 if self.rolls[roll_index] == 10: # Strike
159 roll_index += 1
160 else:
161 if roll_index + 1 >= len(self.rolls):
162 return True
163 # Check if frame sum exceeds 10
164 if self.rolls[roll_index] + self.rolls[roll_index + 1] > 10:
165 return False
166 roll_index += 2
167
168 # Process tenth frame
169 if roll_index >= len(self.rolls):
170 return True
171
172 # For tenth frame, we need to be more careful
173 tenth_frame_rolls = self.rolls[roll_index:]
174
175 if len(tenth_frame_rolls) >= 2:
176 # First two rolls in tenth frame
177 first_two_sum = tenth_frame_rolls[0] + tenth_frame_rolls[1]
178 if tenth_frame_rolls[0] != 10 and first_two_sum > 10:
179 return False
180
181 # If we have a third roll, validate it based on the first two
182 if len(tenth_frame_rolls) >= 3:
183 if tenth_frame_rolls[0] == 10: # First roll was strike
184 if tenth_frame_rolls[1] != 10 and tenth_frame_rolls[1] + tenth_frame_rolls[2] > 10:
185 return False
186 elif first_two_sum == 10: # First two rolls were spare
187 # Third roll is always valid (0-10 pins)
188 pass
189 else: # Open frame
190 # Shouldn't have a third roll
191 return False
192
193 return True
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.