|
import sequtils |
|
from sequtils import concat |
|
|
|
const |
|
totalPins = 10 |
|
totalFrames = 10 |
|
startFrameScore = 0 |
|
startGameScore = 0 |
|
startRollIndex = 0 |
|
rollsInStrikeFrame = 1 |
|
rollsInSpareFrame = 2 |
|
rollsInStandardFrame = 2 |
|
frameFirstRollOffset = 0 |
|
frameSecondRollOffset = 1 |
|
spareBonusRollOffset = 2 |
|
strikeFirstBonusRollOffset = 1 |
|
strikeSecondBonusRollOffset = 1 |
|
|
|
type |
|
BowlingGame = object |
|
rolls: seq[int] |
|
|
|
proc initBowlingGame*(startingRolls: seq[int] = @[]): BowlingGame = |
|
BowlingGame(rolls: startingRolls) |
|
|
|
proc roll*(b: BowlingGame, pins: int): auto = |
|
BowlingGame(rolls: concat(b.rolls, @[pins])) |
|
|
|
proc isStrike(rolls: seq[int], rollIndex: int): auto = |
|
rolls[rollIndex + frameFirstRollOffset] == totalPins |
|
|
|
proc frameStrikeScore(rolls: seq[int], rollIndex: int): auto = |
|
var frameScore = startFrameScore |
|
frameScore += rolls[rollIndex + frameFirstRollOffset] |
|
frameScore += rolls[rollIndex + strikeFirstBonusRollOffset] |
|
frameScore += rolls[rollIndex + strikeSecondBonusRollOffset] |
|
frameScore |
|
|
|
proc isSpare(rolls: seq[int], rollIndex: int): auto = |
|
var frameScore = rolls[rollIndex + frameFirstRollOffset] |
|
frameScore += rolls[rollIndex + frameSecondRollOffset] |
|
frameScore == totalPins |
|
|
|
proc frameSpareScore(rolls: seq[int], rollIndex: int): auto = |
|
var frameScore = startFrameScore |
|
frameScore += rolls[rollIndex + frameFirstRollOffset] |
|
frameScore += rolls[rollIndex + frameSecondRollOffset] |
|
frameScore += rolls[rollIndex + spareBonusRollOffset] |
|
frameScore |
|
|
|
proc frameStandardScore(rolls: seq[int], rollIndex: int): auto = |
|
var frameScore = startFrameScore |
|
frameScore += rolls[rollIndex + frameFirstRollOffset] |
|
frameScore += rolls[rollIndex + frameSecondRollOffset] |
|
frameScore |
|
|
|
proc score*(b: BowlingGame): auto = |
|
var |
|
gameScore = startGameScore |
|
rollIndex = startRollIndex |
|
|
|
for n in .. totalFrames: |
|
if isStrike(b.rolls, rollIndex): |
|
gameScore += frameStrikeScore(b.rolls, rollIndex) |
|
rollIndex += rollsInStrikeFrame |
|
elif isSpare(b.rolls, rollIndex): |
|
gameScore += frameSpareScore(b.rolls, rollIndex) |
|
rollIndex += rollsInSpareFrame |
|
else: |
|
gameScore += frameStandardScore(b.rolls, rollIndex) |
|
rollIndex += rollsInStandardFrame |
|
|
|
gameScore |
|
|
|
when isMainModule: |
|
import unittest |
|
|
|
suite "test bowling kata": |
|
setup: |
|
var bowlingGame = initBowlingGame() |
|
|
|
test "gutter ball game is 0": |
|
# Roll frame 1 to 10 |
|
for n in 1 .. 20: |
|
bowlingGame = bowlingGame.roll(0) |
|
|
|
check: |
|
bowlingGame.score() == 0 |
|
|
|
test "rolls are summed for none bonus scores": |
|
# Roll frame 1 to 5 |
|
for n in 1 .. 10: |
|
bowlingGame = bowlingGame.roll(3) |
|
|
|
# Roll frame 6 to 10 |
|
for n in 1 .. 10: |
|
bowlingGame = bowlingGame.roll(4) |
|
|
|
check: |
|
bowlingGame.score() == 70 |
|
|
|
test "spares give a bonus of the next roll": |
|
# Roll frame 1 |
|
bowlingGame = bowlingGame.roll(3) |
|
bowlingGame = bowlingGame.roll(7) |
|
|
|
# Roll frame 2 |
|
bowlingGame = bowlingGame.roll(1) |
|
bowlingGame = bowlingGame.roll(2) |
|
|
|
# Roll frame 3 to 10 |
|
for n in 1 .. 16: |
|
bowlingGame = bowlingGame.roll(0) |
|
|
|
check: |
|
bowlingGame.score == 14 |
|
|
|
test "spare gives you an extra roll on the last roll": |
|
# Roll frame 1 to 9 |
|
for n in 1 .. 18: |
|
bowlingGame = bowlingGame.roll(0) |
|
|
|
# Roll frame 10 |
|
bowlingGame = bowlingGame.roll(3) |
|
bowlingGame = bowlingGame.roll(7) |
|
bowlingGame = bowlingGame.roll(1) |
|
|
|
check: |
|
bowlingGame.score == 11 |
|
|
|
test "strikes give a bonus of the next two rolls": |
|
# Roll frame 1 |
|
bowlingGame = bowlingGame.roll(10) |
|
|
|
# Roll frame 2 |
|
bowlingGame = bowlingGame.roll(1) |
|
bowlingGame = bowlingGame.roll(2) |
|
|
|
# Roll frame 3 |
|
bowlingGame = bowlingGame.roll(3) |
|
bowlingGame = bowlingGame.roll(0) |
|
|
|
# Roll frame 4 to 10 |
|
for n in 1 .. 14: |
|
bowlingGame = bowlingGame.roll(0) |
|
|
|
check: |
|
bowlingGame.score == 19 |
|
|
|
|
|
test "strike gives you an extra two rolls on the last roll": |
|
# Roll frame 1 to 9 |
|
for n in 1 .. 18: |
|
bowlingGame = bowlingGame.roll(0) |
|
|
|
# Roll frame 10 |
|
bowlingGame = bowlingGame.roll(10) |
|
bowlingGame = bowlingGame.roll(2) |
|
bowlingGame = bowlingGame.roll(3) |
|
|
|
check: |
|
bowlingGame.score == 15 |
|
|
|
test "a perfect game is 300": |
|
# Roll frame 1 to 10 |
|
for n in 1 .. 12: |
|
bowlingGame = bowlingGame.roll(10) |
|
|
|
check: |
|
bowlingGame.score == 300 |