Skip to content

Commit 436c89d

Browse files
Add crypto-square
1 parent a76de32 commit 436c89d

File tree

12 files changed

+3674
-0
lines changed

12 files changed

+3674
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,14 @@
343343
"prerequisites": [],
344344
"difficulty": 6
345345
},
346+
{
347+
"slug": "crypto-square",
348+
"name": "Crypto Square",
349+
"uuid": "af35d898-215e-4dc6-a4f0-d4511a39be0e",
350+
"practices": [],
351+
"prerequisites": [],
352+
"difficulty": 6
353+
},
346354
{
347355
"slug": "knapsack",
348356
"name": "Knapsack",
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Instructions
2+
3+
Implement the classic method for composing secret messages called a square code.
4+
5+
Given an English text, output the encoded version of that text.
6+
7+
First, the input is normalized: the spaces and punctuation are removed from the English text and the message is down-cased.
8+
9+
Then, the normalized characters are broken into rows.
10+
These rows can be regarded as forming a rectangle when printed with intervening newlines.
11+
12+
For example, the sentence
13+
14+
```text
15+
"If man was meant to stay on the ground, god would have given us roots."
16+
```
17+
18+
is normalized to:
19+
20+
```text
21+
"ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots"
22+
```
23+
24+
The plaintext should be organized into a rectangle as square as possible.
25+
The size of the rectangle should be decided by the length of the message.
26+
27+
If `c` is the number of columns and `r` is the number of rows, then for the rectangle `r` x `c` find the smallest possible integer `c` such that:
28+
29+
- `r * c >= length of message`,
30+
- and `c >= r`,
31+
- and `c - r <= 1`.
32+
33+
Our normalized text is 54 characters long, dictating a rectangle with `c = 8` and `r = 7`:
34+
35+
```text
36+
"ifmanwas"
37+
"meanttos"
38+
"tayonthe"
39+
"groundgo"
40+
"dwouldha"
41+
"vegivenu"
42+
"sroots "
43+
```
44+
45+
The coded message is obtained by reading down the columns going left to right.
46+
47+
The message above is coded as:
48+
49+
```text
50+
"imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau"
51+
```
52+
53+
Output the encoded text in chunks that fill perfect rectangles `(r X c)`, with `c` chunks of `r` length, separated by spaces.
54+
For phrases that are `n` characters short of the perfect rectangle, pad each of the last `n` chunks with a single trailing space.
55+
56+
```text
57+
"imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau "
58+
```
59+
60+
Notice that were we to stack these, we could visually decode the ciphertext back in to the original message:
61+
62+
```text
63+
"imtgdvs"
64+
"fearwer"
65+
"mayoogo"
66+
"anouuio"
67+
"ntnnlvt"
68+
"wttddes"
69+
"aohghn "
70+
"sseoau "
71+
```
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+
"crypto_square.s"
8+
],
9+
"test": [
10+
"crypto_square_test.c"
11+
],
12+
"example": [
13+
".meta/example.s"
14+
]
15+
},
16+
"blurb": "Implement the classic method for composing secret messages called a square code.",
17+
"source": "J Dalbey's Programming Practice problems",
18+
"source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html"
19+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
.text
2+
.globl ciphertext
3+
4+
/* extern void ciphertext(char *buffer, const char *plaintext); */
5+
ciphertext:
6+
move a2, zero /* number of alphanumeric characters */
7+
move t0, a1 /* source pointer */
8+
li t5, 10
9+
li t6, 26
10+
j .scan
11+
12+
.count:
13+
addi t2, t1, -'0'
14+
bltu t2, t5, .accept /* digit? */
15+
16+
ori t1, t1, 32
17+
addi t2, t1, -'a'
18+
bgeu t2, t6, .scan /* non-letter? */
19+
20+
.accept:
21+
add a2, a2, 1
22+
23+
.scan:
24+
lbu t1, 0(t0) /* read */
25+
addi t0, t0, 1
26+
bnez t1, .count
27+
28+
sb zero, 0(a0)
29+
beqz a2, .return /* no alphanumeric characters? */
30+
31+
move a4, zero /* number of input columns */
32+
j .square
33+
34+
.increment_columns:
35+
addi a4, a4, 1
36+
37+
.square:
38+
mul t2, a4, a4
39+
blt t2, a2, .increment_columns
40+
41+
addi a3, a4, -1 /* number of input rows */
42+
mul t2, a3, a4
43+
slt t2, t2, a2 /* 1 iff rows * columns < number of alphanumeric characters */
44+
add a3, a3, t2
45+
46+
mul t2, a3, a4
47+
add t2, t2, a4 /* add number of input columns */
48+
addi t2, t2, -1 /* length of output: (rows + 1) * columns - 1 */
49+
add t2, a0, t2
50+
51+
sb zero, 0(t2)
52+
li t1, ' '
53+
54+
.space:
55+
addi t2, t2, -1
56+
sb t1, 0(t2)
57+
bne t2, a0, .space
58+
59+
add a3, a3, 1 /* number of output columns = number of input rows + 1 */
60+
61+
.next_output_column:
62+
move t3, a4 /* number of output rows remaining */
63+
move t4, zero
64+
65+
.read:
66+
lbu t1, 0(a1) /* read */
67+
addi a1, a1, 1
68+
addi t2, t1, -'0'
69+
bltu t2, t5, .write /* digit? */
70+
71+
ori t1, t1, 32
72+
addi t2, t1, -'a'
73+
bgeu t2, t6, .read /* non-letter? */
74+
75+
.write:
76+
add a5, a0, t4
77+
sb t1, 0(a5)
78+
79+
addi a2, a2, -1
80+
beqz a2, .return /* no alphanumeric characters remain? */
81+
82+
add t4, t4, a3
83+
addi t3, t3, -1
84+
bnez t3, .read
85+
86+
addi a0, a0, 1 /* next output column */
87+
j .next_output_column
88+
89+
.return:
90+
ret
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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+
[407c3837-9aa7-4111-ab63-ec54b58e8e9f]
13+
description = "empty plaintext results in an empty ciphertext"
14+
15+
[aad04a25-b8bb-4304-888b-581bea8e0040]
16+
description = "normalization results in empty plaintext"
17+
18+
[64131d65-6fd9-4f58-bdd8-4a2370fb481d]
19+
description = "Lowercase"
20+
21+
[63a4b0ed-1e3c-41ea-a999-f6f26ba447d6]
22+
description = "Remove spaces"
23+
24+
[1b5348a1-7893-44c1-8197-42d48d18756c]
25+
description = "Remove punctuation"
26+
27+
[8574a1d3-4a08-4cec-a7c7-de93a164f41a]
28+
description = "9 character plaintext results in 3 chunks of 3 characters"
29+
30+
[a65d3fa1-9e09-43f9-bcec-7a672aec3eae]
31+
description = "8 character plaintext results in 3 chunks, the last one with a trailing space"
32+
33+
[fbcb0c6d-4c39-4a31-83f6-c473baa6af80]
34+
description = "54 character plaintext results in 7 chunks, the last two with trailing spaces"
35+
include = false
36+
37+
[33fd914e-fa44-445b-8f38-ff8fbc9fe6e6]
38+
description = "54 character plaintext results in 8 chunks, the last two with trailing spaces"
39+
reimplements = "fbcb0c6d-4c39-4a31-83f6-c473baa6af80"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
AS = /usr/bin/riscv64-linux-gnu-as
2+
CC = /usr/bin/riscv64-linux-gnu-gcc
3+
4+
CFLAGS = -g -Wall -Wextra -pedantic -Werror
5+
LDFLAGS =
6+
7+
ALL_LDFLAGS = -pie -Wl,--fatal-warnings
8+
9+
ALL_CFLAGS = -std=c99 -fPIE $(CFLAGS)
10+
ALL_LDFLAGS += $(LDFLAGS)
11+
12+
C_OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
13+
AS_OBJS = $(patsubst %.s,%.o,$(wildcard *.s))
14+
ALL_OBJS = $(filter-out example.o,$(C_OBJS) $(AS_OBJS) vendor/unity.o)
15+
16+
CC_CMD = $(CC) $(ALL_CFLAGS) -c -o $@ $<
17+
18+
all: tests
19+
qemu-riscv64 -L /usr/riscv64-linux-gnu ./$<
20+
21+
tests: $(ALL_OBJS)
22+
@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $(ALL_OBJS)
23+
24+
%.o: %.s
25+
@$(AS) -o $@ $<
26+
27+
%.o: %.c
28+
@$(CC_CMD)
29+
30+
vendor/unity.o: vendor/unity.c vendor/unity.h vendor/unity_internals.h
31+
@$(CC_CMD)
32+
33+
clean:
34+
@rm -f *.o vendor/*.o tests
35+
36+
.PHONY: all clean
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.text
2+
.globl ciphertext
3+
4+
ciphertext:
5+
ret
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#include "vendor/unity.h"
2+
3+
#define BUFFER_SIZE 80
4+
5+
extern void ciphertext(char *buffer, const char *plaintext);
6+
7+
void setUp(void) {
8+
}
9+
10+
void tearDown(void) {
11+
}
12+
13+
void test_empty_plaintext_results_in_an_empty_ciphertext(void) {
14+
char buffer[BUFFER_SIZE];
15+
16+
ciphertext(buffer, "");
17+
TEST_ASSERT_EQUAL_STRING("", buffer);
18+
}
19+
20+
void test_normalization_results_in_empty_plaintext(void) {
21+
TEST_IGNORE();
22+
char buffer[BUFFER_SIZE];
23+
24+
ciphertext(buffer, "... --- ...");
25+
TEST_ASSERT_EQUAL_STRING("", buffer);
26+
}
27+
28+
void test_lowercase(void) {
29+
TEST_IGNORE();
30+
char buffer[BUFFER_SIZE];
31+
32+
ciphertext(buffer, "A");
33+
TEST_ASSERT_EQUAL_STRING("a", buffer);
34+
}
35+
36+
void test_remove_spaces(void) {
37+
TEST_IGNORE();
38+
char buffer[BUFFER_SIZE];
39+
40+
ciphertext(buffer, " b ");
41+
TEST_ASSERT_EQUAL_STRING("b", buffer);
42+
}
43+
44+
void test_remove_punctuation(void) {
45+
TEST_IGNORE();
46+
char buffer[BUFFER_SIZE];
47+
48+
ciphertext(buffer, "@1,%!");
49+
TEST_ASSERT_EQUAL_STRING("1", buffer);
50+
}
51+
52+
void test_9_character_plaintext_results_in_3_chunks_of_3_characters(void) {
53+
TEST_IGNORE();
54+
char buffer[BUFFER_SIZE];
55+
56+
ciphertext(buffer, "This is fun!");
57+
TEST_ASSERT_EQUAL_STRING("tsf hiu isn", buffer);
58+
}
59+
60+
void test_8_character_plaintext_results_in_3_chunks_the_last_one_with_a_trailing_space(void) {
61+
TEST_IGNORE();
62+
char buffer[BUFFER_SIZE];
63+
64+
ciphertext(buffer, "Chill out.");
65+
TEST_ASSERT_EQUAL_STRING("clu hlt io ", buffer);
66+
}
67+
68+
void test_54_character_plaintext_results_in_8_chunks_the_last_two_with_trailing_spaces(void) {
69+
TEST_IGNORE();
70+
char buffer[BUFFER_SIZE];
71+
72+
ciphertext(buffer, "If man was meant to stay on the ground, god would have given us roots.");
73+
TEST_ASSERT_EQUAL_STRING("imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau ", buffer);
74+
}
75+
76+
int main(void) {
77+
UNITY_BEGIN();
78+
RUN_TEST(test_empty_plaintext_results_in_an_empty_ciphertext);
79+
RUN_TEST(test_normalization_results_in_empty_plaintext);
80+
RUN_TEST(test_lowercase);
81+
RUN_TEST(test_remove_spaces);
82+
RUN_TEST(test_remove_punctuation);
83+
RUN_TEST(test_9_character_plaintext_results_in_3_chunks_of_3_characters);
84+
RUN_TEST(test_8_character_plaintext_results_in_3_chunks_the_last_one_with_a_trailing_space);
85+
RUN_TEST(test_54_character_plaintext_results_in_8_chunks_the_last_two_with_trailing_spaces);
86+
return UNITY_END();
87+
}

0 commit comments

Comments
 (0)