Finished
44//
55
66export class Bowling {
7 constructor() {
8 this.rolls = [];
9 this.currentRoll = 0;
10 }
11
712 /**
813 * @param {number} pins
914 */
1015 roll(pins) {
11 throw new Error('Remove this line and implement the function');
16 // Edge Case: Negative roll is invalid
17 if (pins < 0) {
18 throw new Error('Negative roll is invalid');
19 }
20
21 // Edge Case: Pin count exceeds pins on the lane
22 if (pins > 10) {
23 throw new Error('Pin count exceeds pins on the lane');
24 }
25
26 // Edge Case: Cannot roll after game is over
27 if (this.isGameOver()) {
28 throw new Error('Cannot roll after game is over');
29 }
30
31 // Edge Case: Pin count exceeds pins on the lane (in frame)
32 // Need to check if we're in a regular frame (not 10th frame)
33 if (!this.isInTenthFrame() && this.currentRoll > 0) {
34 const previousRoll = this.rolls[this.currentRoll - 1];
35 // Check if we're on the second roll of a frame
36 const isSecondRoll = this.isSecondRollOfFrame();
37
38 if (isSecondRoll && previousRoll + pins > 10) {
39 throw new Error('Pin count exceeds pins on the lane');
40 }
41 }
42
43 this.rolls[this.currentRoll++] = pins;
1244 }
1345
1446 /**
1547 * @returns {number}
1648 */
1749 score() {
18 throw new Error('Remove this line and implement the function');
50 // Edge Case: Score cannot be taken until the end of the game
51 if (!this.isGameOver()) {
52 throw new Error('Score cannot be taken until the end of the game');
53 }
54
55 let score = 0;
56 let rollIndex = 0;
57
58 for (let frame = 0; frame < 10; frame++) {
59 if (this.isStrike(rollIndex)) {
60 score += 10 + this.strikeBonus(rollIndex);
61 rollIndex++;
62 } else if (this.isSpare(rollIndex)) {
63 score += 10 + this.spareBonus(rollIndex);
64 rollIndex += 2;
65 } else {
66 score += this.sumOfBallsInFrame(rollIndex);
67 rollIndex += 2;
68 }
69 }
70
71 return score;
72 }
73
74 isGameOver() {
75 let frameIndex = 0;
76 let rollIndex = 0;
77
78 // Count frames through first 9 frames
79 for (let frame = 0; frame < 9; frame++) {
80 if (rollIndex >= this.currentRoll) {
81 return false; // Not enough rolls yet
82 }
83
84 if (this.rolls[rollIndex] === 10) {
85 // Strike
86 rollIndex += 1;
87 } else {
88 // Regular frame or spare
89 if (rollIndex + 1 >= this.currentRoll) {
90 return false; // Not enough rolls for this frame
91 }
92 rollIndex += 2;
93 }
94 }
95
96 // Check if we have enough rolls for 10th frame
97 if (rollIndex >= this.currentRoll) {
98 return false; // No 10th frame yet
99 }
100
101 // Handle 10th frame
102 const firstRoll = this.rolls[rollIndex];
103
104 if (firstRoll === 10) {
105 // Strike in 10th frame - need 2 more rolls
106 return rollIndex + 3 <= this.currentRoll;
107 } else if (rollIndex + 1 < this.currentRoll && firstRoll + this.rolls[rollIndex + 1] === 10) {
108 // Spare in 10th frame - need 1 more roll
109 return rollIndex + 3 <= this.currentRoll;
110 } else {
111 // Open frame in 10th - need exactly 2 rolls
112 return rollIndex + 2 <= this.currentRoll;
113 }
114 }
115
116 isStrike(rollIndex) {
117 return this.rolls[rollIndex] === 10;
19118 }
119
120 isSpare(rollIndex) {
121 return this.rolls[rollIndex] + this.rolls[rollIndex + 1] === 10;
122 }
123
124 sumOfBallsInFrame(rollIndex) {
125 return this.rolls[rollIndex] + this.rolls[rollIndex + 1];
126 }
127
128 spareBonus(rollIndex) {
129 return this.rolls[rollIndex + 2];
130 }
131
132 strikeBonus(rollIndex) {
133 return this.rolls[rollIndex + 1] + this.rolls[rollIndex + 2];
134 }
135
136 isInTenthFrame() {
137 let frameCount = 0;
138 let rollIndex = 0;
139
140 // Count frames up to current roll
141 while (rollIndex < this.currentRoll && frameCount < 10) {
142 if (this.rolls[rollIndex] === 10) {
143 // Strike
144 rollIndex += 1;
145 frameCount++;
146 } else {
147 // Regular frame or spare
148 rollIndex += 2;
149 frameCount++;
150 }
151 }
152
153 return frameCount >= 9;
154 }
155
156 isSecondRollOfFrame() {
157 let frameCount = 0;
158 let rollIndex = 0;
159
160 // Count frames up to current roll
161 while (rollIndex < this.currentRoll && frameCount < 10) {
162 if (this.rolls[rollIndex] === 10) {
163 // Strike - only one roll in this frame
164 rollIndex += 1;
165 frameCount++;
166 } else {
167 // Regular frame or spare - two rolls
168 if (rollIndex === this.currentRoll - 1) {
169 return true; // We're on the second roll of this frame
170 }
171 rollIndex += 2;
172 frameCount++;
173 }
174 }
175
176 return false;
177 }
178
179 // Handled Edge Cases: Negative roll is invalid, Pin count exceeds pins on the lane, Cannot roll after game is over, Pin count exceeds pins on the lane (in frame), Score cannot be taken until the end of the game
20180}
Test NameStatus
two bonus rolls after a strike in the last frame cannot score more than 10 points
Fail
the second bonus rolls after a strike in the last frame cannot be a strike if the first one is not a strike
Fail
should be able to score a game with all zeros
Pass
should be able to score a game with no strikes or spares
Pass
a spare followed by zeros is worth ten points
Pass
points scored in the roll after a spare are counted twice
Pass
consecutive spares each get a one roll bonus
Pass
a spare in the last frame gets a one roll bonus that is counted once
Pass
a strike earns ten points in a frame with a single roll
Pass
points scored in the two rolls after a strike are counted twice as a bonus
Pass
consecutive strikes each get the two roll bonus
Pass
a strike in the last frame gets a two roll bonuses that is counted once
Pass
rolling a spare with the two roll bonus does not get a bonus roll
Pass
strikes with the two roll bonus do not get bonus rolls
Pass
last two strikes followed by only last bonus with non strike points
Pass
a strike with the one roll bonus after a spare in the last frame does not get a bonus
Pass
all strikes is a perfect game
Pass
rolls cannot score negative points
Pass
a roll cannot score more than 10 points
Pass
two rolls in a frame cannot score more than 10 points
Pass
bonus roll after a strike in the last frame cannot score more than 10 points
Pass
two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike
Pass
second bonus roll after a strike in the last frame cannot score more than 10 points
Pass
an unstarted game cannot be scored
Pass
an incomplete game cannot be scored
Pass
cannot roll if game already has ten frames
Pass
bonus rolls for a strike in the last frame must be rolled before score can be calculated
Pass
both bonus rolls for a strike in the last frame must be rolled before score can be calculated
Pass
bonus roll for a spare in the last frame must be rolled before score can be calculated
Pass
cannot roll after bonus roll for spare
Pass
cannot roll after bonus rolls for strike
Pass

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