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

# Abgasgeruch's solution

## to Crypto Square in the Ruby Track

Published at Feb 11 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 "
``````

For installation and learning resources, refer to the Ruby resources page.

For running the tests provided, you will need the Minitest gem. Open a terminal window and run the following command to install minitest:

``````gem install minitest
``````

If you would like color output, you can `require 'minitest/pride'` in the test file, or note the alternative instruction, below, for running the test file.

Run the tests from the exercise directory using the following command:

``````ruby crypto_square_test.rb
``````

To include color from the command line:

``````ruby -r minitest/pride crypto_square_test.rb
``````

## 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.rb

``````require 'minitest/autorun'
require_relative 'crypto_square'

# Common test data version: 3.2.0 e00dfb3
class CryptoSquareTest < Minitest::Test
def test_empty_plaintext_results_in_an_empty_ciphertext
# skip
plaintext = ''
assert_equal "", Crypto.new(plaintext).ciphertext
end

def test_lowercase
skip
plaintext = 'A'
assert_equal "a", Crypto.new(plaintext).ciphertext
end

def test_remove_spaces
skip
plaintext = '  b '
assert_equal "b", Crypto.new(plaintext).ciphertext
end

def test_remove_punctuation
skip
plaintext = '@1,%!'
assert_equal "1", Crypto.new(plaintext).ciphertext
end

def test_9_character_plaintext_results_in_3_chunks_of_3_characters
skip
plaintext = 'This is fun!'
assert_equal "tsf hiu isn", Crypto.new(plaintext).ciphertext
end

def test_8_character_plaintext_results_in_3_chunks_the_last_one_with_a_trailing_space
skip
plaintext = 'Chill out.'
assert_equal "clu hlt io ", Crypto.new(plaintext).ciphertext
end

def test_54_character_plaintext_results_in_7_chunks_the_last_two_with_trailing_spaces
skip
plaintext = 'If man was meant to stay on the ground, god would have given us roots.'
assert_equal "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn  sseoau ", Crypto.new(plaintext).ciphertext
end
end``````
``````class String

def normalize
self.scan(/\w/).join.downcase
end

end

class Crypto

def initialize(text)
@text = text
end

def ciphertext
text = @text.normalize

return "" if text.length < 1

len = text.length
c = Math.sqrt(len).ceil
r = (len / c.to_f).ceil

rows = []
(0...r).each do |row|
rows << text.slice(row * c, c).ljust(c)
end

cols = Array.new(c, "")
rows.each do |row|
row.each_char.with_index do |char, index|
cols[index] += char
end
end
cols.join(" ")
end

end``````