diff --git a/config.json b/config.json index fd59f0f..3a9b296 100644 --- a/config.json +++ b/config.json @@ -594,6 +594,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "crypto-square", + "name": "Crypto Square", + "uuid": "7e4ad5c7-fe53-4f7b-ac20-8f4c03799194", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "flower-field", "name": "Flower Field", diff --git a/exercises/practice/crypto-square/.busted b/exercises/practice/crypto-square/.busted new file mode 100644 index 0000000..86b84e7 --- /dev/null +++ b/exercises/practice/crypto-square/.busted @@ -0,0 +1,5 @@ +return { + default = { + ROOT = { '.' } + } +} diff --git a/exercises/practice/crypto-square/.docs/instructions.md b/exercises/practice/crypto-square/.docs/instructions.md new file mode 100644 index 0000000..6c3826e --- /dev/null +++ b/exercises/practice/crypto-square/.docs/instructions.md @@ -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 " +``` diff --git a/exercises/practice/crypto-square/.meta/config.json b/exercises/practice/crypto-square/.meta/config.json new file mode 100644 index 0000000..7728d52 --- /dev/null +++ b/exercises/practice/crypto-square/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "glennj" + ], + "files": { + "solution": [ + "crypto_square.moon" + ], + "test": [ + "crypto_square_spec.moon" + ], + "example": [ + ".meta/example.moon" + ] + }, + "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" +} diff --git a/exercises/practice/crypto-square/.meta/example.moon b/exercises/practice/crypto-square/.meta/example.moon new file mode 100644 index 0000000..dad6749 --- /dev/null +++ b/exercises/practice/crypto-square/.meta/example.moon @@ -0,0 +1,21 @@ +pad = (str, width) -> string.format "%-#{width}s", str + +join = table.concat + +encode = (text) -> + clean = text\gsub('[^%a%d]', '')\lower! + return '' if clean == '' + len = math.ceil math.sqrt #clean + + segments = {} + for i = 1, #clean, len + table.insert segments, clean\sub(i, i + len - 1) + + -- pad the last segment + segments[#segments] = pad segments[#segments], len + + transposed = [join [s\sub(i,i) for s in *segments] for i = 1, len] + join transposed, " " + + +{ :encode } diff --git a/exercises/practice/crypto-square/.meta/spec_generator.moon b/exercises/practice/crypto-square/.meta/spec_generator.moon new file mode 100644 index 0000000..19216ef --- /dev/null +++ b/exercises/practice/crypto-square/.meta/spec_generator.moon @@ -0,0 +1,11 @@ +{ + module_imports: {'encode'}, + + generate_test: (case, level) -> + lines = { + "result = encode #{quote case.input.plaintext}", + "expected = #{quote case.expected}", + "assert.are.equal expected, result" + } + table.concat [indent line, level for line in *lines], '\n' +} diff --git a/exercises/practice/crypto-square/.meta/tests.toml b/exercises/practice/crypto-square/.meta/tests.toml new file mode 100644 index 0000000..94ef081 --- /dev/null +++ b/exercises/practice/crypto-square/.meta/tests.toml @@ -0,0 +1,39 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[407c3837-9aa7-4111-ab63-ec54b58e8e9f] +description = "empty plaintext results in an empty ciphertext" + +[aad04a25-b8bb-4304-888b-581bea8e0040] +description = "normalization results in empty plaintext" + +[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" +include = false + +[33fd914e-fa44-445b-8f38-ff8fbc9fe6e6] +description = "54 character plaintext results in 8 chunks, the last two with trailing spaces" +reimplements = "fbcb0c6d-4c39-4a31-83f6-c473baa6af80" diff --git a/exercises/practice/crypto-square/crypto_square.moon b/exercises/practice/crypto-square/crypto_square.moon new file mode 100644 index 0000000..f61d541 --- /dev/null +++ b/exercises/practice/crypto-square/crypto_square.moon @@ -0,0 +1,4 @@ +{ + encode: (plaintext) -> + error 'Implement me' +} diff --git a/exercises/practice/crypto-square/crypto_square_spec.moon b/exercises/practice/crypto-square/crypto_square_spec.moon new file mode 100644 index 0000000..91fd5fb --- /dev/null +++ b/exercises/practice/crypto-square/crypto_square_spec.moon @@ -0,0 +1,42 @@ +import encode from require 'crypto_square' + +describe 'crypto-square', -> + it 'empty plaintext results in an empty ciphertext', -> + result = encode '' + expected = '' + assert.are.equal expected, result + + pending 'normalization results in empty plaintext', -> + result = encode '... --- ...' + expected = '' + assert.are.equal expected, result + + pending 'Lowercase', -> + result = encode 'A' + expected = 'a' + assert.are.equal expected, result + + pending 'Remove spaces', -> + result = encode ' b ' + expected = 'b' + assert.are.equal expected, result + + pending 'Remove punctuation', -> + result = encode '@1,%!' + expected = '1' + assert.are.equal expected, result + + pending '9 character plaintext results in 3 chunks of 3 characters', -> + result = encode 'This is fun!' + expected = 'tsf hiu isn' + assert.are.equal expected, result + + pending '8 character plaintext results in 3 chunks, the last one with a trailing space', -> + result = encode 'Chill out.' + expected = 'clu hlt io ' + assert.are.equal expected, result + + pending '54 character plaintext results in 8 chunks, the last two with trailing spaces', -> + result = encode 'If man was meant to stay on the ground, god would have given us roots.' + expected = 'imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau ' + assert.are.equal expected, result