Skip to content

crypto-square: Reflect changes to problem specifications #738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 22, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions exercises/crypto-square/.meta/.version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1
19 changes: 19 additions & 0 deletions exercises/crypto-square/.meta/generator/crypto_square_case.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
require 'generator/exercise_case'

class CryptoSquareCase < Generator::ExerciseCase

def workload
indent_lines([plaintext_setter, assertion], 4)
end

private

def plaintext_setter
"plaintext = '#{plaintext}'"
end

def assertion
assert_equal { "Crypto.new(plaintext).ciphertext" }
end

end
35 changes: 20 additions & 15 deletions exercises/crypto-square/.meta/solutions/crypto_square.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,41 @@ def initialize(plaintext)
@plaintext = plaintext
end

def ciphertext
transposed.join(' ')
end

private

def normalize_plaintext
@normalized ||= @plaintext.downcase.gsub(/\W/, '')
end

def plaintext_segments
normalize_plaintext.chars.
each_slice(size).
map{ |s| s.join('') }.
to_a
if size > 0
normalize_plaintext.chars.
each_slice(size).
map{ |s| s.join('') }.
to_a
else
[]
end
end

def size
Math.sqrt(normalize_plaintext.length).ceil
end

def ciphertext
transposed.join('')
end

def normalize_ciphertext
transposed.join(' ')
end

private

def transposed
chunk_size = size
chunks = plaintext_segments.map do |s|
Array.new(chunk_size) { |i| s[i] or '' }
Array.new(chunk_size) { |i| s[i] or ' ' }
end
chunks.transpose.map{ |s| s.join('') }
end

end

module BookKeeping
VERSION = 1
end
18 changes: 10 additions & 8 deletions exercises/crypto-square/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ and `r` is the number of rows.
Our normalized text is 54 characters long, dictating a rectangle with
`c = 8` and `r = 7`:

```plain
```text
ifmanwas
meanttos
tayonthe
Expand All @@ -41,22 +41,24 @@ right.

The message above is coded as:

```plain
```text
imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau
```

Output the encoded text in chunks. Phrases that fill perfect squares
`(r X r)` should be output in `r`-length chunks separated by spaces.
Imperfect squares will have `n` empty spaces. Those spaces should be distributed evenly across the last `n` rows.
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.

```plain
imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau
```text
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:

```plain
```text
imtgdvs
fearwer
mayoogo
Expand Down
126 changes: 45 additions & 81 deletions exercises/crypto-square/crypto_square_test.rb
Original file line number Diff line number Diff line change
@@ -1,105 +1,69 @@
require 'minitest/autorun'
require_relative 'crypto_square'

class CryptoTest < Minitest::Test
def test_normalize_strange_characters
crypto = Crypto.new('s#$%^&plunk')
assert_equal 'splunk', crypto.normalize_plaintext
# Common test data version: 3.1.0 e937744
class CryptoSquareTest < Minitest::Test
def test_empty_plaintext_results_in_an_empty_ciphertext
# skip
plaintext = ''
assert_equal "", Crypto.new(plaintext).ciphertext
end

def test_normalize_uppercase_characters
def test_lowercase
skip
crypto = Crypto.new('WHOA HEY!')
assert_equal 'whoahey', crypto.normalize_plaintext
plaintext = 'A'
assert_equal "a", Crypto.new(plaintext).ciphertext
end

def test_normalize_with_numbers
def test_remove_spaces
skip
crypto = Crypto.new('1, 2, 3 GO!')
assert_equal '123go', crypto.normalize_plaintext
plaintext = ' b '
assert_equal "b", Crypto.new(plaintext).ciphertext
end

def test_size_of_small_square
def test_remove_punctuation
skip
crypto = Crypto.new('1234')
assert_equal 2, crypto.size
plaintext = '@1,%!'
assert_equal "1", Crypto.new(plaintext).ciphertext
end

def test_size_of_slightly_larger_square
def test_9_character_plaintext_results_in_3_chunks_of_3_characters
skip
crypto = Crypto.new('123456789')
assert_equal 3, crypto.size
plaintext = 'This is fun!'
assert_equal "tsf hiu isn", Crypto.new(plaintext).ciphertext
end

def test_size_of_non_perfect_square
def test_8_character_plaintext_results_in_3_chunks_the_last_one_with_a_trailing_space
skip
crypto = Crypto.new('123456789abc')
assert_equal 4, crypto.size
plaintext = 'Chill out.'
assert_equal "clu hlt io ", Crypto.new(plaintext).ciphertext
end

def test_size_is_determined_by_normalized_plaintext
def test_54_character_plaintext_results_in_7_chunks_the_last_two_with_trailing_spaces
skip
crypto = Crypto.new('Oh hey, this is nuts!')
assert_equal 4, crypto.size
end

def test_plaintext_segments
skip
crypto = Crypto.new('Never vex thine heart with idle woes')
expected = %w(neverv exthin eheart withid lewoes)
assert_equal expected, crypto.plaintext_segments
end

def test_other_plaintext_segments
skip
crypto = Crypto.new('ZOMG! ZOMBIES!!!')
assert_equal %w(zomg zomb ies), crypto.plaintext_segments
end

def test_ciphertext
skip
crypto = Crypto.new('Time is an illusion. Lunchtime doubly so.')
assert_equal 'tasneyinicdsmiohooelntuillibsuuml', crypto.ciphertext
end

def test_another_ciphertext
skip
crypto = Crypto.new('We all know interspecies romance is weird.')
assert_equal 'wneiaweoreneawssciliprerlneoidktcms', crypto.ciphertext
end

def test_normalized_ciphertext
skip
crypto = Crypto.new('Vampires are people too!')
assert_equal 'vrel aepe mset paoo irpo', crypto.normalize_ciphertext
end

def test_normalized_ciphertext_spills_into_short_segment
skip
crypto = Crypto.new('Madness, and then illumination.')
expected = 'msemo aanin dnin ndla etlt shui'
assert_equal expected, crypto.normalize_ciphertext
end

def test_another_normalized_ciphertext
skip
crypto = Crypto.new(
'If man was meant to stay on the ground god would have given us roots',
)
expected = 'imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau'
assert_equal expected, crypto.normalize_ciphertext
end

def test_normalized_ciphertext_with_punctuation
skip
crypto = Crypto.new('Have a nice day. Feed the dog & chill out!')
expected = 'hifei acedl veeol eddgo aatcu nyhht'
assert_equal expected, crypto.normalize_ciphertext
end

def test_normalized_ciphertext_when_just_less_then_a_full_square
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

# Problems in exercism evolve over time, as we find better ways to ask
# questions.
# The version number refers to the version of the problem you solved,
# not your solution.
#
# Define a constant named VERSION inside of the top level BookKeeping
# module, which may be placed near the end of your file.
#
# In your file, it will look like this:
#
# module BookKeeping
# VERSION = 1 # Where the version number matches the one in the test.
# end
#
# If you are curious, read more about constants on RubyDoc:
# http://ruby-doc.org/docs/ruby-doc-bundle/UsersGuide/rg/constants.html

def test_bookkeeping
skip
crypto = Crypto.new('I am')
assert_equal 'im a', crypto.normalize_ciphertext
assert_equal 1, BookKeeping::VERSION
end
end