Finished
11class BowlingGame:
22 def __init__(self):
3 pass
3 self.rolls = []
4 self.frame_scores = []
5 self.current_frame = 0
6 self.frame_rolls = []
7 self.game_over = False
48
59 def roll(self, pins):
6 pass
10 # Edge Case: Game is already over
11 if self.game_over:
12 raise ValueError("Cannot roll after game is over")
13
14 # Edge Case: Invalid pin count (negative or more than 10)
15 if pins < 0 or pins > 10:
16 raise ValueError("Pins must be between 0 and 10")
17
18 # Edge Case: Too many pins in a frame (except for special 10th frame cases)
19 if len(self.frame_rolls) > 0 and self.current_frame < 9:
20 if self.frame_rolls[0] + pins > 10:
21 raise ValueError("Invalid roll: pins downed exceed 10 in a frame")
22
23 self.frame_rolls.append(pins)
24 self.rolls.append(pins)
25
26 # Handle frame completion
27 if self.current_frame < 9: # Frames 1-9
28 # Strike case
29 if len(self.frame_rolls) == 1 and pins == 10:
30 self.frame_scores.append(self.frame_rolls)
31 self.frame_rolls = []
32 self.current_frame += 1
33 # Open frame or spare
34 elif len(self.frame_rolls) == 2:
35 self.frame_scores.append(self.frame_rolls)
36 self.frame_rolls = []
37 self.current_frame += 1
38 else: # 10th frame
39 # Handle the special rules for the 10th frame
40 if len(self.frame_rolls) == 3:
41 # All rolls are done
42 self.frame_scores.append(self.frame_rolls)
43 self.game_over = True
44 elif len(self.frame_rolls) == 2:
45 # Check if we need a third roll
46 if self.frame_rolls[0] == 10 or sum(self.frame_rolls) == 10:
47 # Strike or spare - need one more roll
48 pass
49 else:
50 # Open frame - done
51 self.frame_scores.append(self.frame_rolls)
52 self.game_over = True
53 elif len(self.frame_rolls) == 1 and self.frame_rolls[0] < 10:
54 # First roll wasn't a strike, so we need a second
55 pass
756
857 def score(self):
9 pass
58 # Edge Case: Empty game should return 0
59 if len(self.rolls) == 0:
60 return 0
61
62 # Edge Case: Game is not yet complete
63 if not self.game_over and (self.current_frame < 9 or len(self.frame_scores) < 10):
64 raise ValueError("Score cannot be taken until the end of the game")
65
66 total_score = 0
67 roll_index = 0
68
69 # Score first 9 frames
70 for frame in range(9):
71 # Edge Case: Not enough frames completed
72 if frame >= len(self.frame_scores):
73 raise ValueError("Score cannot be taken until the end of the game")
74
75 frame_rolls = self.frame_scores[frame]
76
77 if len(frame_rolls) >= 1 and frame_rolls[0] == 10: # Strike
78 # Edge Case: Not enough rolls for strike bonus
79 if len(self.rolls) <= roll_index + 2:
80 raise ValueError("Score cannot be taken until the end of the game")
81 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
82 roll_index += 1
83 elif sum(frame_rolls[:2]) == 10: # Spare
84 # Edge Case: Not enough rolls for spare bonus
85 if len(self.rolls) <= roll_index + 2:
86 raise ValueError("Score cannot be taken until the end of the game")
87 total_score += 10 + self.rolls[roll_index + 2]
88 roll_index += 2
89 else: # Open frame
90 total_score += sum(frame_rolls[:2])
91 roll_index += 2
92
93 # Score 10th frame
94 # Edge Case: 10th frame not completed
95 if len(self.frame_scores) < 10:
96 raise ValueError("Score cannot be taken until the end of the game")
97
98 tenth_frame = self.frame_scores[9]
99 total_score += sum(tenth_frame)
100
101 return total_score
102
103# Handled Edge Cases: Game already over, invalid pin count, too many pins in a frame, game not complete for scoring, insufficient rolls for strike/spare bonus, 10th frame completion rules
Test NameStatus
test_an_unstarted_game_cannot_be_scored
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_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_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.