Skip to content

Instantly share code, notes, and snippets.

@PurpleBooth
Last active September 30, 2019 06:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PurpleBooth/c993e9198c6526493b4844cc098eb22c to your computer and use it in GitHub Desktop.
Save PurpleBooth/c993e9198c6526493b4844cc098eb22c to your computer and use it in GitHub Desktop.
The Bowling Kata in Nim Lang!

Rules

Create a class with 2 methods:

  • roll(self, pins)
  • score(self)

The rules for scoring are as follows

  • A game is 10 frames
  • Each frame can have up to 2 rolls
  • A spare is when you knock down all pins in a frame
  • A strike is when you knock down all pins in the first roll of a frame
  • The score for a frame is the number of pins knocked down
  • If a spare is scored, the next roll is added as a bonus
  • If a strike is scored, the next 2 rolls are added as a bonus
  • A perfect game is 12 successive strikes and score 300 points
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
#!/usr/bin/env bash
set -euo pipefail
nim compile -x --run "bowling.nim"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment