fortitude

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a bowling game.
5
6 Sets up the game state including tracking rolls, current frame,
7 and whether the game is complete.
8 """
9 self.rolls = []
10 self.current_frame = 1
11 self.frame_rolls = []
12 self.frames = []
13 self.game_complete = False
14
515 def roll(self, pins):
6 pass
7
16 """
17 Record a roll in the bowling game.
18
19 Args:
20 pins (int): Number of pins knocked down in this roll
21
22 Raises:
23 ValueError: If pins is negative or greater than 10
24 ValueError: If game is already complete
25 ValueError: If frame rules are violated
26 """
27 # Edge Case: Game already complete
28 if self.game_complete:
29 raise ValueError("game already complete")
30
31 # Edge Case: Invalid pin count
32 if pins < 0 or pins > 10:
33 raise ValueError("invalid pin count")
34
35 # Edge Case: First roll of a frame with invalid pins after previous roll
36 if len(self.frame_rolls) == 1 and (self.frame_rolls[0] + pins) > 10 and self.current_frame < 10:
37 raise ValueError("invalid pin count")
38
39 self.frame_rolls.append(pins)
40 self.rolls.append(pins)
41
42 # Handle frame completion logic
43 if self.current_frame < 10:
44 # Regular frames (1-9)
45 if pins == 10: # Strike
46 self.frames.append(self.frame_rolls[:])
47 self.frame_rolls = []
48 self.current_frame += 1
49 elif len(self.frame_rolls) == 2: # Two rolls completed
50 # Edge Case: Invalid pin count in regular frame
51 if sum(self.frame_rolls) > 10:
52 raise ValueError("invalid pin count")
53 self.frames.append(self.frame_rolls[:])
54 self.frame_rolls = []
55 self.current_frame += 1
56 else:
57 # 10th frame handling
58 # Edge Case: Too many rolls in 10th frame
59 if len(self.frame_rolls) > 3:
60 raise ValueError("invalid fill balls")
61
62 # Determine if 10th frame is complete
63 if len(self.frame_rolls) == 2:
64 # If not a spare or strike, frame is complete
65 if sum(self.frame_rolls) < 10:
66 self.frames.append(self.frame_rolls[:])
67 self.frame_rolls = []
68 self.game_complete = True
69 elif len(self.frame_rolls) == 3:
70 # Edge Case: Invalid 10th frame with 3 rolls
71 # If first two rolls are not 10 or don't sum to 10, third roll shouldn't exist
72 if self.frame_rolls[0] != 10 and sum(self.frame_rolls[0:2]) != 10:
73 raise ValueError("invalid fill balls")
74 # Edge Case: Invalid pin count in 10th frame
75 if self.frame_rolls[0] == 10 and self.frame_rolls[1] != 10 and (self.frame_rolls[1] + self.frame_rolls[2]) > 10:
76 raise ValueError("invalid fill balls")
77 self.frames.append(self.frame_rolls[:])
78 self.frame_rolls = []
79 self.game_complete = True
80
881 def score(self):
9 pass
82 """
83 Calculate the total score for the bowling game.
84
85 Returns:
86 int: Total score of the game
87
88 Raises:
89 ValueError: If the game is not yet complete
90 """
91 # Edge Case: Game not complete
92 if not self.game_complete and (len(self.frames) < 10 or (len(self.frames) == 10 and self.frame_rolls)):
93 raise ValueError("game not complete")
94
95 total_score = 0
96 roll_index = 0
97
98 # Score first 9 frames
99 for frame_num in range(9):
100 # Edge Case: Not enough frames
101 if frame_num >= len(self.frames):
102 raise ValueError("game not complete")
103
104 frame = self.frames[frame_num]
105
106 if len(frame) == 1 and frame[0] == 10: # Strike
107 # Edge Case: Not enough rolls for strike bonus
108 if len(self.rolls) <= roll_index + 2:
109 raise ValueError("game not complete")
110 total_score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
111 roll_index += 1
112 elif len(frame) == 2 and sum(frame) == 10: # Spare
113 # Edge Case: Not enough rolls for spare bonus
114 if len(self.rolls) <= roll_index + 2:
115 raise ValueError("game not complete")
116 total_score += 10 + self.rolls[roll_index + 2]
117 roll_index += 2
118 else: # Open frame
119 total_score += sum(frame)
120 roll_index += 2
121
122 # Score 10th frame
123 # Edge Case: Missing 10th frame
124 if len(self.frames) < 10:
125 raise ValueError("game not complete")
126
127 tenth_frame = self.frames[9]
128 total_score += sum(tenth_frame)
129
130 return total_score
131
132 # Handled Edge Cases: Game already complete, invalid pin count, first roll of frame with invalid pins after previous roll, invalid pin count in regular frame, too many rolls in 10th frame, invalid 10th frame with 3 rolls, invalid pin count in 10th frame, game not complete, not enough frames, not enough rolls for strike bonus, not enough rolls for spare bonus, missing 10th frame
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.