Skip to content

Instantly share code, notes, and snippets.

@Dirklectisch
Created May 16, 2014 11:23
Show Gist options
  • Save Dirklectisch/4f605a5dfbff2a51257d to your computer and use it in GitHub Desktop.
Save Dirklectisch/4f605a5dfbff2a51257d to your computer and use it in GitHub Desktop.
Bowling Kata in Clojure
(ns bowling.core-test
(:require [clojure.test :refer :all]
[bowling.core :refer :all]))
(deftest spare?-test
(testing "Test spare predicate"
(is (spare? [5 5]))
(is (spare? [0 10]))
(is (not (spare? [2 3])))
(is (not (spare? [10 0]))) ))
(deftest conj-roll-test
(is (= (conj-roll [1] 2) [1 2]))
(is (= (conj-roll [1 2] 3) [1 2 3]))
(is (= (conj-roll [1 2] 10) [1 2 10 nil]))
(is (= (conj-roll [1 2 0] 10) [1 2 0 10]))
(is (= (conj-roll [10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil] 10)
[10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10]))
(is (= (conj-roll [10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10] 10)
[10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 10]))
(is (= (conj-roll [10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 10] 10)
[10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 10 10]) ))
(deftest frameify-test
(is (= (frameify [1 2 3 4]) [[1 2] [3 4]]))
(is (= (frameify [1 2 3 4 5]) [[1 2] [3 4] [5]]))
(is (= (frameify [10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 10 10])
[[10 nil] [10 nil] [10 nil] [10 nil] [10 nil] [10 nil] [10 nil] [10 nil] [10 nil] [10 10 10]])) )
(deftest total-test
(testing "Calculating the total of sample games"
(is (= (total [1 4 4 5]) 14))
(is (= (total [1 4 4 5 6 4]) 24))
(is (= (total [1 4 4 5 6 4 5 5]) 39))
(is (= (total [1 4 4 5 6 4 5 5 10 nil]) 59))
(is (= (total [1 4 4 5 6 4 5 5 10 nil 0 1]) 61))
(is (= (total [1 4 4 5 6 4 5 5 10 nil 0 1 7 3]) 71))
(is (= (total [1 4 4 5 6 4 5 5 10 nil 0 1 7 3 6 4]) 87))
(is (= (total [1 4 4 5 6 4 5 5 10 nil 0 1 7 3 6 4 10 nil]) 107))
(is (= (total [1 4 4 5 6 4 5 5 10 nil 0 1 7 3 6 4 10 nil 2 8 6]) 133))
(is (= (total [10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil 10 nil]) 300)) ))
(ns bowling.core)
(defn spare?
[frame]
(and (not= (first frame) 10)
(= (reduce + frame) 10)))
(defn strike?
[frame]
(= 10 (first frame)))
(defn conj-roll
[game pins]
(let [roll-count (count game)]
(cond
(and (< roll-count 18)
(even? roll-count)
(= 10 pins)) (conj game pins nil)
:else (conj game pins) )))
(defn frameify
"Returns a vector of rolls by frame"
[game]
(if (> (count game) 20)
(conj (vec (partition-all 2 (take 18 game)))
(drop 18 game) )
(vec (partition-all 2 game)) ))
(defn total-frame
"Takes a vector of frames and returns the total score for the head frame"
[frames]
(let [tail-frame? (= 1 (count frames))
pin-count (reduce + (remove nil? (first frames)))
next-rolls (remove nil? (flatten (rest frames)))]
(cond
tail-frame? pin-count
(strike? (first frames)) (+ pin-count (reduce + (take 2 next-rolls)))
(spare? (first frames)) (+ pin-count (first next-rolls))
:else pin-count )))
(defn total
"Takes a game and returns the total score for the game"
([game] (total (frameify game) 0))
([frames acc] (if (empty? frames)
acc
(total (rest frames) (+ acc (total-frame frames)) ))))
; Optional mutable state to adhere to the function signatures of the original kata
(def thegame (atom []))
(defn roll
"Registers a roll in the global game state"
[pins]
(swap! thegame conj-roll pins))
(defn score
"Calculates the current total score from the global game state"
[]
(total @thegame))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment