# Thomas Skardal

Hello, computer.

## Long time, no see. Here's some Clojure!

June 22, 2015

Recently I got inspired by this blog post (it’s in norwegian, but I’m sure you can find a way to translate it) which solves the bowling kata in Haskell. The goal is to implement a function that gives you a score for a series of rolls in a bowling game.

This blog post mentions other posts as well, and all of the solutions are worth a read.

So, back to me. I wanted to give it a try in Clojure, and here’s the result!

``````(ns kata-bowling.bowling)

(defn- last-frame? [x y z]
(some nil? [x y z]))

(defn- spare? [x y]
(= (+ x y) 10))

(defn- strike? [x]
(= x 10))

(defn score [[x y z & rolls]]
(cond
(last-frame? x y z) (+ (take-while some? [x y z]))
(spare? x y) (+ 10 z (score (cons z rolls)))
(strike? x) (+ 10 y z (if (empty? rolls) 0 (score (concat [y z] rolls))))
:else (+ x y (score (cons z rolls)))))
``````

I’ve implemented this as a recursive function. Not tail recursive, just plain old recursive. I use `cond` to “match” the different kinds of throws. I’m sure I could make the code shorter and more consice by using something like [core.check](), but I wanted to use vanilla Clojure. If that’s a thing.

What I like about this solution is that it’s quite clear how a strike is better than a spare and how this again is better than a regular frame. I don’t like is how I have to `cons` and `concat` the following rolls back into the collection before recursing.

Any feedback is most welcome!

Finally, here are the tests I wrote to feel confident that the solution is correct.

``````(ns kata-bowling.bowling-test
(:require [clojure.test :refer :all]
[kata-bowling.bowling :refer :all]))

(deftest bowling
(testing "everything in the gutter"
(is (= 0 (score (repeat 20 0)))))
(testing "one single pin"
(is (= 1 (score (cons 1 (repeat 19 0))))))
(testing "a spare gives ten plus the number of pins in next throw"
(is (= (+ 10 5 5) (score [5 5 5]))))
(testing "a strike gives ten plus the number of pins in the two next throws"
(is (= (+ 10 3 1 2 5) (score [10 1 2 5]))))
(testing "no spares or strikes"
(is (= 90 (score (take 20 (interpose 0 (repeat 9)))))))
(testing "all spares"
(is (= 150 (score (repeat 21 5)))))
(testing "a perfect game"
(is (= 300 (score (repeat 12 10))))))
``````

(also available as a gist)