Browse Source

Merge pull request #675 from dawcars/bowling-exercise

bowling: add to track
Logan Stucki 9 years ago
parent
commit
4e721cd2b4

+ 7
- 0
config.json View File

@@ -388,6 +388,13 @@
388 388
     	]
389 389
     },
390 390
     {
391
+    	"slug": "bowling",
392
+    	"difficulty": 6,
393
+    	"topics": [
394
+
395
+    	]
396
+    },
397
+    {
391 398
       "slug": "anagram",
392 399
       "difficulty": 7,
393 400
       "topics": [

+ 18
- 0
exercises/bowling/build.gradle View File

@@ -0,0 +1,18 @@
1
+apply plugin: "java"
2
+apply plugin: "eclipse"
3
+apply plugin: "idea"
4
+
5
+repositories {
6
+  mavenCentral()
7
+}
8
+
9
+dependencies {
10
+  testCompile "junit:junit:4.12"
11
+}
12
+
13
+test {
14
+  testLogging {
15
+    exceptionFormat = 'full'
16
+    events = ["passed", "failed", "skipped"]
17
+  }
18
+}

+ 84
- 0
exercises/bowling/src/example/java/BowlingGame.java View File

@@ -0,0 +1,84 @@
1
+import java.util.ArrayList;
2
+import java.util.List;
3
+
4
+public class BowlingGame {
5
+    private static final int NUMBER_OF_FRAMES = 10;
6
+    private static final int MAXIMUM_FRAME_SCORE = 10;
7
+    private List<Integer> rolls = new ArrayList<Integer>();
8
+
9
+    public void roll(int pins) {
10
+        rolls.add(pins);
11
+    }
12
+
13
+    public int score() {
14
+        int score = 0;
15
+        int frameIndex = 0;
16
+
17
+        for (int i = 1; i <= NUMBER_OF_FRAMES; i++) {
18
+            if (rolls.size() <= frameIndex) {
19
+                throw new IllegalStateException("Score cannot be taken until the end of the game");
20
+            }
21
+
22
+            if (isStrike(frameIndex)) {
23
+                if (rolls.size() <= frameIndex + 2) {
24
+                    throw new IllegalStateException("Score cannot be taken until the end of the game");
25
+                }
26
+
27
+                int strikeBonus = strikeBonus(frameIndex);
28
+                if (strikeBonus > MAXIMUM_FRAME_SCORE && !isStrike(frameIndex + 1)) {
29
+                    throw new IllegalStateException("Pin count exceeds pins on the lane");
30
+                }
31
+
32
+                score += 10 + strikeBonus;
33
+                frameIndex += i == NUMBER_OF_FRAMES ? 3 : 1;
34
+            } else if (isSpare(frameIndex)) {
35
+                if (rolls.size() <= frameIndex + 2) {
36
+                    throw new IllegalStateException("Score cannot be taken until the end of the game");
37
+                }
38
+
39
+                score += 10 + spareBonus(frameIndex);
40
+                frameIndex += i == NUMBER_OF_FRAMES ? 3 : 2;
41
+            } else {
42
+                int frameScore = frameScore(frameIndex);
43
+                if (frameScore < 0) {
44
+                    throw new IllegalStateException("Negative roll is invalid");
45
+                } else if (frameScore > 10) {
46
+                    throw new IllegalStateException("Pin count exceeds pins on the lane");
47
+                }
48
+
49
+                score += frameScore;
50
+                frameIndex += 2;
51
+            }
52
+        }
53
+
54
+        if (!correctNumberOfRolls(frameIndex)) {
55
+            throw new IllegalStateException("Cannot roll after game is over");
56
+        }
57
+
58
+        return score;
59
+    }
60
+
61
+    private boolean correctNumberOfRolls(int frameIndex) {
62
+        return frameIndex == rolls.size();
63
+    }
64
+
65
+    private boolean isStrike(int frameIndex) {
66
+        return rolls.get(frameIndex) == MAXIMUM_FRAME_SCORE;
67
+    }
68
+
69
+    private boolean isSpare(int frameIndex) {
70
+        return rolls.get(frameIndex) + rolls.get(frameIndex + 1) == MAXIMUM_FRAME_SCORE;
71
+    }
72
+
73
+    private int strikeBonus(int frameIndex) {
74
+        return rolls.get(frameIndex + 1) + rolls.get(frameIndex + 2);
75
+    }
76
+
77
+    private int spareBonus(int frameIndex) {
78
+        return rolls.get(frameIndex + 2);
79
+    }
80
+
81
+    private int frameScore(int frameIndex) {
82
+        return rolls.get(frameIndex) + rolls.get(frameIndex + 1);
83
+    }
84
+}

+ 0
- 0
exercises/bowling/src/main/java/.keep View File


+ 291
- 0
exercises/bowling/src/test/java/BowlingTest.java View File

@@ -0,0 +1,291 @@
1
+import org.junit.Before;
2
+import org.junit.Ignore;
3
+import org.junit.Rule;
4
+import org.junit.Test;
5
+import org.junit.rules.ExpectedException;
6
+
7
+import static org.junit.Assert.assertEquals;
8
+
9
+public class BowlingTest {
10
+    private BowlingGame game;
11
+
12
+    @Rule
13
+    public ExpectedException expectedException = ExpectedException.none();
14
+
15
+    @Before
16
+    public void setup() {
17
+        game = new BowlingGame();
18
+    }
19
+
20
+    private void playGame(int[] rolls) {
21
+        for (int pins : rolls) {
22
+            game.roll(pins);
23
+        }
24
+    }
25
+
26
+    @Test
27
+    public void shouldBeAbleToScoreAGameWithAllZeros() {
28
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
29
+
30
+        playGame(rolls);
31
+        assertEquals(0, game.score());
32
+    }
33
+
34
+    @Ignore("Remove to run test")
35
+    @Test
36
+    public void shouldBeAbleToScoreAGameWithNoStrikesOrSpares() {
37
+        int[] rolls = {3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6};
38
+
39
+        playGame(rolls);
40
+        assertEquals(90, game.score());
41
+    }
42
+
43
+    @Ignore("Remove to run test")
44
+    @Test
45
+    public void aSpareFollowedByZerosIsWorthTenPoints() {
46
+        int[] rolls = {6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
47
+
48
+        playGame(rolls);
49
+        assertEquals(10, game.score());
50
+    }
51
+
52
+    @Ignore("Remove to run test")
53
+    @Test
54
+    public void pointsScoredInTheRollAfterASpareAreCountedTwice() {
55
+        int[] rolls = {6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
56
+
57
+        playGame(rolls);
58
+        assertEquals(16, game.score());
59
+    }
60
+
61
+    @Ignore("Remove to run test")
62
+    @Test
63
+    public void consecutiveSparesEachGetAOneRollBonus() {
64
+        int[] rolls = {5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
65
+
66
+        playGame(rolls);
67
+        assertEquals(31, game.score());
68
+    }
69
+
70
+    @Ignore("Remove to run test")
71
+    @Test
72
+    public void aSpareInTheLastFrameGetsAOneRollBonusThatIsCountedOnce() {
73
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7};
74
+
75
+        playGame(rolls);
76
+        assertEquals(17, game.score());
77
+    }
78
+
79
+    @Ignore("Remove to run test")
80
+    @Test
81
+    public void aStrikeEarnsTenPointsInFrameWithASingleRoll() {
82
+        int[] rolls = {10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
83
+
84
+        playGame(rolls);
85
+        assertEquals(10, game.score());
86
+    }
87
+
88
+    @Ignore("Remove to run test")
89
+    @Test
90
+    public void pointsScoredInTheTwoRollsAfterAStrikeAreCountedTwiceAsABonus() {
91
+        int[] rolls = {10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
92
+
93
+        playGame(rolls);
94
+        assertEquals(26, game.score());
95
+    }
96
+
97
+    @Ignore("Remove to run test")
98
+    @Test
99
+    public void consecutiveStrikesEachGetTheTwoRollBonus() {
100
+        int[] rolls = {10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
101
+
102
+        playGame(rolls);
103
+        assertEquals(81, game.score());
104
+    }
105
+
106
+    @Ignore("Remove to run test")
107
+    @Test
108
+    public void aStrikeInTheLastFrameGetsATwoRollBonusThatIsCountedOnce() {
109
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1};
110
+
111
+        playGame(rolls);
112
+        assertEquals(18, game.score());
113
+    }
114
+
115
+    @Ignore("Remove to run test")
116
+    @Test
117
+    public void rollingASpareWithTheTwoRollBonusDoesNotGetABonusRoll() {
118
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3};
119
+
120
+        playGame(rolls);
121
+        assertEquals(20, game.score());
122
+    }
123
+
124
+    @Ignore("Remove to run test")
125
+    @Test
126
+    public void strikesWithTheTwoRollBonusDoNotGetBonusRolls() {
127
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10};
128
+
129
+        playGame(rolls);
130
+        assertEquals(30, game.score());
131
+    }
132
+
133
+    @Ignore("Remove to run test")
134
+    @Test
135
+    public void aStrikeWithTheOneRollBonusAfterASpareInTheLastFrameDoesNotGetABonus() {
136
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10};
137
+
138
+        playGame(rolls);
139
+        assertEquals(20, game.score());
140
+    }
141
+
142
+    @Ignore("Remove to run test")
143
+    @Test
144
+    public void allStrikesIsAPerfectGame() {
145
+        int[] rolls = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
146
+
147
+        playGame(rolls);
148
+        assertEquals(300, game.score());
149
+    }
150
+
151
+    @Ignore("Remove to run test")
152
+    @Test
153
+    public void rollsCanNotScoreNegativePoints() throws IllegalStateException {
154
+        int[] rolls = {-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
155
+
156
+        playGame(rolls);
157
+
158
+        expectedException.expect(IllegalStateException.class);
159
+        expectedException.expectMessage("Negative roll is invalid");
160
+
161
+        game.score();
162
+    }
163
+
164
+    @Ignore("Remove to run test")
165
+    @Test
166
+    public void aRollCanNotScoreMoreThan10Points() throws IllegalStateException {
167
+        int[] rolls = {11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
168
+
169
+        playGame(rolls);
170
+
171
+        expectedException.expect(IllegalStateException.class);
172
+        expectedException.expectMessage("Pin count exceeds pins on the lane");
173
+
174
+        game.score();
175
+    }
176
+
177
+    @Ignore("Remove to run test")
178
+    @Test
179
+    public void twoRollsInAFrameCanNotScoreMoreThan10Points() throws IllegalStateException {
180
+        int[] rolls = {5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
181
+
182
+        playGame(rolls);
183
+
184
+        expectedException.expect(IllegalStateException.class);
185
+        expectedException.expectMessage("Pin count exceeds pins on the lane");
186
+
187
+        game.score();
188
+    }
189
+
190
+    @Ignore("Remove to run test")
191
+    @Test
192
+    public void twoBonusRollsAfterAStrikeInTheLastFrameCanNotScoreMoreThan10Points() throws IllegalStateException {
193
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 6};
194
+
195
+        playGame(rolls);
196
+
197
+        expectedException.expect(IllegalStateException.class);
198
+        expectedException.expectMessage("Pin count exceeds pins on the lane");
199
+
200
+        game.score();
201
+    }
202
+
203
+    @Ignore("Remove to run test")
204
+    @Test
205
+    public void twoBonusRollsAfterAStrikeInTheLastFrameCanScoreMoreThan10PointsIfOneIsAStrike() throws IllegalStateException {
206
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6};
207
+
208
+        playGame(rolls);
209
+
210
+        assertEquals(26, game.score());
211
+    }
212
+
213
+    @Ignore("Remove to run test")
214
+    @Test
215
+    public void anUnstartedGameCanNotBeScored() throws IllegalStateException {
216
+        int[] rolls = new int[0];
217
+
218
+        playGame(rolls);
219
+
220
+        expectedException.expect(IllegalStateException.class);
221
+        expectedException.expectMessage("Score cannot be taken until the end of the game");
222
+
223
+        game.score();
224
+    }
225
+
226
+    @Ignore("Remove to run test")
227
+    @Test
228
+    public void anIncompleteGameCanNotBeScored() throws IllegalStateException {
229
+        int[] rolls = {0, 0};
230
+
231
+        playGame(rolls);
232
+
233
+        expectedException.expect(IllegalStateException.class);
234
+        expectedException.expectMessage("Score cannot be taken until the end of the game");
235
+
236
+        game.score();
237
+    }
238
+
239
+    @Ignore("Remove to run test")
240
+    @Test
241
+    public void aGameWithMoreThanTenFramesCanNotBeScored() throws IllegalStateException {
242
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
243
+
244
+        playGame(rolls);
245
+
246
+        expectedException.expect(IllegalStateException.class);
247
+        expectedException.expectMessage("Cannot roll after game is over");
248
+
249
+        game.score();
250
+    }
251
+
252
+    @Ignore("Remove to run test")
253
+    @Test
254
+    public void bonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated() throws IllegalStateException {
255
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10};
256
+
257
+        playGame(rolls);
258
+
259
+        expectedException.expect(IllegalStateException.class);
260
+        expectedException.expectMessage("Score cannot be taken until the end of the game");
261
+
262
+        game.score();
263
+    }
264
+
265
+    @Ignore("Remove to run test")
266
+    @Test
267
+    public void bothBonusRollsForAStrikeInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated() throws IllegalStateException {
268
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10};
269
+
270
+        playGame(rolls);
271
+
272
+        expectedException.expect(IllegalStateException.class);
273
+        expectedException.expectMessage("Score cannot be taken until the end of the game");
274
+
275
+        game.score();
276
+    }
277
+
278
+    @Ignore("Remove to run test")
279
+    @Test
280
+    public void bonusRollForASpareInTheLastFrameMustBeRolledBeforeScoreCanBeCalculated() throws IllegalStateException {
281
+        int[] rolls = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3};
282
+
283
+        playGame(rolls);
284
+
285
+        expectedException.expect(IllegalStateException.class);
286
+        expectedException.expectMessage("Score cannot be taken until the end of the game");
287
+
288
+        game.score();
289
+    }
290
+
291
+}

+ 1
- 0
exercises/settings.gradle View File

@@ -11,6 +11,7 @@ include 'binary-search'
11 11
 include 'binary-search-tree'
12 12
 include 'bob'
13 13
 include 'book-store'
14
+include 'bowling'
14 15
 include 'bracket-push'
15 16
 include 'change'
16 17
 include 'clock'