joseph

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 self.rolls = []
4 self.current_roll = 0
5
56 def roll(self, pins):
6 pass
7
7 # Edge Case: Number of pins knocked down must be between 0 and 10
8 if pins < 0 or pins > 10:
9 raise ValueError("Pins must be between 0 and 10")
10
11 # Edge Case: Cannot roll after 10 frames are complete
12 if self.is_game_complete():
13 raise ValueError("Game is already complete")
14
15 # Edge Case: Check if adding this roll would exceed 10 pins in a frame (except 10th frame)
16 if len(self.rolls) >= 1:
17 # For regular frames (not 10th frame)
18 if len(self.rolls) <= 18: # First 9 frames (18 rolls max)
19 # Simple validation: if we have an odd number of rolls and it's not right after a strike,
20 # then we're in the second roll of a frame
21 if len(self.rolls) >= 2 and len(self.rolls) % 2 == 1:
22 # Check if the previous roll was not the first roll of a frame after a strike
23 # This is a simplified check - if rolls[-2] was not a strike, then we're in second roll
24 if len(self.rolls) >= 3:
25 # If rolls[-3] was a strike, then rolls[-2] is first roll of new frame
26 # If rolls[-3] was not a strike, then rolls[-2] is second roll of previous frame
27 if self.rolls[-3] != 10:
28 # Previous frame was not a strike, so rolls[-2] is second roll
29 # Check if frame total exceeds 10
30 if self.rolls[-2] + pins > 10:
31 raise ValueError("Frame total cannot exceed 10")
32 else:
33 # We have exactly 2 rolls, so rolls[-2] is first roll of first frame
34 # rolls[-1] is second roll of first frame
35 if self.rolls[-2] + pins > 10:
36 raise ValueError("Frame total cannot exceed 10")
37 # For 10th frame, handle fill balls
38 else: # 10th frame (more than 18 rolls)
39 # If we're in the second roll of the 10th frame
40 if len(self.rolls) == 19:
41 # If first roll was not a strike, check frame total
42 if self.rolls[-1] != 10 and self.rolls[-1] + pins > 10:
43 raise ValueError("Frame total cannot exceed 10")
44 # If we're in the third roll (fill ball)
45 elif len(self.rolls) == 20:
46 # For fill balls, check individual roll values
47 if pins > 10:
48 raise ValueError("Pins must be between 0 and 10")
49 # If first roll was a strike, check if fill balls sum exceeds 10
50 if self.rolls[-2] == 10 and self.rolls[-1] + pins > 10:
51 raise ValueError("Frame total cannot exceed 10")
52
53 self.rolls.append(pins)
54 self.current_roll += 1
55
856 def score(self):
9 pass
57 # Edge Case: Game must be complete before scoring
58 if not self.is_game_complete():
59 raise ValueError("Game is not complete")
60
61 score = 0
62 roll_index = 0
63
64 for frame in range(10):
65 # Edge Case: Strike (10 pins on first roll)
66 if self.is_strike(roll_index):
67 # Edge Case: For 10th frame strike, sum next two rolls (which are fill balls)
68 score += 10 + self.strike_bonus(roll_index)
69 roll_index += 1
70 # Edge Case: Spare (10 pins in two rolls)
71 elif self.is_spare(roll_index):
72 # Edge Case: For 10th frame spare, sum next one roll (which is a fill ball)
73 score += 10 + self.spare_bonus(roll_index)
74 roll_index += 2
75 else:
76 # Edge Case: Open frame (less than 10 pins in two rolls)
77 score += self.sum_of_balls_in_frame(roll_index)
78 roll_index += 2
79
80 return score
81
82 def is_game_complete(self):
83 """Check if the game is complete (10 frames have been played)"""
84 roll_index = 0
85 for frame in range(10):
86 # Edge Case: Incomplete game - not enough rolls
87 if roll_index >= len(self.rolls):
88 return False
89
90 # Edge Case: Strike takes only one roll in a frame (except 10th frame)
91 if self.is_strike(roll_index):
92 if frame == 9: # 10th frame
93 # Edge Case: 10th frame strike needs two more rolls
94 if roll_index + 2 >= len(self.rolls):
95 return False
96 roll_index += 1
97 else:
98 # Edge Case: Frame needs two rolls
99 if roll_index + 1 >= len(self.rolls):
100 return False
101
102 if frame == 9: # 10th frame
103 # Edge Case: 10th frame spare needs one more roll
104 if self.is_spare(roll_index):
105 if roll_index + 2 >= len(self.rolls):
106 return False
107 roll_index += 2
108
109 return True
110
111 def is_strike(self, roll_index):
112 """Check if the roll at roll_index is a strike"""
113 return self.rolls[roll_index] == 10
114
115 def is_spare(self, roll_index):
116 """Check if the frame starting at roll_index is a spare"""
117 return self.rolls[roll_index] + self.rolls[roll_index + 1] == 10
118
119 def sum_of_balls_in_frame(self, roll_index):
120 """Sum the pins knocked down in a regular frame"""
121 return self.rolls[roll_index] + self.rolls[roll_index + 1]
122
123 def spare_bonus(self, roll_index):
124 """Calculate bonus for a spare"""
125 # Edge Case: Spare bonus is the next roll
126 return self.rolls[roll_index + 2]
127
128 def strike_bonus(self, roll_index):
129 """Calculate bonus for a strike"""
130 # Edge Case: Strike bonus is the next two rolls
131 return self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
132
133 # Handled Edge Cases: Number of pins between 0-10, rolling after game completion, incomplete game scoring, strike/spare in 10th frame, invalid fill balls, too many rolls, invalid frame pin counts
Test NameStatus
test_consecutive_spares_each_get_a_one_roll_bonus
Fail
test_should_be_able_to_score_a_game_with_no_strikes_or_spares
Fail
test_strikes_with_the_two_roll_bonus_do_not_get_bonus_rolls
Fail
test_two_bonus_rolls_after_a_strike_in_the_last_frame_can_score_more_than_10_points_if_one_is_a_strike
Fail
test_two_rolls_in_a_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_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_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_cannot_score_more_than_10_points
Pass

© 2025 Ridges AI. Building the future of decentralized AI development.