Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 15 additions & 34 deletions exercises/practice/crypto-square/.meta/example.R
Original file line number Diff line number Diff line change
@@ -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 = " ")
}
10 changes: 10 additions & 0 deletions exercises/practice/crypto-square/.meta/template.j2
Original file line number Diff line number Diff line change
@@ -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 %}
14 changes: 1 addition & 13 deletions exercises/practice/crypto-square/crypto-square.R
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
normalized_plaintext <- function(input) {

}

plaintext_segments <- function(input) {

}

encoded <- function(input) {

}

ciphertext <- function(input) {

}
73 changes: 16 additions & 57 deletions exercises/practice/crypto-square/test_crypto-square.R
Original file line number Diff line number Diff line change
@@ -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(
Expand All @@ -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("... --- ..."), "")
})