trackler 2.0.8.38 → 2.0.8.39
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/tracks/csharp/exercises/list-ops/HINTS.md +1 -1
- data/tracks/csharp/exercises/nucleotide-count/HINTS.md +3 -0
- data/tracks/go/config.json +8 -0
- data/tracks/go/exercises/bowling/bowling_test.go +77 -0
- data/tracks/go/exercises/bowling/cases_test.go +225 -0
- data/tracks/go/exercises/bowling/example.go +133 -0
- data/tracks/go/exercises/bowling/example_gen.go +117 -0
- data/tracks/go/exercises/leap/cases_test.go +2 -1
- data/tracks/go/exercises/leap/example_gen.go +1 -3
- data/tracks/go/gen/gen.go +39 -6
- data/tracks/perl6/bin/README.md +29 -0
- data/tracks/perl6/bin/exercise-gen.pl6 +36 -0
- data/tracks/perl6/config.json +1 -0
- data/tracks/perl6/exercises/hello-world/example.yaml +19 -0
- data/tracks/perl6/templates/test.mustache +53 -0
- data/tracks/python/.travis.yml +1 -1
- data/tracks/python/README.md +2 -6
- data/tracks/python/config.json +9 -0
- data/tracks/python/exercises/anagram/anagram_test.py +52 -48
- data/tracks/python/exercises/largest-series-product/largest_series_product_test.py +43 -42
- data/tracks/python/exercises/nth-prime/example.py +3 -0
- data/tracks/python/exercises/nth-prime/nth_prime_test.py +15 -5
- data/tracks/python/exercises/rotational-cipher/example.py +14 -0
- data/tracks/python/exercises/rotational-cipher/rotational_cipher.py +2 -0
- data/tracks/python/exercises/rotational-cipher/rotational_cipher_test.py +53 -0
- data/tracks/python/exercises/word-search/example.py +9 -8
- metadata +57 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f16f5a4fa0fdde0642c976d3e020bdf84d359613
|
4
|
+
data.tar.gz: 940657bebb2d0ea237f01459d6beeab37766ee9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f67845a691fb409f1c1453bca11cd939f37647ba716bac4a6ccd8d15cb7d0d50f43098c3448491adfc7724d5ef1c1922e96c6c98b1eefc60368e9786dd26fe87
|
7
|
+
data.tar.gz: 59000762c30e40be13816d4d7413ceff5ca4529b98fb912874a12a7a7a9ea272c003019bf7047769f16e73d19dde9e2912c91f15790735f2aa45099bf53630e3
|
data/lib/trackler/version.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
## Hints
|
2
|
-
The `Foldl`
|
2
|
+
The `Foldl` and `Foldr` methods are "fold" functions, which is a concept well-known in the functional programming world, but less so in the object-oriented one. If you'd like more background information, check out this [fold](https://en.wikipedia.org/wiki/Fold_(higher-order_function)) page.
|
data/tracks/go/config.json
CHANGED
@@ -0,0 +1,77 @@
|
|
1
|
+
package bowling
|
2
|
+
|
3
|
+
import "testing"
|
4
|
+
|
5
|
+
const targetTestVersion = 1
|
6
|
+
|
7
|
+
const previousRollErrorMessage = `FAIL: %s
|
8
|
+
Unexpected error occurred: %q
|
9
|
+
while applying the previous rolls for the
|
10
|
+
test case: %v
|
11
|
+
The error was returned from Roll(%d) for previousRolls[%d].`
|
12
|
+
|
13
|
+
func TestTestVersion(t *testing.T) {
|
14
|
+
if testVersion != targetTestVersion {
|
15
|
+
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
func applyPreviousRolls(g *Game, rolls []int) (int, int, error) {
|
20
|
+
for index, pins := range rolls {
|
21
|
+
var err error
|
22
|
+
if err = g.Roll(pins); err != nil {
|
23
|
+
return index, pins, err
|
24
|
+
}
|
25
|
+
}
|
26
|
+
return 0, 0, nil
|
27
|
+
}
|
28
|
+
|
29
|
+
func TestScore(t *testing.T) {
|
30
|
+
for _, tc := range scoreTestCases {
|
31
|
+
g := NewGame()
|
32
|
+
index, pins, err := applyPreviousRolls(g, tc.previousRolls)
|
33
|
+
if err != nil {
|
34
|
+
t.Fatalf(previousRollErrorMessage,
|
35
|
+
tc.description, err, tc.previousRolls, pins, index)
|
36
|
+
}
|
37
|
+
score, err := g.Score()
|
38
|
+
if tc.valid {
|
39
|
+
var _ error = err
|
40
|
+
if err != nil {
|
41
|
+
t.Fatalf("FAIL: %s : Score() after Previous Rolls: %#v expected %d, got error %s",
|
42
|
+
tc.description, tc.previousRolls, tc.score, err)
|
43
|
+
} else {
|
44
|
+
if score != tc.score {
|
45
|
+
t.Fatalf("%s : Score() after Previous Rolls: %#v expected %d, got %d",
|
46
|
+
tc.description, tc.previousRolls, tc.score, score)
|
47
|
+
}
|
48
|
+
}
|
49
|
+
} else if err == nil {
|
50
|
+
t.Fatalf("FAIL: %s : Score() after Previous Rolls: %#v expected an error, got score %d\n\tExplanation: %s",
|
51
|
+
tc.description, tc.previousRolls, score, tc.explainText)
|
52
|
+
}
|
53
|
+
t.Logf("PASS: %s", tc.description)
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
func TestRoll(t *testing.T) {
|
58
|
+
for _, tc := range rollTestCases {
|
59
|
+
g := NewGame()
|
60
|
+
index, pins, err := applyPreviousRolls(g, tc.previousRolls)
|
61
|
+
if err != nil {
|
62
|
+
t.Fatalf(previousRollErrorMessage,
|
63
|
+
tc.description, err, tc.previousRolls, pins, index)
|
64
|
+
}
|
65
|
+
err = g.Roll(tc.roll)
|
66
|
+
if tc.valid && err != nil {
|
67
|
+
var _ error = err
|
68
|
+
t.Fatalf("FAIL: %s : Roll(%d) after Previous Rolls: %#v got unexpected error \"%s\".",
|
69
|
+
tc.description, tc.roll, tc.previousRolls, err)
|
70
|
+
|
71
|
+
} else if !tc.valid && err == nil {
|
72
|
+
t.Fatalf("FAIL: %s : Roll(%d) after Previous Rolls: %#v expected an error.\n\tExplanation: %s",
|
73
|
+
tc.description, tc.roll, tc.previousRolls, tc.explainText)
|
74
|
+
}
|
75
|
+
t.Logf("PASS: %s", tc.description)
|
76
|
+
}
|
77
|
+
}
|
@@ -0,0 +1,225 @@
|
|
1
|
+
package bowling
|
2
|
+
|
3
|
+
// Source: exercism/x-common
|
4
|
+
// Commit: 3cf5eb9 bowling: Make canonical-data.json compliant
|
5
|
+
// x-common version: 1.0.0
|
6
|
+
|
7
|
+
var scoreTestCases = []struct {
|
8
|
+
description string
|
9
|
+
previousRolls []int // bowling rolls to do before the Score() test
|
10
|
+
valid bool // true => no error, false => error expected
|
11
|
+
score int // when .valid == true, the expected score value
|
12
|
+
explainText string // when .valid == false, error explanation text
|
13
|
+
}{
|
14
|
+
{
|
15
|
+
"should be able to score a game with all zeros",
|
16
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
17
|
+
true,
|
18
|
+
0,
|
19
|
+
"",
|
20
|
+
},
|
21
|
+
{
|
22
|
+
"should be able to score a game with no strikes or spares",
|
23
|
+
[]int{3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6},
|
24
|
+
true,
|
25
|
+
90,
|
26
|
+
"",
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"a spare followed by zeros is worth ten points",
|
30
|
+
[]int{6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
31
|
+
true,
|
32
|
+
10,
|
33
|
+
"",
|
34
|
+
},
|
35
|
+
{
|
36
|
+
"points scored in the roll after a spare are counted twice",
|
37
|
+
[]int{6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
38
|
+
true,
|
39
|
+
16,
|
40
|
+
"",
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"consecutive spares each get a one roll bonus",
|
44
|
+
[]int{5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
45
|
+
true,
|
46
|
+
31,
|
47
|
+
"",
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"a spare in the last frame gets a one roll bonus that is counted once",
|
51
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7},
|
52
|
+
true,
|
53
|
+
17,
|
54
|
+
"",
|
55
|
+
},
|
56
|
+
{
|
57
|
+
"a strike earns ten points in a frame with a single roll",
|
58
|
+
[]int{10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
59
|
+
true,
|
60
|
+
10,
|
61
|
+
"",
|
62
|
+
},
|
63
|
+
{
|
64
|
+
"points scored in the two rolls after a strike are counted twice as a bonus",
|
65
|
+
[]int{10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
66
|
+
true,
|
67
|
+
26,
|
68
|
+
"",
|
69
|
+
},
|
70
|
+
{
|
71
|
+
"consecutive strikes each get the two roll bonus",
|
72
|
+
[]int{10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
73
|
+
true,
|
74
|
+
81,
|
75
|
+
"",
|
76
|
+
},
|
77
|
+
{
|
78
|
+
"a strike in the last frame gets a two roll bonus that is counted once",
|
79
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1},
|
80
|
+
true,
|
81
|
+
18,
|
82
|
+
"",
|
83
|
+
},
|
84
|
+
{
|
85
|
+
"rolling a spare with the two roll bonus does not get a bonus roll",
|
86
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3},
|
87
|
+
true,
|
88
|
+
20,
|
89
|
+
"",
|
90
|
+
},
|
91
|
+
{
|
92
|
+
"strikes with the two roll bonus do not get bonus rolls",
|
93
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10},
|
94
|
+
true,
|
95
|
+
30,
|
96
|
+
"",
|
97
|
+
},
|
98
|
+
{
|
99
|
+
"a strike with the one roll bonus after a spare in the last frame does not get a bonus",
|
100
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10},
|
101
|
+
true,
|
102
|
+
20,
|
103
|
+
"",
|
104
|
+
},
|
105
|
+
{
|
106
|
+
"all strikes is a perfect game",
|
107
|
+
[]int{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
|
108
|
+
true,
|
109
|
+
300,
|
110
|
+
"",
|
111
|
+
},
|
112
|
+
|
113
|
+
{
|
114
|
+
"two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike",
|
115
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6},
|
116
|
+
true,
|
117
|
+
26,
|
118
|
+
"",
|
119
|
+
},
|
120
|
+
|
121
|
+
{
|
122
|
+
"an unstarted game can not be scored",
|
123
|
+
[]int{},
|
124
|
+
false,
|
125
|
+
0,
|
126
|
+
"Score cannot be taken until the end of the game",
|
127
|
+
},
|
128
|
+
{
|
129
|
+
"an incomplete game can not be scored",
|
130
|
+
[]int{0, 0},
|
131
|
+
false,
|
132
|
+
0,
|
133
|
+
"Score cannot be taken until the end of the game",
|
134
|
+
},
|
135
|
+
|
136
|
+
{
|
137
|
+
"bonus rolls for a strike in the last frame must be rolled before score can be calculated",
|
138
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10},
|
139
|
+
false,
|
140
|
+
0,
|
141
|
+
"Score cannot be taken until the end of the game",
|
142
|
+
},
|
143
|
+
{
|
144
|
+
"both bonus rolls for a strike in the last frame must be rolled before score can be calculated",
|
145
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10},
|
146
|
+
false,
|
147
|
+
0,
|
148
|
+
"Score cannot be taken until the end of the game",
|
149
|
+
},
|
150
|
+
{
|
151
|
+
"bonus roll for a spare in the last frame must be rolled before score can be calculated",
|
152
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3},
|
153
|
+
false,
|
154
|
+
0,
|
155
|
+
"Score cannot be taken until the end of the game",
|
156
|
+
},
|
157
|
+
}
|
158
|
+
|
159
|
+
var rollTestCases = []struct {
|
160
|
+
description string
|
161
|
+
previousRolls []int // bowling rolls to do before the Roll(roll) test
|
162
|
+
valid bool // true => no error, false => error expected
|
163
|
+
roll int // pin count for the test roll
|
164
|
+
explainText string // when .valid == false, error explanation text
|
165
|
+
}{
|
166
|
+
|
167
|
+
{
|
168
|
+
"rolls can not score negative points",
|
169
|
+
[]int{},
|
170
|
+
false,
|
171
|
+
-1,
|
172
|
+
"Negative roll is invalid",
|
173
|
+
},
|
174
|
+
{
|
175
|
+
"a roll can not score more than 10 points",
|
176
|
+
[]int{},
|
177
|
+
false,
|
178
|
+
11,
|
179
|
+
"Pin count exceeds pins on the lane",
|
180
|
+
},
|
181
|
+
{
|
182
|
+
"two rolls in a frame can not score more than 10 points",
|
183
|
+
[]int{5},
|
184
|
+
false,
|
185
|
+
6,
|
186
|
+
"Pin count exceeds pins on the lane",
|
187
|
+
},
|
188
|
+
{
|
189
|
+
"bonus roll after a strike in the last frame can not score more than 10 points",
|
190
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10},
|
191
|
+
false,
|
192
|
+
11,
|
193
|
+
"Pin count exceeds pins on the lane",
|
194
|
+
},
|
195
|
+
{
|
196
|
+
"two bonus rolls after a strike in the last frame can not score more than 10 points",
|
197
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5},
|
198
|
+
false,
|
199
|
+
6,
|
200
|
+
"Pin count exceeds pins on the lane",
|
201
|
+
},
|
202
|
+
|
203
|
+
{
|
204
|
+
"the second bonus rolls after a strike in the last frame can not be a strike if the first one is not a strike",
|
205
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6},
|
206
|
+
false,
|
207
|
+
10,
|
208
|
+
"Pin count exceeds pins on the lane",
|
209
|
+
},
|
210
|
+
{
|
211
|
+
"second bonus roll after a strike in the last frame can not score than 10 points",
|
212
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10},
|
213
|
+
false,
|
214
|
+
11,
|
215
|
+
"Pin count exceeds pins on the lane",
|
216
|
+
},
|
217
|
+
|
218
|
+
{
|
219
|
+
"cannot roll if game already has ten frames",
|
220
|
+
[]int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
221
|
+
false,
|
222
|
+
0,
|
223
|
+
"Cannot roll after game is over",
|
224
|
+
},
|
225
|
+
}
|
@@ -0,0 +1,133 @@
|
|
1
|
+
// Package bowling implements scoring for the game of bowling.
|
2
|
+
package bowling
|
3
|
+
|
4
|
+
import "errors"
|
5
|
+
|
6
|
+
const testVersion = 1
|
7
|
+
|
8
|
+
var (
|
9
|
+
ErrNegativeRollIsInvalid = errors.New("Negative roll is invalid")
|
10
|
+
ErrPinCountExceedsPinsOnTheLane = errors.New("Pin count exceeds pins on the lane")
|
11
|
+
ErrPrematureScore = errors.New("Score cannot be taken until the end of the game")
|
12
|
+
ErrCannotRollAfterGameOver = errors.New("Cannot roll after game is over")
|
13
|
+
)
|
14
|
+
|
15
|
+
const (
|
16
|
+
pinsPerFrame = 10
|
17
|
+
framesPerGame = 10
|
18
|
+
maxRollsPerFrame = 2
|
19
|
+
maxRollsLastFrame = 3
|
20
|
+
maxRolls = (maxRollsPerFrame * (framesPerGame - 1)) + maxRollsLastFrame
|
21
|
+
)
|
22
|
+
|
23
|
+
// Game records the data to track a game's progress.
|
24
|
+
type Game struct {
|
25
|
+
rolls [maxRolls]int // storage for the rolls
|
26
|
+
nRolls int // counts the rolls accumulated.
|
27
|
+
nFrames int // counts completed frames, up to framesPerGame.
|
28
|
+
rFrameStart int // tracks the starting roll of each frame.
|
29
|
+
}
|
30
|
+
|
31
|
+
// NewGame returns a fresh zero-valued game struct.
|
32
|
+
func NewGame() *Game {
|
33
|
+
return &Game{}
|
34
|
+
}
|
35
|
+
|
36
|
+
// Roll records one roll for a bowling frame with 'pins' knocked down.
|
37
|
+
// An error is possible depending on pin value and previous rolls.
|
38
|
+
func (g *Game) Roll(pins int) error {
|
39
|
+
// Validate pin count on roll.
|
40
|
+
if pins > pinsPerFrame {
|
41
|
+
return ErrPinCountExceedsPinsOnTheLane
|
42
|
+
}
|
43
|
+
if pins < 0 {
|
44
|
+
return ErrNegativeRollIsInvalid
|
45
|
+
}
|
46
|
+
if g.completedFrames() == framesPerGame {
|
47
|
+
return ErrCannotRollAfterGameOver
|
48
|
+
}
|
49
|
+
// Record the roll.
|
50
|
+
g.rolls[g.nRolls] = pins
|
51
|
+
g.nRolls++
|
52
|
+
if pins == pinsPerFrame && g.completedFrames() < framesPerGame-1 {
|
53
|
+
// Frames before last one can be strikes with no problems.
|
54
|
+
g.completeTheFrame()
|
55
|
+
return nil
|
56
|
+
}
|
57
|
+
if g.rollsThisFrame() == maxRollsPerFrame {
|
58
|
+
// Have counted normal max rolls on a frame.
|
59
|
+
if g.rawFrameScore(g.rFrameStart) > pinsPerFrame {
|
60
|
+
// Unless we have completed all but last frame, cannot count > pinsPerFrame.
|
61
|
+
if g.completedFrames() != framesPerGame-1 || !g.isStrike(g.rFrameStart) {
|
62
|
+
return ErrPinCountExceedsPinsOnTheLane
|
63
|
+
}
|
64
|
+
}
|
65
|
+
if g.completedFrames() < framesPerGame-1 {
|
66
|
+
// Completed frames before last one with maxRollsPerFrame.
|
67
|
+
g.completeTheFrame()
|
68
|
+
return nil
|
69
|
+
}
|
70
|
+
// For last frame, is it complete now ?
|
71
|
+
if g.rawFrameScore(g.rFrameStart) < pinsPerFrame {
|
72
|
+
// Yes, complete.
|
73
|
+
g.completeTheFrame()
|
74
|
+
}
|
75
|
+
} else if g.rollsThisFrame() == maxRollsLastFrame {
|
76
|
+
// Extra roll on the last frame.
|
77
|
+
if g.isStrike(g.rFrameStart) {
|
78
|
+
// First was a strike.
|
79
|
+
if !g.isStrike(g.rFrameStart + 1) {
|
80
|
+
// Second was NOT a strike, so last 2 rolls cannot exceed pinsPerFrame.
|
81
|
+
if g.strikeBonus(g.rFrameStart) > pinsPerFrame {
|
82
|
+
return ErrPinCountExceedsPinsOnTheLane
|
83
|
+
}
|
84
|
+
}
|
85
|
+
if b := g.strikeBonus(g.rFrameStart); b > pinsPerFrame && b < 2*pinsPerFrame {
|
86
|
+
// Unless one of the bonuses was a strike, bonus frames too high.
|
87
|
+
if !g.isStrike(g.rFrameStart+1) && !g.isStrike(g.rFrameStart+2) {
|
88
|
+
return ErrPinCountExceedsPinsOnTheLane
|
89
|
+
}
|
90
|
+
}
|
91
|
+
} else if !g.isSpare(g.rFrameStart) {
|
92
|
+
// Attempt to make extra roll in last frame without strike or spare.
|
93
|
+
return ErrCannotRollAfterGameOver
|
94
|
+
}
|
95
|
+
// Completed last frame.
|
96
|
+
g.completeTheFrame()
|
97
|
+
}
|
98
|
+
|
99
|
+
return nil
|
100
|
+
}
|
101
|
+
|
102
|
+
// Score returns the score of the game with a potential error.
|
103
|
+
func (g *Game) Score() (int, error) {
|
104
|
+
if g.completedFrames() != framesPerGame {
|
105
|
+
return 0, ErrPrematureScore
|
106
|
+
}
|
107
|
+
|
108
|
+
score := 0
|
109
|
+
frameStart := 0
|
110
|
+
|
111
|
+
for frame := 0; frame < framesPerGame; frame++ {
|
112
|
+
if g.isStrike(frameStart) {
|
113
|
+
score += pinsPerFrame + g.strikeBonus(frameStart)
|
114
|
+
frameStart++
|
115
|
+
} else if g.isSpare(frameStart) {
|
116
|
+
score += pinsPerFrame + g.spareBonus(frameStart)
|
117
|
+
frameStart += maxRollsPerFrame
|
118
|
+
} else {
|
119
|
+
score += g.rawFrameScore(frameStart)
|
120
|
+
frameStart += maxRollsPerFrame
|
121
|
+
}
|
122
|
+
}
|
123
|
+
return score, nil
|
124
|
+
}
|
125
|
+
|
126
|
+
func (g *Game) rollsThisFrame() int { return g.nRolls - g.rFrameStart }
|
127
|
+
func (g *Game) completeTheFrame() { g.nFrames++; g.rFrameStart = g.nRolls }
|
128
|
+
func (g *Game) completedFrames() int { return g.nFrames }
|
129
|
+
func (g *Game) isStrike(f int) bool { return g.rolls[f] == pinsPerFrame }
|
130
|
+
func (g *Game) rawFrameScore(f int) int { return g.rolls[f] + g.rolls[f+1] }
|
131
|
+
func (g *Game) spareBonus(f int) int { return g.rolls[f+2] }
|
132
|
+
func (g *Game) strikeBonus(f int) int { return g.rolls[f+1] + g.rolls[f+2] }
|
133
|
+
func (g *Game) isSpare(f int) bool { return (g.rolls[f] + g.rolls[f+1]) == pinsPerFrame }
|