diff --git a/exercises/practice/crypto-square/.meta/example.R b/exercises/practice/crypto-square/.meta/example.R index 9f439750..ea66bf80 100644 --- a/exercises/practice/crypto-square/.meta/example.R +++ b/exercises/practice/crypto-square/.meta/example.R @@ -1,37 +1,18 @@ -normalized_plaintext <- function(input) { - gsub("[^[:alnum:]]", "", input) |> - tolower() -} - -map_plaintext_to_matrix <- function(input) { - txt <- normalized_plaintext(input) - width <- max(1, nchar(txt) |> sqrt() |> ceiling()) - ext_len <- ceiling(nchar(txt) / width) * width - txt <- sprintf(paste0("%-", ext_len, "s"), txt) - - strsplit(txt, "") |> - unlist() |> - matrix(ncol = width, byrow = TRUE) -} - -plaintext_segments <- function(input) { - if (!nzchar(input)) { - return("") - } - map_plaintext_to_matrix(input) |> - apply(MARGIN = 1, paste, collapse = "") |> - trimws() -} - -encoded <- function(input) { - map_plaintext_to_matrix(input) |> - apply(MARGIN = 2, paste, collapse = "") |> - trimws() |> - paste(collapse = "") -} +library(stringr) ciphertext <- function(input) { - map_plaintext_to_matrix(input) |> - apply(MARGIN = 2, paste, collapse = "") |> - paste(collapse = " ") + normalized <- input |> str_to_lower() |> str_remove_all("[^a-z0-9]") + if (normalized == "") return("") + + # R matrices are column-major + # we will need a transpose to match the problem specification + r <- normalized |> nchar() |> sqrt() |> ceiling() + c <- (nchar(normalized) / r) |> ceiling() + normalized |> + str_pad(c * r, "right") |> + str_split_1("") |> + matrix(nrow = r, ncol = c) |> + t() |> + apply(2, str_flatten) |> + str_flatten(collapse = " ") } diff --git a/exercises/practice/crypto-square/.meta/template.j2 b/exercises/practice/crypto-square/.meta/template.j2 new file mode 100644 index 00000000..3a5558b3 --- /dev/null +++ b/exercises/practice/crypto-square/.meta/template.j2 @@ -0,0 +1,10 @@ +{%- import "generator_macros.j2" as macros with context -%} +{{ macros.canonical_ref() }} + +{{ macros.header() }} + +{% for case in cases -%} +test_that("{{ case["description"] }}", { + expect_equal({{ case["property"] }}("{{ case["input"]["plaintext"] }}"), "{{ case["expected"] }}") +}) +{% endfor %} diff --git a/exercises/practice/crypto-square/crypto-square.R b/exercises/practice/crypto-square/crypto-square.R index b053b3d6..0be9e490 100644 --- a/exercises/practice/crypto-square/crypto-square.R +++ b/exercises/practice/crypto-square/crypto-square.R @@ -1,15 +1,3 @@ -normalized_plaintext <- function(input) { - -} - -plaintext_segments <- function(input) { - -} - -encoded <- function(input) { - -} - ciphertext <- function(input) { - + } diff --git a/exercises/practice/crypto-square/test_crypto-square.R b/exercises/practice/crypto-square/test_crypto-square.R index b6bcef27..2530987c 100644 --- a/exercises/practice/crypto-square/test_crypto-square.R +++ b/exercises/practice/crypto-square/test_crypto-square.R @@ -1,68 +1,31 @@ +# These tests are auto-generated with test data from: +# https://github.com/exercism/problem-specifications/tree/main/exercises/crypto-square/canonical-data.json +# File last updated on 2026-08-05 + source("./crypto-square.R") library(testthat) +test_that("empty plaintext results in an empty ciphertext", { + expect_equal(ciphertext(""), "") +}) +test_that("normalization results in empty plaintext", { + expect_equal(ciphertext("... --- ..."), "") +}) test_that("Lowercase", { - expect_equal(normalized_plaintext("Hello"), "hello") + expect_equal(ciphertext("A"), "a") }) - test_that("Remove spaces", { - expect_equal(normalized_plaintext("Hi there"), "hithere") + expect_equal(ciphertext(" b "), "b") }) - test_that("Remove punctuation", { - expect_equal(normalized_plaintext("@1, 2%, 3 Go!"), "123go") -}) - -test_that("empty plaintext results in an empty rectangle", { - expect_equal(plaintext_segments(""), "") -}) - -test_that("4 character plaintext results in an 2x2 rectangle", { - expect_equal(plaintext_segments("Ab Cd"), c("ab", "cd")) -}) - -test_that("9 character plaintext results in an 3x3 rectangle", { - expect_equal(plaintext_segments("This is fun!"), c("thi", "sis", "fun")) -}) - -test_that("54 character plaintext results in an 8x7 rectangle", { - expect_equal( - plaintext_segments( - "If man was meant to stay on the ground, god would have given us roots." - ), - c( - "ifmanwas", - "meanttos", - "tayonthe", - "groundgo", - "dwouldha", - "vegivenu", - "sroots" - ) - ) -}) - -test_that("empty plaintext results in an empty encode", { - expect_equal(encoded(""), "") -}) - -test_that("Non-empty plaintext results in the combined plaintext segments", { - expect_equal( - encoded( - "If man was meant to stay on the ground, god would have given us roots." - ), - "imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau" - ) -}) - -test_that("empty plaintext results in an empty ciphertext", { - expect_equal(ciphertext(""), "") + expect_equal(ciphertext("@1,%!"), "1") }) - test_that("9 character plaintext results in 3 chunks of 3 characters", { expect_equal(ciphertext("This is fun!"), "tsf hiu isn") }) - +test_that("8 character plaintext results in 3 chunks, the last one with a trailing space", { + expect_equal(ciphertext("Chill out."), "clu hlt io ") +}) test_that("54 character plaintext results in 8 chunks, the last two with trailing spaces", { expect_equal( ciphertext( @@ -71,7 +34,3 @@ test_that("54 character plaintext results in 8 chunks, the last two with trailin "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " ) }) - -test_that("normalization results in empty plaintext", { - expect_equal(ciphertext("... --- ..."), "") -})