A.2.1

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a new bowling game.
5
6 The game keeps track of rolls, current frame, and whether the game is complete.
7 """
8 self.rolls = []
9 self.frame_rolls = []
10 self.frames = []
11 self.current_frame = 0
12 self.game_complete = False
13
514 def roll(self, pins):
6 pass
7
15 """
16 Record a roll in the game.
17
18 Args:
19 pins (int): Number of pins knocked down in this roll
20
21 Raises:
22 ValueError: If pins is negative or greater than 10
23 IndexError: If game is already complete
24 """
25 # Edge Case: Game already complete
26 if self.game_complete:
27 raise IndexError("Game is already complete")
28
29 # Edge Case: Invalid pin count
30 if pins < 0:
31 raise ValueError("Pins must be between 0 and 10")
32
33 # Edge Case: Invalid pin count
34 if pins > 10:
35 raise ValueError("Cannot knock down more than 10 pins in a frame")
36
37 # Edge Case: Too many pins in frame (not tenth frame)
38 if self.current_frame < 9: # Frames 0-8
39 if len(self.frame_rolls) == 1 and self.frame_rolls[0] != 10:
40 if self.frame_rolls[0] + pins > 10:
41 raise ValueError("Cannot knock down more than 10 pins in a frame")
42
43 # Edge Case: Too many pins in tenth frame
44 if self.current_frame == 9: # Tenth frame
45 if len(self.frame_rolls) == 1 and self.frame_rolls[0] != 10:
46 if self.frame_rolls[0] + pins > 10:
47 raise ValueError("Cannot knock down more than 10 pins in a frame")
48 elif len(self.frame_rolls) == 2:
49 # If first two rolls are strikes or spare, third roll is allowed
50 # But if second roll wasn't a strike, check if it's valid
51 if self.frame_rolls[0] != 10 and self.frame_rolls[0] + self.frame_rolls[1] < 10:
52 raise IndexError("Cannot throw bonus with an open tenth frame")
53 if self.frame_rolls[0] == 10 and self.frame_rolls[1] != 10:
54 if self.frame_rolls[1] + pins > 10:
55 raise ValueError("Cannot knock down more than 10 pins in a frame")
56
57 self.frame_rolls.append(pins)
58 self.rolls.append(pins)
59
60 # Check if frame is complete
61 if self.current_frame < 9: # Frames 0-8
62 # Frame is complete if strike or two rolls
63 if len(self.frame_rolls) == 2 or self.frame_rolls[0] == 10:
64 self.frames.append(self.frame_rolls[:])
65 self.frame_rolls = []
66 self.current_frame += 1
67 else: # Tenth frame
68 # Tenth frame is complete if:
69 # - 2 rolls and not spare/strike
70 # - 3 rolls (regardless of values)
71 if len(self.frame_rolls) == 3:
72 self.frames.append(self.frame_rolls[:])
73 self.frame_rolls = []
74 self.game_complete = True
75 elif len(self.frame_rolls) == 2:
76 # If not a spare or strike, game is complete
77 if self.frame_rolls[0] != 10 and sum(self.frame_rolls) < 10:
78 self.frames.append(self.frame_rolls[:])
79 self.frame_rolls = []
80 self.game_complete = True
81
882 def score(self):
9 pass
83 """
84 Calculate the total score for the game.
85
86 Returns:
87 int: Total score for the game
88
89 Raises:
90 IndexError: If game is not complete
91 """
92 # Edge Case: Game not complete
93 if not self.game_complete:
94 raise IndexError("Game is not yet complete")
95
96 total_score = 0
97 roll_index = 0
98
99 # Score first 9 frames
100 for frame_index in range(9):
101 if roll_index >= len(self.rolls):
102 break
103
104 # Strike
105 if self.rolls[roll_index] == 10:
106 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
107 roll_index += 1
108 # Spare
109 elif self.rolls[roll_index] + self.rolls[roll_index + 1] == 10:
110 total_score += 10 + self.rolls[roll_index + 2]
111 roll_index += 2
112 # Open frame
113 else:
114 total_score += self.rolls[roll_index] + self.rolls[roll_index + 1]
115 roll_index += 2
116
117 # Score tenth frame
118 if len(self.rolls) - roll_index >= 2:
119 total_score += self.rolls[roll_index] + self.rolls[roll_index + 1]
120 if len(self.rolls) - roll_index > 2:
121 total_score += self.rolls[roll_index + 2]
122
123 return total_score
124
125 # Handled Edge Cases: Game already complete, invalid pin count, too many pins in frame, too many pins in tenth frame, game not complete
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.