viola

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a new bowling game.
5 """
6 self.rolls = []
7
58 def roll(self, pins):
6 pass
9 """
10 Record a roll in the game.
11
12 Args:
13 pins (int): Number of pins knocked down in this roll
14
15 Raises:
16 ValueError: If the number of pins is invalid or game is already finished
17 """
18 # Check if game is already finished
19 if self._is_game_finished():
20 raise ValueError("Cannot roll after game is over")
21
22 # Validate pins
23 if pins < 0 or pins > 10:
24 raise ValueError("Pins must be between 0 and 10")
25
26 # Validate frame rules for frames 1-9
27 if len(self.rolls) < 18: # Frames 1-9 (max 18 rolls)
28 # For frames 1-9, check if this roll exceeds 10 pins in the frame
29 if len(self.rolls) % 2 == 1: # Second roll of a frame (frames 1-9)
30 if self.rolls[-1] + pins > 10:
31 raise ValueError("Invalid roll: pins downed in a frame cannot exceed 10")
32
33 # Validate frame rules for frame 10
34 elif len(self.rolls) >= 18: # Frame 10 rolls
35 if len(self.rolls) == 18: # First roll of 10th frame
36 # No validation needed
37 pass
38 elif len(self.rolls) == 19: # Second roll of 10th frame
39 first_roll = self.rolls[18]
40 if first_roll != 10 and first_roll + pins > 10:
41 raise ValueError("Invalid roll: pins downed in a frame cannot exceed 10")
42 elif len(self.rolls) == 20: # Third roll of 10th frame (fill ball)
43 # Only allowed if first was strike or first two were spare
44 first_roll = self.rolls[18]
45 second_roll = self.rolls[19]
46 # Check if we actually should have a third roll
47 if first_roll != 10 and first_roll + second_roll != 10:
48 raise ValueError("Invalid fill balls")
49
50 self.rolls.append(pins)
51
752
53
54 def _is_game_finished(self):
55 """
56 Check if the game is finished.
57
58 Returns:
59 bool: True if the game is finished, False otherwise
60 """
61 # Game can't be finished with fewer than 18 rolls (9 frames * 2 rolls)
62 if len(self.rolls) < 18:
63 return False
64
65 # Check 10th frame status
66 if len(self.rolls) == 18: # Only first roll of 10th frame
67 # Game is not finished with only one roll in 10th frame
68 return False
69 elif len(self.rolls) == 19: # Only first two rolls of 10th frame exist
70 # This case should not be reached because we check len(self.rolls) == 19
71 # But if it is, we have 19 rolls (indices 0-18)
72 # Roll 18 is the first roll of frame 10
73 # There is no roll 19 because we only have 19 rolls total
74 # This means we only have one roll in frame 10, so game is not finished
75 return False
76 elif len(self.rolls) == 20: # Two rolls in 10th frame
77 # Game is finished only if it's an open frame (not a spare or strike)
78 first_roll = self.rolls[18]
79 second_roll = self.rolls[19]
80 return first_roll + second_roll < 10
81 elif len(self.rolls) == 21: # Three rolls in 10th frame
82 # Game is always finished with three rolls (strike or spare with fill balls)
83 return True
84 elif len(self.rolls) > 20: # More than 20 rolls (shouldn't happen in valid games)
85 return True
86
87 return False
88
889 def score(self):
9 pass
90 """
91 Calculate the total score for the game.
92
93 Returns:
94 int: The total score of the game
95
96 Raises:
97 ValueError: If the game is not yet complete
98 """
99 # Check if game is finished
100 if not self._is_game_finished():
101 raise ValueError("Score cannot be taken until the end of the game")
102
103 total_score = 0
104 roll_index = 0
105
106 # Score first 9 frames
107 for frame in range(9):
108 if roll_index >= len(self.rolls):
109 break
110
111 if self.rolls[roll_index] == 10: # Strike
112 # Add bonus for next two rolls
113 if roll_index + 2 < len(self.rolls):
114 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
115 else:
116 # This shouldn't happen if game is finished
117 raise ValueError("Invalid game state: not enough rolls for strike bonus")
118 roll_index += 1
119 else:
120 frame_score = self.rolls[roll_index] + self.rolls[roll_index + 1]
121 if frame_score == 10: # Spare
122 # Add bonus for next roll
123 if roll_index + 2 < len(self.rolls):
124 total_score += 10 + self.rolls[roll_index + 2]
125 else:
126 # This shouldn't happen if game is finished
127 raise ValueError("Invalid game state: not enough rolls for spare bonus")
128 else: # Open frame
129 total_score += frame_score
130 roll_index += 2
131
132 # Score tenth frame - just sum all remaining rolls (rolls 18, 19, and possibly 20)
133 while roll_index < len(self.rolls):
134 total_score += self.rolls[roll_index]
135 roll_index += 1
136
137 return total_score
Test NameStatus
test_a_strike_earns_ten_points_in_a_frame_with_a_single_roll
Fail
test_all_strikes_is_a_perfect_game
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_two_rolls_after_a_strike_are_counted_twice_as_a_bonus
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_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_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_points_scored_in_the_roll_after_a_spare_are_counted_twice
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.