# artemkorsakov's solution

## to Crypto Square in the C# Track

Published at May 03 2019 · 0 comments
Instructions
Test suite
Solution

#### Note:

This exercise has changed since this solution was written.

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

## Running the tests

To run the tests, run the command `dotnet test` from within the exercise directory.

Initially, only the first test will be enabled. This is to encourage you to solve the exercise one step at a time. Once you get the first test passing, remove the `Skip` property from the next test and work on getting that test passing. Once none of the tests are skipped and they are all passing, you can submit your solution using `exercism submit CryptoSquare.cs`

## Further information

For more detailed information about the C# track, including how to get help if you're having trouble, please visit the exercism.io C# language page.

## Source

J Dalbey's Programming Practice problems http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html

### CryptoSquareTest.cs

``````// This file was auto-generated based on version 3.2.0 of the canonical data.

using Xunit;

public class CryptoSquareTest
{
[Fact]
public void Empty_plaintext_results_in_an_empty_ciphertext()
{
var plaintext = "";
var expected = "";
Assert.Equal(expected, CryptoSquare.Ciphertext(plaintext));
}

[Fact(Skip = "Remove to run test")]
public void Lowercase()
{
var plaintext = "A";
var expected = "a";
Assert.Equal(expected, CryptoSquare.Ciphertext(plaintext));
}

[Fact(Skip = "Remove to run test")]
public void Remove_spaces()
{
var plaintext = "  b ";
var expected = "b";
Assert.Equal(expected, CryptoSquare.Ciphertext(plaintext));
}

[Fact(Skip = "Remove to run test")]
public void Remove_punctuation()
{
var plaintext = "@1,%!";
var expected = "1";
Assert.Equal(expected, CryptoSquare.Ciphertext(plaintext));
}

[Fact(Skip = "Remove to run test")]
public void Number_9_character_plaintext_results_in_3_chunks_of_3_characters()
{
var plaintext = "This is fun!";
var expected = "tsf hiu isn";
Assert.Equal(expected, CryptoSquare.Ciphertext(plaintext));
}

[Fact(Skip = "Remove to run test")]
public void Number_8_character_plaintext_results_in_3_chunks_the_last_one_with_a_trailing_space()
{
var plaintext = "Chill out.";
var expected = "clu hlt io ";
Assert.Equal(expected, CryptoSquare.Ciphertext(plaintext));
}

[Fact(Skip = "Remove to run test")]
public void Number_54_character_plaintext_results_in_7_chunks_the_last_two_with_trailing_spaces()
{
var plaintext = "If man was meant to stay on the ground, god would have given us roots.";
var expected = "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn  sseoau ";
Assert.Equal(expected, CryptoSquare.Ciphertext(plaintext));
}
}``````
``````using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

public static class CryptoSquare
{
private static readonly Regex regex = new Regex("\\W");

public static string NormalizedPlaintext(string plaintext) =>
regex.Replace(plaintext.ToLower(), "");

public static IEnumerable<string> PlaintextSegments(string plaintext)
{
var normalized = NormalizedPlaintext(plaintext);
var size = GetRectangleSize(normalized.Length);
normalized += new string(' ', size.Item2);
var rectangle = new string[size.Item1];
for (int i = 0; i < rectangle.Length; i++)
{
rectangle[i] = normalized.Substring(i * size.Item2, size.Item2);
}

return rectangle;
}

public static string Encoded(string plaintext)
{
var segments = PlaintextSegments(plaintext).ToArray();
if (segments.Length == 0)
{
return "";
}

var result = "";
for (int i = 0; i < segments[0].Length; i++)
{
for (int j = 0; j < segments.Length; j++)
{
if (segments[j][i] != ' ')
{
result += segments[j][i];
}
}
}

return result;
}

public static string Ciphertext(string plaintext)
{
var encoded = Encoded(plaintext);
var size = GetRectangleSize(encoded.Length);
var few = size.Item1 * size.Item2 - encoded.Length;

var rectangle = new string[size.Item2];
for (int i = 0; i < rectangle.Length - few; i++)
{
rectangle[i] = encoded.Substring(i * size.Item1, size.Item1);
}

for (int i = 0; i < few; i++)
{
rectangle[rectangle.Length - few + i] = encoded.Substring((rectangle.Length - few + i) * size.Item1 - i, size.Item1 - 1) + " ";
}

return string.Join(" ", rectangle);
}

private static (int, int) GetRectangleSize(int lenght)
{
var sqrt = (int)Math.Sqrt(lenght);
return sqrt * sqrt == lenght
? (sqrt, sqrt)
: lenght <= sqrt * (sqrt + 1)
? (sqrt, sqrt + 1)
: (sqrt + 1, sqrt + 1);
}
}``````