diff --git a/exercises/crypto-square/example/crypto_square.d b/exercises/crypto-square/example/crypto_square.d index 73d9e729..1bd888eb 100644 --- a/exercises/crypto-square/example/crypto_square.d +++ b/exercises/crypto-square/example/crypto_square.d @@ -1,180 +1,127 @@ - module crypto; -import std.string; -import std.array; -import std.math : sqrt, floor, ceil; -import std.conv : to; - -import std.stdio; -import std.algorithm : map, filter; -import std.ascii : isAlphaNum; - - -class Cipher -{ -public: - this (const string text) - { - this.normalized = text.filter!isAlphaNum.map!toLower.to!string; - } - - string normalizePlainText () - { - return normalized; - } - - /** - * Return the number of encrypted segments(that is number of columns for the crypto square). - */ - size_t size () - { - size_t root = to!ulong(floor(sqrt(to!float(normalized.length)))); - - size_t distance = normalized.length - root * root; - if (distance == 0) - { - return root; - } - else - { - return to!ulong(root) + 1; - } - } - - string[] plainTextSegments () - { - size_t columns = size(); - size_t rem = normalized.length % columns; - string[] result; - - size_t len = normalized.length; - for (size_t j = 0; j <= (len - columns); j += columns) - { - result ~= normalized[j..j + columns]; - } - - // we need to handle the leftovers - if (rem) - { - result ~= normalized[len - rem .. len]; - } - - return result; - } - - string cipherText () - { - string result = normalizedCipherText(); - - return result.replace(" ", ""); - } - - string normalizedCipherText () - { - string result; - string[] segments = plainTextSegments(); - size_t columns = size(); - - for (size_t i = 0; i < columns; ++i) - { - string cryptoSegment; - foreach (s; segments) - { - if (i < s.length) cryptoSegment ~= s[i]; - } - - result ~= cryptoSegment; - result ~= " "; - } - - return strip(result); - - } - -private: - const string normalized; +struct Cipher { + import std.ascii : isAlphaNum; + import std.algorithm.iteration : filter, joiner; + import std.range : array, chunks, transposed, walkLength; + import std.uni : asLowerCase; + import std.math : sqrt, ceil; + + string delimiter; + typeof("".asLowerCase.filter!isAlphaNum) content; + this(string s) { + content = s.asLowerCase.filter!isAlphaNum; + } + + auto normalizePlainText() { + return content; + } + + @property + uint size() { + return cast(uint)(cast(double)content.walkLength).sqrt.ceil; + } + + @property + auto plainTextSegments() { + return content.chunks(size); + } + + @property + auto cipherText() { + return plainTextSegments.array.transposed.joiner(delimiter); + } + + Cipher normalize() { + Cipher result = this; + result.delimiter = " "; + return result; + } } unittest { +import std.algorithm.comparison : equal; +immutable int allTestsEnabled = 0; // normalize_strange_characters { - auto theCipher = new Cipher("s#$%^&plunk"); - assert("splunk" == theCipher.normalizePlainText()); + auto theCipher = Cipher("s#$%^&plunk"); + assert(equal("splunk", theCipher.normalizePlainText())); } +static if (allTestsEnabled) +{ // normalize_numbers { - auto theCipher = new Cipher("1, 2, 3 GO!"); - assert("123go" == theCipher.normalizePlainText()); + auto theCipher = Cipher("1, 2, 3 GO!"); + assert(equal("123go", theCipher.normalizePlainText())); } // size_of_small_square { - auto theCipher = new Cipher("1234"); + auto theCipher = Cipher("1234"); assert(2U == theCipher.size()); } // size_of_slightly_larger_square { - auto theCipher = new Cipher("123456789"); + auto theCipher = Cipher("123456789"); assert(3U == theCipher.size()); } // size_of_non_perfect_square { - auto theCipher = new Cipher("123456789abc"); + auto theCipher = Cipher("123456789abc"); assert(4U == theCipher.size()); } // size_of_non_perfect_square_less { - auto theCipher = new Cipher("zomgzombies"); + auto theCipher = Cipher("zomgzombies"); assert(4U == theCipher.size()); } // plain_text_segments_from_phrase { const string[] expected = ["neverv", "exthin", "eheart", "withid", "lewoes"]; - auto theCipher = new Cipher("Never vex thine heart with idle woes"); + auto theCipher = Cipher("Never vex thine heart with idle woes"); const auto actual = theCipher.plainTextSegments(); - assert(expected == actual); + assert(equal(expected, actual)); } // plain_text_segments_from_complex_phrase { const string[] expected = ["zomg", "zomb", "ies"]; - auto theCipher = new Cipher("ZOMG! ZOMBIES!!!"); + auto theCipher = Cipher("ZOMG! ZOMBIES!!!"); const auto actual = theCipher.plainTextSegments(); - assert(expected == actual); + assert(equal(expected, actual)); } // Cipher_text_short_phrase { - auto theCipher = new Cipher("Time is an illusion. Lunchtime doubly so."); - assert("tasneyinicdsmiohooelntuillibsuuml" == theCipher.cipherText()); + auto theCipher = Cipher("Time is an illusion. Lunchtime doubly so."); + assert(equal("tasneyinicdsmiohooelntuillibsuuml", theCipher.cipherText())); } // Cipher_text_long_phrase { - auto theCipher = new Cipher("We all know interspecies romance is weird."); - assert("wneiaweoreneawssciliprerlneoidktcms" == theCipher.cipherText()); + auto theCipher = Cipher("We all know interspecies romance is weird."); + assert(equal("wneiaweoreneawssciliprerlneoidktcms", theCipher.cipherText())); } // normalized_Cipher_text1 { - auto theCipher = new Cipher("Madness, and then illumination."); - assert("msemo aanin dnin ndla etlt shui" == theCipher.normalizedCipherText()); + auto theCipher = Cipher("Madness, and then illumination."); + assert(equal("msemo aanin dnin ndla etlt shui", theCipher.normalize.cipherText())); } // normalized_Cipher_text2 { - auto theCipher = new Cipher("Vampires are people too!"); - assert("vrel aepe mset paoo irpo" == theCipher.normalizedCipherText()); + auto theCipher = Cipher("Vampires are people too!"); + assert(equal("vrel aepe mset paoo irpo", theCipher.normalize.cipherText())); } - } +} \ No newline at end of file diff --git a/exercises/crypto-square/source/crypto_square.d b/exercises/crypto-square/source/crypto_square.d index 943927f1..151cdb60 100644 --- a/exercises/crypto-square/source/crypto_square.d +++ b/exercises/crypto-square/source/crypto_square.d @@ -1,90 +1,89 @@ - module crypto; unittest { +import std.algorithm.comparison : equal; immutable int allTestsEnabled = 0; // normalize_strange_characters { - auto theCipher = new Cipher("s#$%^&plunk"); - assert("splunk" == theCipher.normalizePlainText()); + auto theCipher = Cipher("s#$%^&plunk"); + assert(equal("splunk", theCipher.normalizePlainText())); } static if (allTestsEnabled) { // normalize_numbers { - auto theCipher = new Cipher("1, 2, 3 GO!"); - assert("123go" == theCipher.normalizePlainText()); + auto theCipher = Cipher("1, 2, 3 GO!"); + assert(equal("123go", theCipher.normalizePlainText())); } // size_of_small_square { - auto theCipher = new Cipher("1234"); + auto theCipher = Cipher("1234"); assert(2U == theCipher.size()); } // size_of_slightly_larger_square { - auto theCipher = new Cipher("123456789"); + auto theCipher = Cipher("123456789"); assert(3U == theCipher.size()); } // size_of_non_perfect_square { - auto theCipher = new Cipher("123456789abc"); + auto theCipher = Cipher("123456789abc"); assert(4U == theCipher.size()); } // size_of_non_perfect_square_less { - auto theCipher = new Cipher("zomgzombies"); + auto theCipher = Cipher("zomgzombies"); assert(4U == theCipher.size()); } // plain_text_segments_from_phrase { const string[] expected = ["neverv", "exthin", "eheart", "withid", "lewoes"]; - auto theCipher = new Cipher("Never vex thine heart with idle woes"); + auto theCipher = Cipher("Never vex thine heart with idle woes"); const auto actual = theCipher.plainTextSegments(); - assert(expected == actual); + assert(equal(expected, actual)); } // plain_text_segments_from_complex_phrase { const string[] expected = ["zomg", "zomb", "ies"]; - auto theCipher = new Cipher("ZOMG! ZOMBIES!!!"); + auto theCipher = Cipher("ZOMG! ZOMBIES!!!"); const auto actual = theCipher.plainTextSegments(); - assert(expected == actual); + assert(equal(expected, actual)); } // Cipher_text_short_phrase { - auto theCipher = new Cipher("Time is an illusion. Lunchtime doubly so."); - assert("tasneyinicdsmiohooelntuillibsuuml" == theCipher.cipherText()); + auto theCipher = Cipher("Time is an illusion. Lunchtime doubly so."); + assert(equal("tasneyinicdsmiohooelntuillibsuuml", theCipher.cipherText())); } // Cipher_text_long_phrase { - auto theCipher = new Cipher("We all know interspecies romance is weird."); - assert("wneiaweoreneawssciliprerlneoidktcms" == theCipher.cipherText()); + auto theCipher = Cipher("We all know interspecies romance is weird."); + assert(equal("wneiaweoreneawssciliprerlneoidktcms", theCipher.cipherText())); } // normalized_Cipher_text1 { - auto theCipher = new Cipher("Madness, and then illumination."); - assert("msemo aanin dnin ndla etlt shui" == theCipher.normalize.cipherText()); + auto theCipher = Cipher("Madness, and then illumination."); + assert(equal("msemo aanin dnin ndla etlt shui", theCipher.normalize.cipherText())); } // normalized_Cipher_text2 { - auto theCipher = new Cipher("Vampires are people too!"); - assert("vrel aepe mset paoo irpo" == theCipher.normalize.cipherText()); -} + auto theCipher = Cipher("Vampires are people too!"); + assert(equal("vrel aepe mset paoo irpo", theCipher.normalize.cipherText())); } - } +} \ No newline at end of file