The Bowling Game Kata in Scala
Here is the end result of my implementation of the Bowling Game Kata in Scala. You can see all steps including the tests on CodersDojo.org.
[sourcecode language=”scala” wraplines=”false”]
class BowlingGame {
var rolls: List[Int] = List()
def roll(pins: Int): Unit = {
rolls = rolls :+ pins
}
def score: Int = {
scoreRecursive(0, 1, rolls)
}
def scoreRecursive(currentScore: Int, frame: Int, rolls: List[Int]): Int = {
frame match {
case 11 => currentScore
case f => rolls match {
case 10 :: rollsTail // strike
=> scoreRecursive(currentScore + (rolls take (3) sum), f + 1, rollsTail)
case first :: second :: rollsTail if (first + second == 10) // spare
=> scoreRecursive(currentScore + (rolls take (3) sum), f + 1, rollsTail)
case first :: second :: rollsTail // normal
=> scoreRecursive(currentScore + (rolls take (2) sum), f + 1, rollsTail)
case _ // incomplete game
=> throw new Exception(“Only complete games can be scored.”)
}
}
}
}
[/sourcecode]
Comparing this piece of code with the Java implementation from Uncle Bob (who, no doubt, knows how to write clean Java code) I would conclude that it is more expressive and concise. The pattern matching is a) shorter and b) makes the algorighm stand out more clearly. I do, however, appreciate that this might have to do with personal taste. But, what this implemenation with pattern matching does make trivial is to also score partial games. It just requires two more lines of code that seem almost obvious.
[sourcecode language=”scala” wraplines=”false” highlight=”23,24,25,26"]
class BowlingGame {
var rolls: List[Int] = List()
def roll(pins: Int): Unit = {
rolls = rolls :+ pins
}
def score: Int = {
scoreRecursive(0, 1, rolls)
}
def scoreRecursive(currentScore: Int, frame: Int, rolls: List[Int]): Int = {
frame match {
case 11 => currentScore
case f => rolls match {
case 10 :: rollsTail // strike
=> scoreRecursive(currentScore + (rolls take (3) sum), f + 1, rollsTail)
case first :: second :: rollsTail if (first + second == 10) // spare
=> scoreRecursive(currentScore + (rolls take (3) sum), f + 1, rollsTail)
case first :: second :: rollsTail // normal
=> scoreRecursive(currentScore + (rolls take (2) sum), f + 1, rollsTail)
case last :: rollsTail // partial frame
=> currentScore + last
case nil // partial game
=> currentScore
}
}
}
}
[/sourcecode]
As I described in my previous post (link), the variable rolls might indicate that the above code could be made more functional by replacing it with some other construct like list comprehension or recursion. However, thinking about it, it sort of makes sense since the rolls are indeed what changes as a game progresses. I couldn’t come up with a more functional implementation that is not less expressive. Can you?