My first Clojure code was the Bowling Kata I wrote about in my last post. Today I did the FizzBuzz Kata and the stage 2 requirements. This was a lot simpler than the Bowling Kata.
There is not much to say about it, here is my test code:
(ns fizzbuzztest (:use fizzbuzz clojure.test)) (deftest nonefizzbuzz-numbers-return-itself (is (= (fizzbuzz '(1 2 4 7)) '(1 2 4 7)))) (deftest multiple-of-three-and-not-five-return-fizz (is (= (fizzbuzz '(3 6 9 12 18 21 24 27)) (take 8 (repeat "fizz")) ))) (deftest multiple-of-five-and-not-three-return-buzz (is (= (fizzbuzz '(5 10 20 25 40 50 55 65)) (take 8 (repeat "buzz")) ))) (deftest multiple-of-three-and-five-return-fizzbuzz (is (= (fizzbuzz '(15 30 45 60 75 90 105 120)) (take 8 (repeat "fizzbuzz")) ))) (deftest three-in-number-returns-fizz (is (= (fizzbuzz '(3 13 23 31 103)) (repeat 5 "fizz")))) (deftest five-in-number-returns-buzz (is (= (fizzbuzz '(5 52 58 151 502)) (repeat 5 "buzz")))) (run-tests)
and here is the implementation:
(ns fizzbuzz) (defn- numeric-fizz? [n] (= (rem n 3) 0)) (defn- string-fizz? [n] (some #(= % \3) (str n))) (defn- fizz? [n] (or (numeric-fizz? n) (string-fizz? n))) (defn- numeric-buzz? [n] (= (rem n 5) 0)) (defn- string-buzz? [n] (some #(= % \5) (str n))) (defn- buzz? [n] (or (numeric-buzz? n) (string-buzz? n))) (defn- fizzbuzz? [n] (and (fizz? n) (buzz? n))) (defn- replace-fizz-buzz [n] (cond (fizzbuzz? n) "fizzbuzz" (fizz? n) "fizz" (buzz? n) "buzz" (number? n) n)) (defn fizzbuzz [numbers] (map replace-fizz-buzz numbers))
I like the function that checks if a number contains a ‘3’ character. Although it looks weird it is not so hard to read after getting a little used to Clojure code.
(defn- string-fizz? [n] (some #(= % \3) (str n)))
This functions gets a number n as parameter, which is converted to a string with (str n). The some calls the anonymous function #(= % \3) on each element (i.e. character) of n as string. If the anonymous function returns true, some return true as well. The anonymous function simply checks if its parameter (the %) is the character 3.
There is one issue with the cond in replace-fizz-buzz:the last condition (number? n) is just a dummy condition. Actually I don’t want it. If none of the other conditions match, it should just return the n. But that is not possible with cond. I’m looking for a better solution…
I also created my first Leiningen build script to run the tests. Leiningen is a build tool for Clojure. Here is the build script (named project.clj and placed in the project root folder):
(defproject fizzbuzz "1.0.0" :description "A cloure implmementation of the FizzBuzz kata." :dependencies [[org.clojure/clojure "1.1.0"]])
Quite simple ;-)
Running the following command:
$ lein test fizzbuzztest
prints:
[null] Testing fizzbuzztest [null] Ran 6 tests containing 6 assertions. [null] 0 failures, 0 errors. [null] -------------------- [null] Total: [null] Ran 6 tests containing 6 assertions. [null] 0 failures, 0 errors.
Works, but I have no idea, why it prints the [null] stuff.