Skip to content

Commit bc3579a

Browse files
authored
Merge pull request #174 from atk/bowling
new exercise: bowling
2 parents 8b0d862 + 05989b9 commit bc3579a

File tree

12 files changed

+766
-0
lines changed

12 files changed

+766
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,14 @@
383383
"prerequisites": [],
384384
"difficulty": 6
385385
},
386+
{
387+
"slug": "bowling",
388+
"name": "Bowling",
389+
"uuid": "4b4f120f-1057-465f-a910-a0cdae7a4993",
390+
"practices": [],
391+
"prerequisites": [],
392+
"difficulty": 6
393+
},
386394
{
387395
"slug": "kindergarten-garden",
388396
"name": "Kindergarten Garden",
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Instructions
2+
3+
Score a bowling game.
4+
5+
Bowling is a game where players roll a heavy ball to knock down pins arranged in a triangle.
6+
Write code to keep track of the score of a game of bowling.
7+
8+
## Scoring Bowling
9+
10+
The game consists of 10 frames.
11+
A frame is composed of one or two ball throws with 10 pins standing at frame initialization.
12+
There are three cases for the tabulation of a frame.
13+
14+
- An open frame is where a score of less than 10 is recorded for the frame.
15+
In this case the score for the frame is the number of pins knocked down.
16+
17+
- A spare is where all ten pins are knocked down by the second throw.
18+
The total value of a spare is 10 plus the number of pins knocked down in their next throw.
19+
20+
- A strike is where all ten pins are knocked down by the first throw.
21+
The total value of a strike is 10 plus the number of pins knocked down in the next two throws.
22+
If a strike is immediately followed by a second strike, then the value of the first strike cannot be determined until the ball is thrown one more time.
23+
24+
Here is a three frame example:
25+
26+
| Frame 1 | Frame 2 | Frame 3 |
27+
| :--------: | :--------: | :--------------: |
28+
| X (strike) | 5/ (spare) | 9 0 (open frame) |
29+
30+
Frame 1 is (10 + 5 + 5) = 20
31+
32+
Frame 2 is (5 + 5 + 9) = 19
33+
34+
Frame 3 is (9 + 0) = 9
35+
36+
This means the current running total is 48.
37+
38+
The tenth frame in the game is a special case.
39+
If someone throws a spare or a strike then they get one or two fill balls respectively.
40+
Fill balls exist to calculate the total of the 10th frame.
41+
Scoring a strike or spare on the fill ball does not give the player more fill balls.
42+
The total value of the 10th frame is the total number of pins knocked down.
43+
44+
For a tenth frame of X1/ (strike and a spare), the total value is 20.
45+
46+
For a tenth frame of XXX (three strikes), the total value is 30.
47+
48+
## Requirements
49+
50+
Write code to keep track of the score of a game of bowling.
51+
It should support two operations:
52+
53+
- `roll(pins : int)` is called each time the player rolls a ball.
54+
The argument is the number of pins knocked down.
55+
- `score() : int` is called only at the very end of the game.
56+
It returns the total score for that game.

exercises/practice/bowling/.eslintrc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"root": true,
3+
"extends": "@exercism/eslint-config-javascript",
4+
"env": {
5+
"jest": true
6+
},
7+
"overrides": [
8+
{
9+
"files": [
10+
"*.spec.js"
11+
],
12+
"excludedFiles": [
13+
"custom.spec.js"
14+
],
15+
"extends": "@exercism/eslint-config-javascript/maintainers"
16+
}
17+
]
18+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"authors": [
3+
"atk"
4+
],
5+
"files": {
6+
"solution": [
7+
"bowling.wat"
8+
],
9+
"test": [
10+
"bowling.spec.js"
11+
],
12+
"example": [
13+
".meta/proof.ci.wat"
14+
],
15+
"invalidator": [
16+
"package.json"
17+
]
18+
},
19+
"blurb": "Score a bowling game.",
20+
"source": "The Bowling Game Kata from UncleBob",
21+
"source_url": "https://web.archive.org/web/20221001111000/http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata",
22+
"custom": {
23+
"version.tests.compatibility": "jest-27",
24+
"flag.tests.task-per-describe": false,
25+
"flag.tests.may-run-long": false,
26+
"flag.tests.includes-optional": false
27+
}
28+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
(module
2+
;; status codes
3+
(global $ok i32 (i32.const 0))
4+
(global $negativeRoll i32 (i32.const -1))
5+
(global $exceedingPinCount i32 (i32.const -2))
6+
(global $rollAfterEnd i32 (i32.const -3))
7+
(global $prematureScoring i32 (i32.const -4))
8+
9+
;; empty stack
10+
(global $empty i32 (i32.const -1))
11+
12+
;; game data
13+
(global $score (mut i32) (i32.const 0))
14+
(global $frame (mut i32) (i32.const 0))
15+
(global $stackA (mut i32) (i32.const -1))
16+
(global $stackB (mut i32) (i32.const -1))
17+
18+
;;
19+
;; Collect a roll
20+
;;
21+
;; @param {i32} points - the points scored by a single roll
22+
;;
23+
;; @result {i32} - status code (see globals)
24+
;;
25+
(func (export "roll") (param $points i32) (result i32)
26+
(if (i32.ge_u (global.get $frame) (i32.const 10)) (then (return (global.get $rollAfterEnd))))
27+
(if (i32.lt_s (local.get $points) (i32.const 0)) (then (return (global.get $negativeRoll))))
28+
;; points > 10
29+
(if (i32.or (i32.gt_s (local.get $points) (i32.const 10)) (i32.or
30+
;; stackA < 10, stackB = empty, stackA + points > 10
31+
(i32.and (i32.and (i32.ne (global.get $stackA) (i32.const 10))
32+
(i32.eq (global.get $stackB) (global.get $empty)))
33+
(i32.gt_s (i32.add (global.get $stackA) (local.get $points)) (i32.const 10)))
34+
;; stackA = 10, stackB = 0..9, stackB + points > 10
35+
(i32.and (i32.and (i32.eq (global.get $stackA) (i32.const 10))
36+
(i32.and (i32.ne (global.get $stackB) (global.get $empty)) (i32.ne (global.get $stackB) (i32.const 10))))
37+
(i32.gt_s (i32.add (global.get $stackB) (local.get $points)) (i32.const 10)))))
38+
(then (return (global.get $exceedingPinCount))))
39+
;; 2 in stack + 1 roll
40+
(if (i32.ne (global.get $stackB) (global.get $empty)) (then
41+
(global.set $score (i32.add (i32.add (i32.add (global.get $score) (global.get $stackA))
42+
(global.get $stackB)) (local.get $points)))
43+
(global.set $frame (i32.add (global.get $frame) (i32.const 1)))
44+
(if (i32.eq (global.get $stackA) (i32.const 10)) (then
45+
(global.set $stackA (global.get $stackB))
46+
(global.set $stackB (local.get $points)))
47+
(else
48+
(global.set $stackA (local.get $points))
49+
(global.set $stackB (global.get $empty)))))
50+
;; 1 in stack + 1 roll, being a spare
51+
(else (if (i32.and (i32.ne (global.get $stackA) (global.get $empty))
52+
(i32.lt_u (i32.add (global.get $stackA) (local.get $points)) (i32.const 10))) (then
53+
(global.set $score (i32.add (i32.add (global.get $score) (global.get $stackA)) (local.get $points)))
54+
(global.set $frame (i32.add (global.get $frame) (i32.const 1)))
55+
(global.set $stackA (global.get $empty))
56+
(global.set $stackB (global.get $empty)))
57+
;; otherwise push to stack
58+
(else
59+
(if (i32.eq (global.get $stackA) (global.get $empty))
60+
(then (global.set $stackA (local.get $points)))
61+
(else (global.set $stackB (local.get $points))))
62+
))))
63+
(global.get $ok)
64+
)
65+
66+
;;
67+
;; Score the game
68+
;;
69+
;; @result {i32} - points or status code (see globals)
70+
;;
71+
(func (export "score") (result i32)
72+
(select (global.get $score)
73+
(global.get $prematureScoring)
74+
(i32.eq (global.get $frame) (i32.const 10)))
75+
)
76+
)
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[656ae006-25c2-438c-a549-f338e7ec7441]
13+
description = "should be able to score a game with all zeros"
14+
15+
[f85dcc56-cd6b-4875-81b3-e50921e3597b]
16+
description = "should be able to score a game with no strikes or spares"
17+
18+
[d1f56305-3ac2-4fe0-8645-0b37e3073e20]
19+
description = "a spare followed by zeros is worth ten points"
20+
21+
[0b8c8bb7-764a-4287-801a-f9e9012f8be4]
22+
description = "points scored in the roll after a spare are counted twice"
23+
24+
[4d54d502-1565-4691-84cd-f29a09c65bea]
25+
description = "consecutive spares each get a one roll bonus"
26+
27+
[e5c9cf3d-abbe-4b74-ad48-34051b2b08c0]
28+
description = "a spare in the last frame gets a one roll bonus that is counted once"
29+
30+
[75269642-2b34-4b72-95a4-9be28ab16902]
31+
description = "a strike earns ten points in a frame with a single roll"
32+
33+
[037f978c-5d01-4e49-bdeb-9e20a2e6f9a6]
34+
description = "points scored in the two rolls after a strike are counted twice as a bonus"
35+
36+
[1635e82b-14ec-4cd1-bce4-4ea14bd13a49]
37+
description = "consecutive strikes each get the two roll bonus"
38+
39+
[e483e8b6-cb4b-4959-b310-e3982030d766]
40+
description = "a strike in the last frame gets a two roll bonus that is counted once"
41+
42+
[9d5c87db-84bc-4e01-8e95-53350c8af1f8]
43+
description = "rolling a spare with the two roll bonus does not get a bonus roll"
44+
45+
[576faac1-7cff-4029-ad72-c16bcada79b5]
46+
description = "strikes with the two roll bonus do not get bonus rolls"
47+
48+
[efb426ec-7e15-42e6-9b96-b4fca3ec2359]
49+
description = "last two strikes followed by only last bonus with non strike points"
50+
51+
[72e24404-b6c6-46af-b188-875514c0377b]
52+
description = "a strike with the one roll bonus after a spare in the last frame does not get a bonus"
53+
54+
[62ee4c72-8ee8-4250-b794-234f1fec17b1]
55+
description = "all strikes is a perfect game"
56+
57+
[1245216b-19c6-422c-b34b-6e4012d7459f]
58+
description = "rolls cannot score negative points"
59+
60+
[5fcbd206-782c-4faa-8f3a-be5c538ba841]
61+
description = "a roll cannot score more than 10 points"
62+
63+
[fb023c31-d842-422d-ad7e-79ce1db23c21]
64+
description = "two rolls in a frame cannot score more than 10 points"
65+
66+
[6082d689-d677-4214-80d7-99940189381b]
67+
description = "bonus roll after a strike in the last frame cannot score more than 10 points"
68+
69+
[e9565fe6-510a-4675-ba6b-733a56767a45]
70+
description = "two bonus rolls after a strike in the last frame cannot score more than 10 points"
71+
72+
[2f6acf99-448e-4282-8103-0b9c7df99c3d]
73+
description = "two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike"
74+
75+
[6380495a-8bc4-4cdb-a59f-5f0212dbed01]
76+
description = "the second bonus rolls after a strike in the last frame cannot be a strike if the first one is not a strike"
77+
78+
[2b2976ea-446c-47a3-9817-42777f09fe7e]
79+
description = "second bonus roll after a strike in the last frame cannot score more than 10 points"
80+
81+
[29220245-ac8d-463d-bc19-98a94cfada8a]
82+
description = "an unstarted game cannot be scored"
83+
84+
[4473dc5d-1f86-486f-bf79-426a52ddc955]
85+
description = "an incomplete game cannot be scored"
86+
87+
[2ccb8980-1b37-4988-b7d1-e5701c317df3]
88+
description = "cannot roll if game already has ten frames"
89+
90+
[4864f09b-9df3-4b65-9924-c595ed236f1b]
91+
description = "bonus rolls for a strike in the last frame must be rolled before score can be calculated"
92+
93+
[537f4e37-4b51-4d1c-97e2-986eb37b2ac1]
94+
description = "both bonus rolls for a strike in the last frame must be rolled before score can be calculated"
95+
96+
[8134e8c1-4201-4197-bf9f-1431afcde4b9]
97+
description = "bonus roll for a spare in the last frame must be rolled before score can be calculated"
98+
99+
[9d4a9a55-134a-4bad-bae8-3babf84bd570]
100+
description = "cannot roll after bonus roll for spare"
101+
102+
[d3e02652-a799-4ae3-b53b-68582cc604be]
103+
description = "cannot roll after bonus rolls for strike"

exercises/practice/bowling/.npmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
audit=false

exercises/practice/bowling/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Exercism
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default {
2+
presets: ["@exercism/babel-preset-javascript"],
3+
plugins: [],
4+
};

0 commit comments

Comments
 (0)