Repository: exercism/clojure
Pull request #173 (2017-06-18 18:13:24)

Add rotational-cipher puzzle with tests and solution.
Added the rotational-cipher puzzle with tests and solution.

https://github.com/exercism/x-common/blob/master/exercises/rotational-cipher/description.md

yurrriq: Thanks. This looks pretty good, but could you please make the internal definitions private?

It would also be good to put blank lines between the top-level definitions, but I don't feel strongly about that, so it's up to you.

I also wonder if we could make use of `mapcat`.
mwfogleman: I added blank lines, made the internal function private (but not the variables), and added the metadata to the config.json file.

The solution does not include mapcat at this time.
yurrriq: Looks like `config.json` is missing a `,` and causing the Travis build to fail. Could you please add `^:private` to the `def`s too? I'm fine with the current `mapcat`-less implementation.

Patch:
diff --git a/config.json b/config.json
index 27f91f2..f54c631 100644
--- a/config.json
+++ b/config.json
@@ -421,6 +421,13 @@
       "slug": "secret-handshake",
       "topics": [
 
+      ]
+    },
+    {
+      "difficulty": 1,
+      "slug": "rotational-cipher",
+      "topics": [
+
       ]
     }
   ]
diff --git a/exercises/rotational-cipher/project.clj b/exercises/rotational-cipher/project.clj
new file mode 100644
index 0000000..47613ad
--- /dev/null
+++ b/exercises/rotational-cipher/project.clj
@@ -0,0 +1,4 @@
+(defproject rotational-cipher "0.1.0-SNAPSHOT"
+  :description "rotational cipher exercise."
+  :url "https://github.com/exercism/xclojure/tree/master/exercises/rotational-cipher"
+  :dependencies [[org.clojure/clojure "1.8.0"]])
diff --git a/exercises/rotational-cipher/src/example.clj b/exercises/rotational-cipher/src/example.clj
new file mode 100644
index 0000000..d40e1b1
--- /dev/null
+++ b/exercises/rotational-cipher/src/example.clj
@@ -0,0 +1,21 @@
+(ns rotational-cipher)
+
+(def ^:private string (partial apply str))
+
+(def ^:private lower-case "abcdefghijklmnopqrstuvwxyz")
+
+(def ^:private upper-case (->> lower-case (map clojure.string/upper-case) string))
+
+(def ^:private letters (into #{} (concat lower-case upper-case)))
+
+(defn- rotater [shift]
+  (let [encoding (->> (cycle letters)
+                      (drop (* shift 2))
+                      (take 52)
+                      (zipmap letters))]
+    (fn [char] (get encoding char char))))
+
+(defn rotate [message shift]
+  (->> message
+       (map (rotater shift))
+       string))


Test patch:
diff --git a/exercises/rotational-cipher/test/rotational_cipher_test.clj b/exercises/rotational-cipher/test/rotational_cipher_test.clj
new file mode 100644
index 0000000..d711c26
--- /dev/null
+++ b/exercises/rotational-cipher/test/rotational_cipher_test.clj
@@ -0,0 +1,34 @@
+(ns rotational-cipher-test
+  (:require  [clojure.test :refer [deftest is testing]]
+             rotational-cipher))
+
+(deftest rotational-cipher-test
+  (testing "rotate a by 1"
+    (is (= (rotational-cipher/rotate "a" 1) "b")))
+
+  (testing "rotate a by 26, same output as input"
+    (is (= (rotational-cipher/rotate "a" 26) "a")))
+
+  (testing "rotate a by 0, same output as input"
+    (is (= (rotational-cipher/rotate "a" 0) "a")))
+
+  (testing "rotate m by 13"
+    (is (= (rotational-cipher/rotate "m" 13) "z")))
+
+  (testing "rotate n by 13 with wrap around alphabet"
+    (is (= (rotational-cipher/rotate "n" 13) "a")))
+
+  (testing "rotate capital letters"
+    (is (= (rotational-cipher/rotate "OMG" 5) "TRL")))
+
+  (testing "rotate spaces"
+    (is (= (rotational-cipher/rotate "O M G" 5) "T R L")))
+  
+  (testing "rotate numbers"
+    (is (= (rotational-cipher/rotate "Testing 1 2 3 testing" 4) "Xiwxmrk 1 2 3 xiwxmrk")))
+
+  (testing "rotate punctuation"
+    (is (= (rotational-cipher/rotate "Let's eat, Grandma!" 21) "Gzo'n zvo, Bmviyhv!")))
+
+  (testing "rotate all letters"
+    (is (= (rotational-cipher/rotate "The quick brown fox jumps over the lazy dog." 13) "Gur dhvpx oebja sbk whzcf bire gur ynml qbt."))))