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

# FerPerales's solution

## to Crypto Square in the Ruby Track

Published at Apr 13 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``````
``````# Crypto
#
class Crypto
def initialize(plaintext)
@plaintext = normalize_text(plaintext)
end

def ciphertext
return '' if @plaintext.empty?

(width, height) = calculate_size
matrix = fill_matrix(height)
output = transpose_matrix(matrix, width)
remove_extra_whitespace(output)
end

private

def fill_matrix(height)
matrix = []
@plaintext.chars.each_slice(height) do |slice|
matrix << slice.fill(' ', slice.length, height - slice.length)
end
matrix
end

def transpose_matrix(matrix, width)
output = []
matrix.transpose.flatten.each_slice(width) do |slice|
output << slice.join
output << ' '
end
output
end

def remove_extra_whitespace(output)
output[0..-2].join
end

def normalize_text(text)
text.gsub(/ |,|\@|\?|\!|\%|\./, '').downcase
end

def calculate_size
length = @plaintext.length
width = Math.sqrt(length).floor
height = Math.sqrt(length).ceil
width += 1 unless width * height >= length

[width, height]
end
end``````