ruby - rail-fence-cipher
This commit is contained in:
parent
505afd4b98
commit
4d0cebcbff
89
ruby/rail-fence-cipher/README.md
Normal file
89
ruby/rail-fence-cipher/README.md
Normal file
@ -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.
|
26
ruby/rail-fence-cipher/rail_fence_cipher.rb
Normal file
26
ruby/rail-fence-cipher/rail_fence_cipher.rb
Normal file
@ -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
|
61
ruby/rail-fence-cipher/rail_fence_cipher_test.rb
Normal file
61
ruby/rail-fence-cipher/rail_fence_cipher_test.rb
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user