Created
May 16, 2014 11:23
-
-
Save Dirklectisch/4f605a5dfbff2a51257d to your computer and use it in GitHub Desktop.
Bowling Kata in Clojure
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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)) )) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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