Skip to content
This repository has been archived by the owner on May 30, 2023. It is now read-only.

add crypto square exercise #120

Merged
merged 2 commits into from
May 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,16 @@
"difficulty": 5,
"topics": null
},
{
"slug": "crypto-square",
"name": "Crypto Square",
"uuid": "6206d9b0-454e-4cf5-9c8e-dade7485e909",
"practices": [],
"prerequisites": [
"strings"
],
"difficulty": 4
},
{
"slug": "complex-numbers",
"name": "Complex Numbers",
Expand Down
71 changes: 71 additions & 0 deletions exercises/practice/crypto-square/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Instructions

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 down-cased.

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

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

is normalized to:

```text
"ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots"
```

The plaintext should be organized into a rectangle as square as possible.
The size of the rectangle should be decided by the length of the message.

If `c` is the number of columns and `r` is the number of rows, then for the rectangle `r` x `c` find the smallest possible integer `c` such that:

- `r * c >= length of message`,
- and `c >= r`,
- and `c - r <= 1`.

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

```text
"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:

```text
"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.

```text
"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:

```text
"imtgdvs"
"fearwer"
"mayoogo"
"anouuio"
"ntnnlvt"
"wttddes"
"aohghn "
"sseoau "
```
19 changes: 19 additions & 0 deletions exercises/practice/crypto-square/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"ErikSchierboom"
],
"files": {
"solution": [
"src/crypto_square.cljs"
],
"test": [
"test/crypto_square_test.cljs"
],
"example": [
".meta/src/example.cljs"
]
},
"blurb": "Implement the classic method for composing secret messages called a square code.",
"source": "J Dalbey's Programming Practice problems",
"source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html"
}
24 changes: 24 additions & 0 deletions exercises/practice/crypto-square/.meta/src/example.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(ns crypto-square
(:require [clojure.string :as str]))

(defn normalize-plaintext [plaintext]
(str/lower-case (str/replace plaintext #"[^\w]" "")))

(defn square-size [plaintext]
(int (Math/ceil (Math/sqrt (count (normalize-plaintext plaintext))))))

(defn plaintext-segments [plaintext]
(let [normalized-plaintext (normalize-plaintext plaintext)
size (square-size normalized-plaintext)]
(map #(apply str %) (partition size size nil normalized-plaintext))))

(defn- padded-segments [plaintext pad]
(let [segments (plaintext-segments plaintext)
r (count (first segments))]
(map #(concat % (take (- r (count %)) (repeat pad))) segments)))

(defn ciphertext [plaintext]
(apply str (apply mapcat vector (padded-segments plaintext nil))))

(defn normalize-ciphertext [plaintext]
(str/join " " (map #(apply str %) (apply map vector (padded-segments plaintext \ )))))
24 changes: 24 additions & 0 deletions exercises/practice/crypto-square/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This is an auto-generated file. Regular comments will be removed when this
# file is regenerated. Regenerating will not touch any manually added keys,
# so comments can be added in a "comment" key.

[407c3837-9aa7-4111-ab63-ec54b58e8e9f]
description = "empty plaintext results in an empty ciphertext"

[64131d65-6fd9-4f58-bdd8-4a2370fb481d]
description = "Lowercase"

[63a4b0ed-1e3c-41ea-a999-f6f26ba447d6]
description = "Remove spaces"

[1b5348a1-7893-44c1-8197-42d48d18756c]
description = "Remove punctuation"

[8574a1d3-4a08-4cec-a7c7-de93a164f41a]
description = "9 character plaintext results in 3 chunks of 3 characters"

[a65d3fa1-9e09-43f9-bcec-7a672aec3eae]
description = "8 character plaintext results in 3 chunks, the last one with a trailing space"

[fbcb0c6d-4c39-4a31-83f6-c473baa6af80]
description = "54 character plaintext results in 7 chunks, the last two with trailing spaces"
10 changes: 10 additions & 0 deletions exercises/practice/crypto-square/deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{:deps
{org.clojure/clojure {:mvn/version "1.10.1"}
org.clojure/clojurescript {:mvn/version "1.10.773"}}

:aliases
{:test
{:extra-paths ["test"]
:extra-deps
{olical/cljs-test-runner {:mvn/version "3.8.0"}}
:main-opts ["-m" "cljs-test-runner.main"]}}}
21 changes: 21 additions & 0 deletions exercises/practice/crypto-square/src/crypto_square.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
(ns crypto-square)

(defn normalize-plaintext [] ;; <- arglist goes here
;; your code goes here
)

(defn square-size [] ;; <- arglist goes here
;; your code goes here
)

(defn plaintext-segments [] ;; <- arglist goes here
;; your code goes here
)

(defn ciphertext [] ;; <- arglist goes here
;; your code goes here
)

(defn normalize-ciphertext [] ;; <- arglist goes here
;; your code goes here
)
48 changes: 48 additions & 0 deletions exercises/practice/crypto-square/test/crypto_square_test.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
(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 (= "vrel aepe mset paoo irpo"
(crypto-square/normalize-ciphertext "Vampires are people too!"))))
(deftest cipher-4
(is (= "msemo aanin dnin ndla etlt shui "
(crypto-square/normalize-ciphertext "Madness, and then illumination."))))
(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)))))
(deftest cipher-6
(is (= "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau "
(crypto-square/normalize-ciphertext "If man was meant to stay on the ground, god would have given us roots."))))