diff --git a/config.json b/config.json index 4787e17d..5b0d532d 100644 --- a/config.json +++ b/config.json @@ -688,6 +688,14 @@ "practices": [], "prerequisites": [], "difficulty": 1 + }, + { + "slug": "rail-fence-cipher", + "name": "Rail Fence Cipher", + "uuid": "e4b63b53-d6ca-4a1d-8e02-e295bd2c9c65", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ] }, diff --git a/exercises/practice/rail-fence-cipher/.docs/instructions.md b/exercises/practice/rail-fence-cipher/.docs/instructions.md new file mode 100644 index 00000000..e311de6c --- /dev/null +++ b/exercises/practice/rail-fence-cipher/.docs/instructions.md @@ -0,0 +1,57 @@ +# Instructions + +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. diff --git a/exercises/practice/rail-fence-cipher/.meta/config.json b/exercises/practice/rail-fence-cipher/.meta/config.json new file mode 100644 index 00000000..0e6bb6a6 --- /dev/null +++ b/exercises/practice/rail-fence-cipher/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "erikschierboom" + ], + "files": { + "solution": [ + "rail-fence-cipher.R" + ], + "test": [ + "test_rail-fence-cipher.R" + ], + "example": [ + ".meta/example.R" + ] + }, + "blurb": "Implement encoding and decoding for the rail fence cipher.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Transposition_cipher#Rail_Fence_cipher" +} diff --git a/exercises/practice/rail-fence-cipher/.meta/example.R b/exercises/practice/rail-fence-cipher/.meta/example.R new file mode 100644 index 00000000..91c01ccc --- /dev/null +++ b/exercises/practice/rail-fence-cipher/.meta/example.R @@ -0,0 +1,19 @@ +encode <- function(rails, plaintext) { + transform(rails, plaintext, \(i, fence) fence[i]) +} + +decode <- function(rails, ciphertext) { + transform(rails, ciphertext, \(i, fence) match(i, fence)) +} + +transform <- function(rails, text, char_index) { + chars <- strsplit(text, "") |> unlist() + fence <- rail_fence(rails, length(chars)) + indices <- sapply(seq_along(chars), \(i) char_index(i, fence)) + chars[indices] |> paste0(collapse = "") +} + +rail_fence <- function(rails, num_chars) { + zigzag <- c(seq_len(rails), seq(rails - 1, 2)) + rep(zigzag, length.out = num_chars) |> order() +} diff --git a/exercises/practice/rail-fence-cipher/.meta/tests.toml b/exercises/practice/rail-fence-cipher/.meta/tests.toml new file mode 100644 index 00000000..dfc5e16b --- /dev/null +++ b/exercises/practice/rail-fence-cipher/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[46dc5c50-5538-401d-93a5-41102680d068] +description = "encode -> encode with two rails" + +[25691697-fbd8-4278-8c38-b84068b7bc29] +description = "encode -> encode with three rails" + +[384f0fea-1442-4f1a-a7c4-5cbc2044002c] +description = "encode -> encode with ending in the middle" + +[cd525b17-ec34-45ef-8f0e-4f27c24a7127] +description = "decode -> decode with three rails" + +[dd7b4a98-1a52-4e5c-9499-cbb117833507] +description = "decode -> decode with five rails" + +[93e1ecf4-fac9-45d9-9cd2-591f47d3b8d3] +description = "decode -> decode with six rails" diff --git a/exercises/practice/rail-fence-cipher/rail-fence-cipher.R b/exercises/practice/rail-fence-cipher/rail-fence-cipher.R new file mode 100644 index 00000000..9d0d2a39 --- /dev/null +++ b/exercises/practice/rail-fence-cipher/rail-fence-cipher.R @@ -0,0 +1,7 @@ +encode <- function(rails, plaintext) { + +} + +decode <- function(rails, ciphertext) { + +} diff --git a/exercises/practice/rail-fence-cipher/test_rail-fence-cipher.R b/exercises/practice/rail-fence-cipher/test_rail-fence-cipher.R new file mode 100644 index 00000000..edc755aa --- /dev/null +++ b/exercises/practice/rail-fence-cipher/test_rail-fence-cipher.R @@ -0,0 +1,44 @@ +source("./rail-fence-cipher.R") +library(testthat) + +test_that("Encode with two rails", { + rails <- 2 + plaintext <- "XOXOXOXOXOXOXOXOXO" + expected <- "XXXXXXXXXOOOOOOOOO" + expect_equal(encode(rails, plaintext), expected) +}) + +test_that("Encode with three rails", { + rails <- 3 + plaintext <- "WEAREDISCOVEREDFLEEATONCE" + expected <- "WECRLTEERDSOEEFEAOCAIVDEN" + expect_equal(encode(rails, plaintext), expected) +}) + +test_that("Encode with ending in the middle", { + rails <- 4 + plaintext <- "EXERCISES" + expected <- "ESXIEECSR" + expect_equal(encode(rails, plaintext), expected) +}) + +test_that("Decode with three rails", { + rails <- 3 + ciphertext <- "TEITELHDVLSNHDTISEIIEA" + expected <- "THEDEVILISINTHEDETAILS" + expect_equal(decode(rails, ciphertext), expected) +}) + +test_that("Decode with five rails", { + rails <- 5 + ciphertext <- "EIEXMSMESAORIWSCE" + expected <- "EXERCISMISAWESOME" + expect_equal(decode(rails, ciphertext), expected) +}) + +test_that("Decode with six rails", { + rails <- 6 + ciphertext <- "133714114238148966225439541018335470986172518171757571896261" + expected <- "112358132134558914423337761098715972584418167651094617711286" + expect_equal(decode(rails, ciphertext), expected) +})