🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉 # SergiiVlasiuk's solution

## to Crypto Square in the Scala Track

Published at Aug 25 2019 · 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. Phrases that fill perfect rectangles `(r X c)` should be output `c` chunks of `r` length, separated by spaces. Phrases that do not fill perfect rectangles will have `n` empty spaces. Those spaces should be distributed evenly, added to the end of the last `n` chunks.

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

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

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

The Scala exercises assume an SBT project scheme. The exercise solution source should be placed within the exercise directory/src/main/scala. The exercise unit tests can be found within the exercise directory/src/test/scala.

To run the tests simply run the command `sbt test` in the exercise directory.

For more detailed info about the Scala track see the help page.

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

### CryptoSquareTest.scala

``````import org.scalatest.{Matchers, FunSuite}

/** @version 3.2.0 */
class CryptoSquareTest extends FunSuite with Matchers {

test("empty plaintext results in an empty ciphertext") {
CryptoSquare.ciphertext("") should be("")
}

test("Lowercase") {
pending
CryptoSquare.ciphertext("A") should be("a")
}

test("Remove spaces") {
pending
CryptoSquare.ciphertext("  b ") should be("b")
}

test("Remove punctuation") {
pending
CryptoSquare.ciphertext("@1,%!") should be("1")
}

test("9 character plaintext results in 3 chunks of 3 characters") {
pending
CryptoSquare.ciphertext("This is fun!") should be("tsf hiu isn")
}

test(
"8 character plaintext results in 3 chunks, the last one with a trailing space") {
pending
CryptoSquare.ciphertext("Chill out.") should be("clu hlt io ")
}

test(
"54 character plaintext results in 7 chunks, the last two with trailing spaces") {
pending
CryptoSquare.ciphertext(
"If man was meant to stay on the ground, god would have given us roots.") should be(
"imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn  sseoau ")
}
}``````
``````object CryptoSquare {
private def normalize(message: String): String = message.toLowerCase.replaceAll("[\\W]|_", "")

private def numberRows(msgLength: Int): Int = Math.sqrt(msgLength).toInt

def ciphertext(message: String): String = {
if (message.isEmpty) ""
else {
val normalized = normalize(message)
val numRows = numberRows(normalized.length)
val numCols = if ((numRows * numRows) % normalized.length > 0) numRows + 1 else numRows
val chunks: List[String] = normalized.sliding(numCols, numCols).toList.map(f => f.padTo(numCols, " ").mkString)
(0 until numCols).map(idx => chunks.map(_ (idx))).toList.map(_.mkString).mkString(" ")
}
}
}``````