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

# KiligWY's solution

## to Crypto Square in the Objective-C Track

Published at Jul 13 2018 · 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
``````

## Setup

There are two different methods of getting set up to run the tests with Objective-C:

• Create an Xcode project with a test target which will run the tests.
• Use the ruby gem `objc` as a test runner utility.

Both are described in more detail here: http://exercism.io/languages/objective-c

### Submitting Exercises

When submitting an exercise, make sure your solution file is in the same directory as the test code.

The submit command will look something like:

``````exercism submit <path-to-exercism-workspace>/objective-c/crypto-square/CryptoSquare.m
``````

You can find the Exercism workspace by running `exercism debug` and looking for the line beginning with Workspace.

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

``````#import <XCTest/XCTest.h>
#if __has_include("CryptoSquareExample.h")
# import "CryptoSquareExample.h"
# else
# import "CryptoSquare.h"
#endif

@interface CryptoSquareTest : XCTestCase

@end

@implementation CryptoSquareTest

- (void)testNormalizeStrangeCharacters {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"s#\$%^&plunk"];
XCTAssertEqualObjects(@"splunk", [crypto normalizePlaintext]);
}

- (void)testNormalizeUppercaseCharacters {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"WHOA HEY!"];
XCTAssertEqualObjects(@"whoahey", [crypto normalizePlaintext]);
}

- (void)testNormalizeWithNumbers {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"1, 2, 3 GO!"];
XCTAssertEqualObjects(@"123go", [crypto normalizePlaintext]);
}

- (void)testSizeOfSmallSquare {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"1234"];
XCTAssertEqual(2, crypto.numberOfColumns);
}

- (void)testSizeOfSlightlyLargerSquare {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"123456789"];
XCTAssertEqual(3, crypto.numberOfColumns);
}

- (void)testSizeOfNonPerfectSquare {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"123456789abc"];
XCTAssertEqual(4, crypto.numberOfColumns);
}

- (void)testSizeIsDeterminedByNormalizedPlaintext {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"Oh hey, this is nuts!"];
XCTAssertEqual(4, crypto.numberOfColumns);
}

- (void)testPlaintextSegments {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"Never vex thine heart with idle woes"];
NSArray *expected = @[@"neverv", @"exthin", @"eheart", @"withid", @"lewoes"];
XCTAssertEqualObjects(expected, crypto.plaintextSegments);
}

- (void)testOtherPlaintextSegments {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"ZOMG! ZOMBIES!!!"];
NSArray *expected = @[@"zomg", @"zomb", @"ies"];
XCTAssertEqualObjects(expected, crypto.plaintextSegments);
}

- (void)testCiphertext {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"Time is an illusion. Lunchtime doubly so."];
XCTAssertEqualObjects(@"tasneyinicdsmiohooelntuillibsuuml", crypto.cipherText);
}

- (void)testAnotherCiphertext {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"We all know interspecies romance is weird."];
XCTAssertEqualObjects(@"wneiaweoreneawssciliprerlneoidktcms", crypto.cipherText);
}

- (void)testNormalizedCiphertext {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"Vampires are people too!"];
XCTAssertEqualObjects(@"vrel aepe mset paoo irpo", crypto.normalizedCipherText);
}

- (void)testNormalizedCiphertextSpillsIntoShortSegment {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"Madness, and then illumination."];
XCTAssertEqualObjects(@"msemo aanin dninn dlaet ltshu i", crypto.normalizedCipherText);
}

- (void)testAnotherNormalizedCiphertext {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:
@"If man was meant to stay on the ground god would have given us roots"];
NSString *expected = @"imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghns seoau";
XCTAssertEqualObjects(expected, crypto.normalizedCipherText);
}

- (void)testNormalizedCiphertextWithPunctuation {
CryptoSquare *crypto = [[CryptoSquare alloc] initWithText:@"Have a nice day. Feed the dog & chill out!"];
NSString *expected = @"hifei acedl veeol eddgo aatcu nyhht";
XCTAssertEqualObjects(expected, crypto.normalizedCipherText);
}

@end``````

### CryptoSquare.h

``````#import <Foundation/Foundation.h>

@interface CryptoSquare : NSObject

@property (nonatomic, assign) NSInteger numberOfColumns;
@property (nonatomic, strong) NSArray *plaintextSegments;
@property (nonatomic, copy) NSString *cipherText;
@property (nonatomic, copy) NSString *normalizedCipherText;
@property (nonatomic, copy) NSString *normalizePlaintext;

- (instancetype)initWithText:(NSString *)text;

@end``````

### CryptoSquare.m

``````#import "CryptoSquare.h"

@interface CryptoSquare ()

@property (nonatomic, assign) NSInteger numberOfRows;

@end

@implementation CryptoSquare

- (instancetype)initWithText:(NSString *)text {
if (self = [super init]) {
self.normalizePlaintext = [[text lowercaseString] stringByReplacingOccurrencesOfString:@"[^a-z0-9]" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, text.length)];
}
return self;
}

- (NSInteger)numberOfColumns {
for (NSInteger c = 1; c <= self.normalizePlaintext.length; ++c) {
NSInteger r = self.normalizePlaintext.length / c + (self.normalizePlaintext.length % c > 0 ? 1 : 0);
if (c >= r && c - r <= 1) {
self.numberOfRows = r;
return c;
}
}
return 0;
}

- (NSArray *)plaintextSegments {
return [self segments:self.normalizePlaintext];
}

- (NSString *)cipherText {
NSArray *array = self.plaintextSegments;
NSMutableString *result = [NSMutableString string];
for (NSInteger i = 0; i < self.numberOfColumns; ++i) {
for (NSInteger j = 0; j < array.count; ++j) {
if ([array[j] length] > i) {
[result appendString:[array[j] substringWithRange:NSMakeRange(i, 1)]];
}
}
}
return result;
}

- (NSString *)normalizedCipherText {
return [[self segments:self.cipherText] componentsJoinedByString:@" "];
}

- (NSArray *)segments:(NSString *)text {
NSInteger c, r;
if ([text isEqualToString:self.normalizePlaintext]) {
c = self.numberOfColumns;
r = self.numberOfRows;
} else {
c = self.numberOfRows;
r = self.numberOfColumns;
}
NSMutableArray *array = [NSMutableArray array];
for (NSInteger i = 0; i < r; ++i) {
if (i < r - 1) {
[array addObject:[text substringWithRange:NSMakeRange(i * c, c)]];
} else {
}
}
return array;
}

@end``````