Skip to content

Commit 2053151

Browse files
Add rail-fence-cipher exercise (#59)
1 parent cc0c887 commit 2053151

File tree

7 files changed

+191
-0
lines changed

7 files changed

+191
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,14 @@
413413
"practices": [],
414414
"prerequisites": [],
415415
"difficulty": 7
416+
},
417+
{
418+
"slug": "rail-fence-cipher",
419+
"name": "Rail Fence Cipher",
420+
"uuid": "4e80fefa-8209-43c4-9740-cf8e54b9aecd",
421+
"practices": [],
422+
"prerequisites": [],
423+
"difficulty": 7
416424
}
417425
]
418426
},
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Instructions
2+
3+
Implement encoding and decoding for the rail fence cipher.
4+
5+
The Rail Fence cipher is a form of transposition cipher that gets its name from the way in which it's encoded.
6+
It was already used by the ancient Greeks.
7+
8+
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).
9+
Finally the message is then read off in rows.
10+
11+
For example, using three "rails" and the message "WE ARE DISCOVERED FLEE AT ONCE", the cipherer writes out:
12+
13+
```text
14+
W . . . E . . . C . . . R . . . L . . . T . . . E
15+
. E . R . D . S . O . E . E . F . E . A . O . C .
16+
. . A . . . I . . . V . . . D . . . E . . . N . .
17+
```
18+
19+
Then reads off:
20+
21+
```text
22+
WECRLTEERDSOEEFEAOCAIVDEN
23+
```
24+
25+
To decrypt a message you take the zig-zag shape and fill the ciphertext along the rows.
26+
27+
```text
28+
? . . . ? . . . ? . . . ? . . . ? . . . ? . . . ?
29+
. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? .
30+
. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . .
31+
```
32+
33+
The first row has seven spots that can be filled with "WECRLTE".
34+
35+
```text
36+
W . . . E . . . C . . . R . . . L . . . T . . . E
37+
. ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? . ? .
38+
. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . .
39+
```
40+
41+
Now the 2nd row takes "ERDSOEEFEAOC".
42+
43+
```text
44+
W . . . E . . . C . . . R . . . L . . . T . . . E
45+
. E . R . D . S . O . E . E . F . E . A . O . C .
46+
. . ? . . . ? . . . ? . . . ? . . . ? . . . ? . .
47+
```
48+
49+
Leaving "AIVDEN" for the last row.
50+
51+
```text
52+
W . . . E . . . C . . . R . . . L . . . T . . . E
53+
. E . R . D . S . O . E . E . F . E . A . O . C .
54+
. . A . . . I . . . V . . . D . . . E . . . N . .
55+
```
56+
57+
If you now read along the zig-zag shape you can read the original message.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"keiravillekode"
4+
],
5+
"files": {
6+
"solution": [
7+
"rail_fence_cipher.fut"
8+
],
9+
"test": [
10+
"test.fut"
11+
],
12+
"example": [
13+
".meta/example.fut"
14+
]
15+
},
16+
"blurb": "Implement encoding and decoding for the rail fence cipher.",
17+
"source": "Wikipedia",
18+
"source_url": "https://en.wikipedia.org/wiki/Transposition_cipher#Rail_Fence_cipher"
19+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
def rail_lengths (rails: i64) (n: i64): [rails]i64 =
2+
let (lengths, _, _) = loop (lengths, rail, direction) = (replicate rails 0, 0, 1) for _ in 0..<n do
3+
let rail2 = rail + direction
4+
let direction2 = if rail2 > 0 && rail2 + 1 < rails then direction else -direction
5+
in
6+
(lengths with [rail] = lengths[rail] + 1, rail2, direction2)
7+
in
8+
lengths
9+
10+
def rail_offsets (rails: i64) (n: i64): [rails]i64 =
11+
let lengths = rail_lengths rails n
12+
let (offsets, _) = loop (offsets, acc) = (replicate rails 0, 0) for rail in 0..<rails do
13+
(offsets with [rail] = acc, acc + lengths[rail])
14+
in
15+
offsets
16+
17+
def process [n] (msg: [n]u8) (rails: i64) (is_decode: bool): [n]u8 =
18+
let (result, _, _, _) = loop (result, offsets, rail, direction) = (replicate n 0u8, rail_offsets rails n, 0, 1) for i in 0..<n do
19+
let rail2 = rail + direction
20+
let direction2 = if rail2 > 0 && rail2 + 1 < rails then direction else -direction
21+
let offset = offsets[rail]
22+
let offsets2 = offsets with [rail] = offset + 1
23+
let result2 = if is_decode then result with [i] = msg[offset] else result with [offset] = msg[i]
24+
in
25+
(result2, offsets2, rail2, direction2)
26+
in
27+
result
28+
29+
def encode (msg: []u8) (rails: i64): []u8 =
30+
process msg rails false
31+
32+
def decode (msg: []u8) (rails: i64): []u8 =
33+
process msg rails true
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[46dc5c50-5538-401d-93a5-41102680d068]
13+
description = "encode -> encode with two rails"
14+
15+
[25691697-fbd8-4278-8c38-b84068b7bc29]
16+
description = "encode -> encode with three rails"
17+
18+
[384f0fea-1442-4f1a-a7c4-5cbc2044002c]
19+
description = "encode -> encode with ending in the middle"
20+
21+
[cd525b17-ec34-45ef-8f0e-4f27c24a7127]
22+
description = "decode -> decode with three rails"
23+
24+
[dd7b4a98-1a52-4e5c-9499-cbb117833507]
25+
description = "decode -> decode with five rails"
26+
27+
[93e1ecf4-fac9-45d9-9cd2-591f47d3b8d3]
28+
description = "decode -> decode with six rails"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def encode (msg: []u8) (rails: i64): []u8 = ???
2+
3+
def decode (msg: []u8) (rails: i64): []u8 = ???
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import "rail_fence_cipher"
2+
3+
-- encode with two rails
4+
-- ==
5+
-- entry: test_encode
6+
-- input { "XOXOXOXOXOXOXOXOXO" 2i64 }
7+
-- output { "XXXXXXXXXOOOOOOOOO" }
8+
9+
-- encode with three rails
10+
-- ==
11+
-- entry: test_encode
12+
-- input { "WEAREDISCOVEREDFLEEATONCE" 3i64 }
13+
-- output { "WECRLTEERDSOEEFEAOCAIVDEN" }
14+
15+
-- encode with ending in the middle
16+
-- ==
17+
-- entry: test_encode
18+
-- input { "EXERCISES" 4i64 }
19+
-- output { "ESXIEECSR" }
20+
21+
-- decode with three rails
22+
-- ==
23+
-- entry: test_decode
24+
-- input { "TEITELHDVLSNHDTISEIIEA" 3i64 }
25+
-- output { "THEDEVILISINTHEDETAILS" }
26+
27+
-- decode with five rails
28+
-- ==
29+
-- entry: test_decode
30+
-- input { "EIEXMSMESAORIWSCE" 5i64 }
31+
-- output { "EXERCISMISAWESOME" }
32+
33+
-- decode with six rails
34+
-- ==
35+
-- entry: test_decode
36+
-- input { "133714114238148966225439541018335470986172518171757571896261" 6i64 }
37+
-- output { "112358132134558914423337761098715972584418167651094617711286" }
38+
39+
entry test_encode (msg: []u8) (rails: i64): []u8 =
40+
encode msg rails
41+
42+
entry test_decode (msg: []u8) (rails: i64): []u8 =
43+
decode msg rails

0 commit comments

Comments
 (0)