sourdough

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
511 def roll(self, pins):
6 pass
7
12 """
13 Record a roll in the game.
14
15 Args:
16 pins (int): Number of pins knocked down in this roll
17
18 Raises:
19 ValueError: If pins is negative or greater than 10
20 IndexError: If game is already over
21 """
22 # Edge Case: Invalid number of pins
23 if pins < 0:
24 raise ValueError("pins cannot be negative")
25
26 # Edge Case: Too many pins
27 if pins > 10:
28 raise ValueError("pin count exceeds pins on the lane")
29
30 # Edge Case: Game already completed
31 if len(self.frames) == 10:
32 # Check if we're in the 10th frame and can still roll
33 tenth_frame = self.frames[9]
34 # If it's not a strike or spare, game is over
35 if not (tenth_frame[0] == 10 or sum(tenth_frame) == 10):
36 raise IndexError("cannot roll after game is over")
37 # If it's a strike, we can have up to 2 more rolls
38 elif tenth_frame[0] == 10:
39 if len(tenth_frame) == 3:
40 raise IndexError("cannot roll after game is over")
41 # If it's a spare, we can have 1 more roll
42 elif sum(tenth_frame) == 10 and len(tenth_frame) == 2:
43 if len(tenth_frame) == 3: # Already added the bonus roll
44 raise IndexError("cannot roll after game is over")
45
46 # Edge Case: Validate second roll before adding
47 if len(self.frame_rolls) == 1 and self.frame_rolls[0] != 10:
48 if self.frame_rolls[0] + pins > 10:
49 raise ValueError("pin count exceeds pins on the lane")
50
51 # Add the roll to current frame
52 self.frame_rolls.append(pins)
53
54 # Handle frame completion
55 if self.current_frame < 10:
56 # Regular frames
57 if self.frame_rolls[0] == 10 or len(self.frame_rolls) == 2:
58 self.frames.append(self.frame_rolls)
59 self.frame_rolls = []
60 self.current_frame += 1
61 else:
62 # 10th frame handling
63 tenth_frame_complete = False
64
65 # Strike in 10th frame - need 3 rolls total
66 if len(self.frame_rolls) == 3 and self.frame_rolls[0] == 10:
67 tenth_frame_complete = True
68 # Spare in 10th frame - need 3 rolls total
69 elif len(self.frame_rolls) == 3 and sum(self.frame_rolls[:2]) == 10:
70 tenth_frame_complete = True
71 # Open frame in 10th frame - need 2 rolls total
72 elif len(self.frame_rolls) == 2 and sum(self.frame_rolls) < 10:
73 tenth_frame_complete = True
74
75 if tenth_frame_complete:
76 self.frames.append(self.frame_rolls)
77 self.frame_rolls = []
78
79
80
81 self.rolls.append(pins)
82
883 def score(self):
9 pass
84 """
85 Calculate the total score for the game.
86
87 Returns:
88 int: Total score of the game
89
90 Raises:
91 IndexError: If the game is not yet complete
92 """
93 # Edge Case: Game not complete
94 if len(self.frames) < 10:
95 raise IndexError("score cannot be taken until the end of the game")
96
97 # Edge Case: 10th frame incomplete
98 if len(self.frames) == 10:
99 tenth_frame = self.frames[9]
100 # If it's not a strike or spare, it should have 2 rolls
101 if not (tenth_frame[0] == 10 or sum(tenth_frame[:2]) == 10):
102 if len(tenth_frame) < 2:
103 raise IndexError("score cannot be taken until the end of the game")
104 # If it's a strike or spare, it should have 3 rolls
105 elif len(tenth_frame) < 3:
106 raise IndexError("score cannot be taken until the end of the game")
107
108 total_score = 0
109 roll_index = 0
110
111 for frame_num in range(10):
112 if frame_num < 9: # Frames 1-9
113 if self.rolls[roll_index] == 10: # Strike
114 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
115 roll_index += 1
116 elif self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare
117 total_score += 10 + self.rolls[roll_index + 2]
118 roll_index += 2
119 else: # Open frame
120 total_score += self.rolls[roll_index] + self.rolls[roll_index + 1]
121 roll_index += 2
122 else: # 10th frame
123 total_score += sum(self.rolls[roll_index:])
124
125 return total_score
126
127 # Handled Edge Cases: Invalid number of pins, too many pins, game already completed, too many pins in frame, second roll exceeds remaining pins, third roll in 10th frame exceeds remaining pins, game not complete, 10th frame incomplete
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.