From 4d0cebcbffa3afce6c85f06bab9c69efb4496380 Mon Sep 17 00:00:00 2001 From: James Walker Date: Thu, 8 Nov 2018 22:52:17 -0500 Subject: [PATCH] ruby - rail-fence-cipher --- ruby/rail-fence-cipher/README.md | 89 +++++++++++++++++++ ruby/rail-fence-cipher/rail_fence_cipher.rb | 26 ++++++ .../rail_fence_cipher_test.rb | 61 +++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 ruby/rail-fence-cipher/README.md create mode 100644 ruby/rail-fence-cipher/rail_fence_cipher.rb create mode 100644 ruby/rail-fence-cipher/rail_fence_cipher_test.rb diff --git a/ruby/rail-fence-cipher/README.md b/ruby/rail-fence-cipher/README.md new file mode 100644 index 0000000..fbd6efa --- /dev/null +++ b/ruby/rail-fence-cipher/README.md @@ -0,0 +1,89 @@ +# Rail Fence Cipher + +Implement encoding and decoding for the rail fence cipher. + +The Rail Fence cipher is a form of transposition cipher that gets its name from +the way in which it's encoded. It was already used by the ancient Greeks. + +In the Rail Fence cipher, the message is written downwards on successive "rails" +of an imaginary fence, then moving up when we get to the bottom (like a zig-zag). +Finally the message is then read off in rows. + +For example, using three "rails" and the message "WE ARE DISCOVERED FLEE AT ONCE", +the cipherer writes out: + +```text +W . . . E . . . C . . . R . . . L . . . T . . . E +. E . R . D . S . O . E . E . F . E . A . O . C . +. . A . . . I . . . V . . . D . . . E . . . N . . +``` + +Then reads off: + +```text +WECRLTEERDSOEEFEAOCAIVDEN +``` + +To decrypt a message you take the zig-zag shape and fill the ciphertext along the rows. + +```text +? . . . ? . . . ? . . . ? . . . ? . . . ? . . . ? +. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . +. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . +``` + +The first row has seven spots that can be filled with "WECRLTE". + +```text +W . . . E . . . C . . . R . . . L . . . T . . . E +. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . +. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . +``` + +Now the 2nd row takes "ERDSOEEFEAOC". + +```text +W . . . E . . . C . . . R . . . L . . . T . . . E +. E . R . D . S . O . E . E . F . E . A . O . C . +. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . . +``` + +Leaving "AIVDEN" for the last row. + +```text +W . . . E . . . C . . . R . . . L . . . T . . . E +. E . R . D . S . O . E . E . F . E . A . O . C . +. . A . . . I . . . V . . . D . . . E . . . N . . +``` + +If you now read along the zig-zag shape you can read the original message. + +* * * * + +For installation and learning resources, refer to the +[Ruby resources page](http://exercism.io/languages/ruby/resources). + +For running the tests provided, you will need the Minitest gem. Open a +terminal window and run the following command to install minitest: + + gem install minitest + +If you would like color output, you can `require 'minitest/pride'` in +the test file, or note the alternative instruction, below, for running +the test file. + +Run the tests from the exercise directory using the following command: + + ruby rail_fence_cipher_test.rb + +To include color from the command line: + + ruby -r minitest/pride rail_fence_cipher_test.rb + + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Transposition_cipher#Rail_Fence_cipher](https://en.wikipedia.org/wiki/Transposition_cipher#Rail_Fence_cipher) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/ruby/rail-fence-cipher/rail_fence_cipher.rb b/ruby/rail-fence-cipher/rail_fence_cipher.rb new file mode 100644 index 0000000..349538f --- /dev/null +++ b/ruby/rail-fence-cipher/rail_fence_cipher.rb @@ -0,0 +1,26 @@ +# RailFenceCipher class +class RailFenceCipher + def self.encode(message, rails) + rows = Array.new(rails, '') + pattern(rails, message.length).each.with_index do |row, char| + rows[row] += message[char] + end + rows.join + end + + def self.decode(message, rails) + chars = message.chars + counts = get_counts(rails, message.length) + rows = Array.new(rails) { |row| chars.shift(counts[row]) } + pattern(rails, message.length).map { |i| rows[i].shift }.join + end + + def self.pattern(rails, size) + zigzag = 0.upto(rails - 1).to_a + (rails - 2).downto(1).to_a + zigzag.cycle.take(size) + end + + def self.get_counts(rails, size) + Array.new(rails) { |row| pattern(rails, size).count { |i| i == row } } + end +end diff --git a/ruby/rail-fence-cipher/rail_fence_cipher_test.rb b/ruby/rail-fence-cipher/rail_fence_cipher_test.rb new file mode 100644 index 0000000..d49a59c --- /dev/null +++ b/ruby/rail-fence-cipher/rail_fence_cipher_test.rb @@ -0,0 +1,61 @@ +require 'minitest/autorun' +require_relative 'rail_fence_cipher' + +class RailFenceCipherTest < Minitest::Test + def test_encode_with_empty_string + # skip + assert_equal '', RailFenceCipher.encode('', 4) + end + + def test_encode_with_one_rail + # skip + assert_equal 'One rail, only one rail', + RailFenceCipher.encode('One rail, only one rail', 1) + end + + def test_encode_with_two_rails + # skip + assert_equal 'XXXXXXXXXOOOOOOOOO', + RailFenceCipher.encode('XOXOXOXOXOXOXOXOXO', 2) + end + + def test_encode_with_three_rails + # skip + assert_equal 'WECRLTEERDSOEEFEAOCAIVDEN', + RailFenceCipher.encode('WEAREDISCOVEREDFLEEATONCE', 3) + end + + def test_encode_with_ending_in_the_middle + # skip + assert_equal 'ESXIEECSR', RailFenceCipher.encode('EXERCISES', 4) + end + + def test_encode_with_less_letters_than_rails + # skip + assert_equal 'More rails than letters', + RailFenceCipher.encode('More rails than letters', 24) + end + + def test_decode_with_empty_string + # skip + assert_equal '', RailFenceCipher.decode('', 4) + end + + def test_decode_with_one_rail + # skip + assert_equal 'ABCDEFGHIJKLMNOP', + RailFenceCipher.decode('ABCDEFGHIJKLMNOP', 1) + end + + def test_decode_with_two_rails + # skip + assert_equal 'XOXOXOXOXOXOXOXOXO', + RailFenceCipher.decode('XXXXXXXXXOOOOOOOOO', 2) + end + + def test_decode_with_three_rails + # skip + assert_equal 'THEDEVILISINTHEDETAILS', + RailFenceCipher.decode('TEITELHDVLSNHDTISEIIEA', 3) + end +end