ðŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io ðŸŽ‰

# Pete's solution

## to Crypto Square in the Clojure Track

Published at May 02 2020 · 0 comments
Instructions
Test suite
Solution

Implement the classic method for composing secret messages called a square code.

Given an English text, output the encoded version of that text.

First, the input is normalized: the spaces and punctuation are removed from the English text and the message is downcased.

Then, the normalized characters are broken into rows. These rows can be regarded as forming a rectangle when printed with intervening newlines.

For example, the sentence

``````"If man was meant to stay on the ground, god would have given us roots."
``````

is normalized to:

``````"ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots"
``````

The plaintext should be organized in to a rectangle. The size of the rectangle (`r x c`) should be decided by the length of the message, such that `c >= r` and `c - r <= 1`, where `c` is the number of columns and `r` is the number of rows.

Our normalized text is 54 characters long, dictating a rectangle with `c = 8` and `r = 7`:

``````"ifmanwas"
"meanttos"
"tayonthe"
"groundgo"
"dwouldha"
"vegivenu"
"sroots  "
``````

The coded message is obtained by reading down the columns going left to right.

The message above is coded as:

``````"imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau"
``````

Output the encoded text in chunks that fill perfect rectangles `(r X c)`, with `c` chunks of `r` length, separated by spaces. For phrases that are `n` characters short of the perfect rectangle, pad each of the last `n` chunks with a single trailing space.

``````"imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn  sseoau "
``````

Notice that were we to stack these, we could visually decode the ciphertext back in to the original message:

``````"imtgdvs"
"fearwer"
"mayoogo"
"anouuio"
"ntnnlvt"
"wttddes"
"aohghn "
"sseoau "
``````

## Source

J Dalbey's Programming Practice problems http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html

## Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

### crypto_square_test.clj

``````(ns crypto-square-test
(:require [clojure.test :refer [deftest is]]
crypto-square))

(deftest normalize-splunk
(is (= "splunk" (crypto-square/normalize-plaintext "s#!@\$%plunk"))))
(deftest normalize-with-punctuation
(is (= "123go" (crypto-square/normalize-plaintext "1, 2, 3 GO!"))))

(deftest square-2
(is (= 2 (crypto-square/square-size "1234"))))
(deftest square-3
(is (= 3 (crypto-square/square-size "123456789"))))
(deftest square-4
(is (= 4 (crypto-square/square-size "123456789abc"))))

(deftest segments
(is (= ["neverv", "exthin", "eheart", "withid", "lewoes"]
(crypto-square/plaintext-segments "Never vex thine heart with idle woes."))))
(deftest segments-2
(is (= ["zomg", "zomb", "ies"]
(crypto-square/plaintext-segments "ZOMG! ZOMBIES!!!"))))

(deftest cipher-1
(is (= "tasneyinicdsmiohooelntuillibsuuml"
(crypto-square/ciphertext "Time is an illusion. Lunchtime doubly so."))))
(deftest cipher-2
(is (= "wneiaweoreneawssciliprerlneoidktcms"
(crypto-square/ciphertext "We all know interspecies romance is weird."))))
(deftest cipher-3
(is (= "msemo aanin dnin ndla etlt shui"
(deftest cipher-4
(is (= "vrel aepe mset paoo irpo"
(crypto-square/normalize-ciphertext "Vampires are people too!"))))
(deftest cipher-5
(is (= (str "ageihdsednsh lsagtoonaepe lannswnccair hrditeaetnrh "
"ueethdnatoio mbqyewdnotto aouayicdwhod nranatosaef "
"bnldrhnhrrb efirersodir irnieecusno nedgnailoat")
(let [plaintext (str "All human beings are born free "
"and equal in dignity and rights. "
"They are endowed with reason and conscience "
"and should act towards one another "
"in a spirit of brotherhood.")]
(crypto-square/normalize-ciphertext plaintext)))))``````
``````(ns crypto-square
(:require [clojure.string :as str]
[clojure.math.numeric-tower :as maths]))

(defn normalize-plaintext
"Downcase a string and filter out non-alphanumerics"
[s]
{:pre [(string? s)]}
(->> (str/lower-case s)
(re-seq #"[a-z0-9]*")
(apply str)))

(defn square-size
"get the longer side length of a rectangle as nearly square the will contain
the characters of a string"
[s]
{:pre [(string? s)]}
(-> s
(count)
(maths/sqrt)
(maths/ceil)
(int)))

(defn- segmentify [s]
(let [string (normalize-plaintext s)
sq-size (square-size string)]
(partition sq-size sq-size (repeat nil) string)))

(defn plaintext-segments
"Normalize a string and split into chunks"
[s]
{:pre [(string? s)]}
(->> s
(segmentify)
(map #(apply str %))))

(defn- transpose
"transpose a matrix"
[m]
(apply mapv vector m))

(defn normalize-ciphertext
"Crypto-square encode a string and return it in chunks that fill perfect rectangles"
[s]
{:pre [(string? s)]}
(->> s
(segmentify)
(transpose)
(map #(apply str %))
(str/join " ")))

(defn ciphertext
"Encode a string using the crypto-square code"
[s]
{:pre [(string? s)]}
(->> s
(normalize-ciphertext)
(filter #(not= \space %))
(apply str)))``````