Skip to content

Commit 781c814

Browse files
authored
Add Bowling for Racket (#412)
1 parent 19df369 commit 781c814

File tree

7 files changed

+449
-0
lines changed

7 files changed

+449
-0
lines changed

config.json

+8
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,14 @@
742742
],
743743
"prerequisites": [],
744744
"difficulty": 8
745+
},
746+
{
747+
"slug": "bowling",
748+
"name": "Bowling",
749+
"uuid": "f6ca2cb9-f169-4c3e-8a64-6d3326b01d70",
750+
"practices": [],
751+
"prerequisites": [],
752+
"difficulty": 6
745753
}
746754
]
747755
},
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.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"authors": ["blakelewis"],
3+
"files": {
4+
"solution": [
5+
"bowling.rkt"
6+
],
7+
"test": [
8+
"bowling-test.rkt"
9+
],
10+
"example": [
11+
".meta/example.rkt"
12+
]
13+
},
14+
"blurb": "Score a bowling game.",
15+
"source": "The Bowling Game Kata from UncleBob",
16+
"source_url": "https://web.archive.org/web/20221001111000/http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata"
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#lang racket
2+
3+
(provide game%)
4+
5+
(define game%
6+
(class object%
7+
(super-new)
8+
(define frame 1)
9+
(define ball 0)
10+
(define standing 10)
11+
(define total 0)
12+
(define bonus1 0)
13+
(define bonus2 0)
14+
(define fill-balls 0)
15+
16+
(define (game-over?)
17+
(and (> frame 10) (zero? fill-balls)))
18+
19+
(define (new-frame)
20+
(set! frame (add1 frame))
21+
(set! standing 10))
22+
23+
(define (add-roll pins)
24+
(define bonus
25+
(cond [(> frame 10) (max 0 (- bonus1 (- frame 10)))]
26+
[(zero? ball) bonus1]
27+
[else bonus2]))
28+
29+
(if (zero? ball) (set! bonus1 0) (set! bonus2 0))
30+
31+
(set! total (+ total (* pins (add1 bonus))))
32+
(set! standing (- standing pins))
33+
(cond
34+
[(zero? standing)
35+
(cond
36+
[(zero? ball) ; strike
37+
(set! bonus1 (add1 bonus2))
38+
(set! bonus2 1)
39+
(when (= frame 10) (set! fill-balls 2))]
40+
[else ; spare
41+
(set! bonus1 1)
42+
(when (= frame 10) (set! fill-balls 1))
43+
(set! ball 0)])]
44+
[else ; ordinary roll
45+
(set! ball (- 1 ball))])
46+
(when (> frame 10) (set! fill-balls (sub1 fill-balls)))
47+
(when (zero? ball) (new-frame)))
48+
49+
(define/public (roll pins)
50+
(when (or (< pins 0) (> pins standing))
51+
(error "Invalid number of pins"))
52+
(when (game-over?)
53+
(error "Game is over"))
54+
(add-roll pins))
55+
56+
(define/public (score)
57+
(cond
58+
[(game-over?) total]
59+
[else (error "Game is not over")]))))
+103
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"

0 commit comments

Comments
 (0)