Skip to content

Instantly share code, notes, and snippets.

@Vinai
Created September 22, 2017 09:02
Show Gist options
  • Save Vinai/8294a03975d1f67563b258636bbdbda7 to your computer and use it in GitHub Desktop.
Save Vinai/8294a03975d1f67563b258636bbdbda7 to your computer and use it in GitHub Desktop.
Print diamond kata in Clojure early while I was learning the language.
(ns print-diamond.core)
(defmacro abs
"Return the absolute value of the specified number.
This is a macro only for practice.
A regular function (max value (- value)) would work just as well"
[value]
`(if (pos? ~value) ~value (- ~value)))
(defn size
[letter]
(* 2 (- (int letter) (int \A))))
(defn middle
[letter]
(/ (size letter) 2))
(defn- offset
[letter row]
(let [m (middle letter)]
(- m (abs (- m row)))))
(defn char-for-row
[letter row]
(char (+ (int \A) (offset letter row))))
(defn left
[letter row]
(- (middle letter) (offset letter row)))
(defn right
[letter row]
(- (size letter) (left letter row)))
(defn is-char-at
[letter row col]
(or (= col (left letter row)) (= col (right letter row))))
(defn char-at
[letter row col]
(if (is-char-at letter row col)
(char-for-row letter row)
" "))
(defn print-diamond
[letter]
(let [size (inc (size letter))
cells (for [x (range size), y (range size)] [x y])
chars (map (fn [[row col]] (char-at letter row col)) cells)]
(apply str (interpose "\n" (map #(apply str %1) (partition size chars))))))
(ns print-diamond.core-test
(:require [clojure.test :refer :all]
[print-diamond.core :refer :all]))
(deftest print-diamond-parts
(testing "size"
(is (= 0 (size \A)))
(is (= 2 (size \B)))
(is (= 4 (size \C))))
(testing "middle"
(is (= 0 (middle \A)))
(is (= 1 (middle \B))))
(testing "char-for-row"
(is (= \A (char-for-row \A 0)))
(is (= \A (char-for-row \B 0)))
(is (= \B (char-for-row \B 1)))
(is (= \A (char-for-row \B 2))))
(testing "left"
(is (= 0 (left \A 0)))
(is (= 1 (left \B 0)))
(is (= 0 (left \B 1)))
(is (= 1 (left \B 2))))
(testing "right"
(is (= 0 (right \A 0)))
(is (= 1 (right \B 0)))
(is (= 2 (right \B 1)))
(is (= 1 (right \B 2))))
(testing "is-char-at"
(is (= true (is-char-at \A 0 0)))
(is (= false (is-char-at \A 0 1)))
(is (= false (is-char-at \B 0 0)))
(is (= true (is-char-at \B 0 1))))
(testing "char-at"
(is (= \A (char-at \A 0 0)))
(is (= " " (char-at \B 0 0)))
(is (= \A (char-at \B 0 1)))
(is (= \B (char-at \B 1 0)))))
(deftest print-diamond-test
(testing "A diamond"
(is (= "A" (print-diamond \A)))
(is (= (str " A " "\n"
"B B" "\n"
" A ") (print-diamond \B)))
(is (= (str " A " "\n"
" B B " "\n"
"C C" "\n"
" B B " "\n"
" A ") (print-diamond \C)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment