[CodeKata][Scala] Bowling Game - Pajace/CodeKata GitHub Wiki
Production code
/**
* Created by Pajace on 2016/6/11.
*/
class BowlingGame {
var rolls = List[Int]()
def roll(pins: Int) = {
rolls = rolls :+ pins
}
def score() = {
var totalScore = 0
var frameIndex = 0
def increaseFrameIndex(bonusType: BonusType.Value) = bonusType match {
case BonusType.Strike => frameIndex = frameIndex + 1
case _ => frameIndex = frameIndex + 2
}
for (frame <- 1 to 10) {
val twoRollScore = (rolls(frameIndex), rolls(frameIndex + 1))
val result = calculateFrameScore(twoRollScore, frameIndex)
increaseFrameIndex(result._2)
totalScore = totalScore + result._1
}
totalScore
}
private def calculateFrameScore(score: (Int, Int), frameIndex: Int) = (isStrike(score), isSpare(score)) match {
case (true, false) =>
val result = score._1 + rolls(frameIndex + 1) + rolls(frameIndex + 2)
(result, BonusType.Strike)
case (false, true) =>
val result = score.sum + rolls(frameIndex + 2)
(result, BonusType.Spare)
case _ =>
(score.sum, BonusType.None)
}
private def isSpare(score: (Int, Int)) = score.sum == 10
private def isStrike(score: (Int, Int)) = score._1 == 10
implicit class ImproveTuple(value: (Int, Int)) {
def sum = value._1 + value._2
}
object BonusType extends Enumeration {
val Strike, Spare, None = Value
}
}
Test Case
import org.scalatest.{BeforeAndAfterEach, FlatSpec, Matchers}
/**
* Created by Pajace on 2016/6/11.
*/
class BowlingGameTest extends FlatSpec with Matchers with BeforeAndAfterEach {
var game : BowlingGame = _
override protected def beforeEach(): Unit = {
game = new BowlingGame
}
private def rollMany(n:Int, pins:Int) = (1 to n).foreach(rolls=> game.roll(pins))
"BowlingGame" should "be create by new" in {
game.isInstanceOf[BowlingGame] should be (true)
}
"Score" should "be 0, if all frames are knocked 0 pin" in {
rollMany(20, 0)
game.score should be (0)
}
it should "be 20, if all knocked 1 pins for every rolls in every frames" in {
rollMany(20, 1)
game.score should be (20)
}
"One spare" should "get bonus by next frame's first roll's pins" in {
rollSpare(5)
game.roll(3)
rollMany(17, 0)
game.score should be (16)
}
"One strike" should "get bouns by next frame's score" in {
rollStrike()
game.roll(3)
game.roll(4)
rollMany(16, 0)
game.score() should be (24)
}
"PerfectGame" should "get 300 as score" in {
rollMany(12, 10)
game.score() should be (300)
}
private def rollStrike(): Unit = {
game.roll(10)
}
private def rollSpare(firstRoll:Int): Unit = {
game.roll(firstRoll)
game.roll(10-firstRoll)
}
}