joseph

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 self.frames = []
4 self.current_frame = []
5 self.frame_count = 0
6 self.game_over = False
7 self.rolls = []
8
59 def roll(self, pins):
6 pass
7
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)
15 if pins < 0:
16 raise ValueError("Negative roll is invalid")
17
18 # Edge Case: Invalid pin count (more than 10)
19 if pins > 10:
20 raise ValueError("Pin count exceeds pins on the lane")
21
22 # Edge Case: First roll in a frame with more than 10 pins
23 if len(self.current_frame) == 1 and self.frame_count < 9:
24 if self.current_frame[0] + pins > 10:
25 raise ValueError("Pin count exceeds pins on the lane")
26
27 self.current_frame.append(pins)
28 self.rolls.append(pins)
29
30 # Handle regular frames (0-8)
31 if self.frame_count < 9:
32 # Strike case
33 if pins == 10 and len(self.current_frame) == 1:
34 self.frames.append(self.current_frame[:])
35 self.current_frame = []
36 self.frame_count += 1
37 # Regular case (2 rolls)
38 elif len(self.current_frame) == 2:
39 self.frames.append(self.current_frame[:])
40 self.current_frame = []
41 self.frame_count += 1
42 # Handle last frame (9)
43 else:
44 # Edge Case: Invalid fill balls in 10th frame
45 if len(self.current_frame) == 2:
46 # If first two rolls are not strike or spare, no third roll allowed
47 if self.current_frame[0] != 10 and sum(self.current_frame) < 10:
48 self.frames.append(self.current_frame[:])
49 self.current_frame = []
50 self.game_over = True
51 elif len(self.current_frame) == 3:
52 # Validate the third roll
53 # If first roll was strike
54 if self.current_frame[0] == 10:
55 # Second roll is strike
56 if self.current_frame[1] == 10:
57 # Valid - third roll can be anything 0-10
58 pass
59 # Second roll is not strike
60 else:
61 # Third roll combined with second must not exceed 10 (unless second is 10)
62 if self.current_frame[1] + self.current_frame[2] > 10 and self.current_frame[1] != 10:
63 raise ValueError("invalid fill balls")
64 # First roll not strike, but second makes spare
65 elif self.current_frame[0] != 10 and self.current_frame[0] + self.current_frame[1] == 10:
66 # Third roll is fine (0-10)
67 pass
68 # First two rolls don't make strike or spare
69 else:
70 raise ValueError("invalid fill balls")
71
72 self.frames.append(self.current_frame[:])
73 self.current_frame = []
74 self.game_over = True
75
876 def score(self):
9 pass
77 # Edge Case: Attempting to score before game is complete
78 if not self.game_over and (len(self.frames) < 10 or (len(self.frames) == 10 and self.current_frame)):
79 raise IndexError("Score cannot be taken until the end of the game")
80
81 total_score = 0
82 roll_index = 0
83
84 # Score first 9 frames
85 for frame_num in range(9):
86 if roll_index >= len(self.rolls):
87 break
88
89 # Strike
90 if self.rolls[roll_index] == 10:
91 total_score += 10
92 # Add next two rolls
93 if roll_index + 1 < len(self.rolls):
94 total_score += self.rolls[roll_index + 1]
95 if roll_index + 2 < len(self.rolls):
96 total_score += self.rolls[roll_index + 2]
97 roll_index += 1
98 else:
99 frame_score = self.rolls[roll_index] + self.rolls[roll_index + 1]
100 total_score += frame_score
101 # Spare
102 if frame_score == 10:
103 # Add next roll
104 if roll_index + 2 < len(self.rolls):
105 total_score += self.rolls[roll_index + 2]
106 roll_index += 2
107
108 # Score 10th frame
109 while roll_index < len(self.rolls):
110 total_score += self.rolls[roll_index]
111 roll_index += 1
112
113 return total_score
114 # Handled Edge Cases: Game already over, negative pins, too many pins, invalid pin count in frame, invalid fill balls, scoring before game completion
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.