weekends

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 self.total_rolls_made = 0
11
512 def roll(self, pins):
6 pass
7
13 """
14 Record a roll in the game.
15
16 Args:
17 pins (int): Number of pins knocked down in this roll
18
19 Raises:
20 ValueError: If pins is negative or greater than 10
21 IndexError: If game is already over
22 """
23 # Edge Case: Invalid number of pins
24 if pins < 0 or pins > 10:
25 raise ValueError("Pins must be between 0 and 10")
26
27 # Validate frame pin count (except for strikes)
28 if len(self.frame_rolls) == 1 and self.frame_rolls[0] != 10:
29 if self.frame_rolls[0] + pins > 10:
30 raise ValueError("Frame cannot exceed 10 pins")
31
32 # Edge Case: Game already completed
33 if len(self.frames) == 10:
34 # If 10th frame is complete, no more rolls allowed
35 tenth_frame = self.frames[9]
36 if len(tenth_frame) == 2 and sum(tenth_frame) < 10:
37 # Open frame in 10th frame - game complete
38 raise IndexError("Game has already ended")
39 elif len(tenth_frame) == 3:
40 # Spare or strike with fill balls - game complete
41 raise IndexError("Game has already ended")
42 elif len(tenth_frame) == 2 and sum(tenth_frame) == 10:
43 # Spare in 10th frame - need 1 fill ball
44 pass # Allow one more roll
45 elif len(tenth_frame) == 2 and tenth_frame[0] == 10:
46 # Strike in 10th frame - need 2 fill balls
47 pass # Allow two more rolls
48 elif len(tenth_frame) == 1 and tenth_frame[0] == 10:
49 # Just rolled the strike in 10th frame - need 2 fill balls
50 pass # Allow two more rolls
51 # If we get here, we're still in the process of completing the 10th frame
52
53 # Add roll to current frame
54 self.frame_rolls.append(pins)
55
56 # Handle frame completion
57 if self.current_frame < 10:
58 # Regular frames (1-9)
59 if len(self.frame_rolls) == 2 or self.frame_rolls[0] == 10:
60 self.frames.append(self.frame_rolls)
61 self.frame_rolls = []
62 self.current_frame += 1
63 else:
64 # 10th frame special handling
65 # Only complete the 10th frame when we have:
66 # - 2 rolls with sum < 10 (open frame)
67 # - 3 rolls (spare or strike with fill balls)
68 if len(self.frame_rolls) == 2 and sum(self.frame_rolls) < 10:
69 # Open frame in 10th frame
70 self.frames.append(self.frame_rolls)
71 self.frame_rolls = []
72 elif len(self.frame_rolls) == 3:
73 # Spare or strike with fill balls - validate and complete
74 # Validate fill balls
75 if self.frame_rolls[0] == 10:
76 # Strike in 10th frame
77 if self.frame_rolls[1] == 10 and self.frame_rolls[2] > 10:
78 raise ValueError("Fill balls cannot exceed 10 pins")
79 if self.frame_rolls[1] < 10 and self.frame_rolls[1] + self.frame_rolls[2] > 10:
80 raise ValueError("Fill balls cannot exceed 10 pins")
81 elif self.frame_rolls[0] + self.frame_rolls[1] == 10:
82 # Spare in 10th frame
83 if self.frame_rolls[2] > 10:
84 raise ValueError("Pins must be between 0 and 10")
85 self.frames.append(self.frame_rolls)
86 self.frame_rolls = []
87
888 def score(self):
9 pass
89 """
90 Calculate the total score for the game.
91
92 Returns:
93 int: Total score for the game
94
95 Raises:
96 IndexError: If game is not yet complete
97 """
98 # Edge Case: Game not yet complete
99 if len(self.frames) < 10:
100 raise IndexError("Game is not yet complete")
101
102
103
104 # Edge Case: 10th frame not complete
105 if len(self.frames) == 10:
106 tenth_frame = self.frames[9]
107 if len(tenth_frame) < 2:
108 raise IndexError("Game is not yet complete")
109 if len(tenth_frame) == 2 and sum(tenth_frame) == 10 and tenth_frame[0] != 10:
110 raise IndexError("Game is not yet complete")
111 if len(tenth_frame) == 2 and tenth_frame[0] == 10:
112 raise IndexError("Game is not yet complete")
113
114
115
116
117
118 total_score = 0
119
120 # Score frames 1-9
121 for i in range(9):
122 frame = self.frames[i]
123 frame_score = sum(frame)
124
125 # Handle strike
126 if len(frame) == 1 and frame[0] == 10:
127 # Add next two rolls
128 if i+1 < len(self.frames):
129 next_frame = self.frames[i+1]
130 if len(next_frame) >= 2:
131 frame_score += next_frame[0] + next_frame[1]
132 elif len(next_frame) == 1 and i+2 < len(self.frames):
133 # Next frame is also a strike
134 frame_score += next_frame[0] + self.frames[i+2][0]
135 # Handle spare
136 elif len(frame) == 2 and sum(frame) == 10:
137 # Add first roll of next frame
138 if i+1 < len(self.frames):
139 frame_score += self.frames[i+1][0]
140
141 total_score += frame_score
142
143 # Score 10th frame
144 tenth_frame = self.frames[9]
145 total_score += sum(tenth_frame)
146
147 return total_score
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.