yahoo

Finished
11class BowlingGame:
22 def __init__(self):
3 pass
4
3 """
4 Initialize a new bowling game.
5 """
6 self.rolls = []
7
58 def roll(self, pins):
6 pass
7
9 """
10 Record a roll in the game.
11
12 Args:
13 pins (int): Number of pins knocked down in this roll.
14
15 Raises:
16 ValueError: If the number of pins is invalid.
17 IndexError: If the game is already complete.
18 """
19 # Edge Case: Invalid pin count (negative or more than 10)
20 if pins < 0:
21 raise ValueError("Pins must be between 0 and 10")
22 if pins > 10:
23 raise ValueError("Pins must be between 0 and 10")
24
25 # Check if game is already complete
26 if self.is_game_complete():
27 raise IndexError("Game has already ended")
28
29 # Edge Case: Adding pins that would exceed 10 in a frame (except for strikes and tenth frame)
30 if not self._is_valid_roll(pins):
31 raise ValueError("Cannot knock down more than 10 pins in a frame")
32
33 self.rolls.append(pins)
34
35 def _is_valid_roll(self, pins):
36 """Check if the current roll is valid."""
37 if len(self.rolls) == 0:
38 return True
39
40 # Find current frame and check validity
41 frame_index = 0
42 frame_count = 0
43
44 # Count frames to determine current position
45 while frame_count < 10 and frame_index < len(self.rolls):
46 if frame_count < 9: # Frames 1-9
47 if self.rolls[frame_index] == 10: # Strike
48 frame_index += 1
49 else:
50 if frame_index + 1 < len(self.rolls):
51 frame_index += 2
52 else:
53 # We're in the middle of a frame
54 if frame_index < len(self.rolls):
55 return self.rolls[frame_index] + pins <= 10
56 return True
57 frame_count += 1
58 else: # Frame 10 - always valid
59 return True
60
61 # If we've processed all frames, we're in frame 10
62 return True
63
64 def is_game_complete(self):
65 """Check if the game is complete."""
66 # A game needs at least 12 rolls to be complete (9 open frames + 10th frame with bonus)
67 # But can have up to 21 rolls (12 strikes)
68 if len(self.rolls) < 12:
69 return False
70
71 # Count frames to see if we have 10 complete frames
72 frame_count = 0
73 roll_index = 0
74
75 # Process frames 1-9
76 while frame_count < 9 and roll_index < len(self.rolls):
77 if self.rolls[roll_index] == 10: # Strike
78 roll_index += 1
79 else:
80 if roll_index + 1 >= len(self.rolls):
81 return False # Incomplete frame
82 roll_index += 2
83 frame_count += 1
84
85 # Process 10th frame
86 if frame_count < 9: # Should never happen with the while loop above
87 return False
88
89 # Check if we have any rolls for the 10th frame
90 if roll_index >= len(self.rolls):
91 return False
92
93 # 10th frame logic
94 if self.rolls[roll_index] == 10: # Strike in 10th frame
95 # Need 2 more rolls for bonus
96 return roll_index + 2 < len(self.rolls)
97 elif roll_index + 1 < len(self.rolls) and self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare in 10th frame
98 # Need 1 more roll for bonus
99 return roll_index + 2 < len(self.rolls)
100 else:
101 # Open frame in 10th frame - no bonus rolls needed
102 return roll_index + 1 < len(self.rolls)
103
8104 def score(self):
9 pass
105 """
106 Calculate the total score for the game.
107
108 Returns:
109 int: The total score of the game.
110
111 Raises:
112 IndexError: If the game is not yet complete.
113 """
114 # Edge Case: Game not yet complete
115 if not self.is_game_complete():
116 raise IndexError("Game is not yet complete")
117
118 score = 0
119 roll_index = 0
120
121 for frame in range(10):
122 if frame < 9: # Frames 1-9
123 if self.rolls[roll_index] == 10: # Strike
124 score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
125 roll_index += 1
126 else:
127 frame_score = self.rolls[roll_index] + self.rolls[roll_index + 1]
128 if frame_score == 10: # Spare
129 score += 10 + self.rolls[roll_index + 2]
130 else: # Open frame
131 score += frame_score
132 roll_index += 2
133 else: # Frame 10
134 if self.rolls[roll_index] == 10: # Strike
135 score += 10 + self.rolls[roll_index + 1] + self.rolls[roll_index + 2]
136 elif self.rolls[roll_index] + self.rolls[roll_index + 1] == 10: # Spare
137 score += 10 + self.rolls[roll_index + 2]
138 else: # Open frame
139 score += self.rolls[roll_index] + self.rolls[roll_index + 1]
140
141 return score
142 # Handled Edge Cases: Invalid pin count, game already completed, exceeding 10 pins in a frame,
143 # game not complete, incomplete tenth frame, invalid fill balls,
144 # strike in frames 1-9, spare in frames 1-9, open frame in frames 1-9,
145 # tenth frame scoring (strike, spare, open)
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.