diff --git a/config.json b/config.json index 17f89b1..5dd8e4f 100644 --- a/config.json +++ b/config.json @@ -234,6 +234,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "crypto-square", + "name": "Crypto Square", + "uuid": "de268eb1-66a8-4094-b19f-25da515fb7ac", + "practices": [], + "prerequisites": [], + "difficulty": 7 + }, { "slug": "nth-prime", "name": "Nth Prime", diff --git a/exercises/practice/crypto-square/.docs/hints.md b/exercises/practice/crypto-square/.docs/hints.md new file mode 100644 index 0000000..52d65b0 --- /dev/null +++ b/exercises/practice/crypto-square/.docs/hints.md @@ -0,0 +1,6 @@ +# Hints + +## General + +- The `$t0-9` registers can be used to temporarily store values +- The instructions specify which registers are used as input and output diff --git a/exercises/practice/crypto-square/.docs/instructions.append.md b/exercises/practice/crypto-square/.docs/instructions.append.md new file mode 100644 index 0000000..1e66ce6 --- /dev/null +++ b/exercises/practice/crypto-square/.docs/instructions.append.md @@ -0,0 +1,9 @@ +# Instructions append + +## Registers + +| Register | Usage | Type | Description | +| -------- | ------------ | ------- | ----------------------------- | +| `$a0` | input | address | null-terminated input string | +| `$a1` | input/output | address | null-terminated output string | +| `$t0-9` | temporary | any | used for temporary storage | diff --git a/exercises/practice/crypto-square/.docs/instructions.md b/exercises/practice/crypto-square/.docs/instructions.md new file mode 100644 index 0000000..6c3826e --- /dev/null +++ b/exercises/practice/crypto-square/.docs/instructions.md @@ -0,0 +1,71 @@ +# Instructions + +Implement the classic method for composing secret messages called a square code. + +Given an English text, output the encoded version of that text. + +First, the input is normalized: the spaces and punctuation are removed from the English text and the message is down-cased. + +Then, the normalized characters are broken into rows. +These rows can be regarded as forming a rectangle when printed with intervening newlines. + +For example, the sentence + +```text +"If man was meant to stay on the ground, god would have given us roots." +``` + +is normalized to: + +```text +"ifmanwasmeanttostayonthegroundgodwouldhavegivenusroots" +``` + +The plaintext should be organized into a rectangle as square as possible. +The size of the rectangle should be decided by the length of the message. + +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: + +- `r * c >= length of message`, +- and `c >= r`, +- and `c - r <= 1`. + +Our normalized text is 54 characters long, dictating a rectangle with `c = 8` and `r = 7`: + +```text +"ifmanwas" +"meanttos" +"tayonthe" +"groundgo" +"dwouldha" +"vegivenu" +"sroots " +``` + +The coded message is obtained by reading down the columns going left to right. + +The message above is coded as: + +```text +"imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau" +``` + +Output the encoded text in chunks that fill perfect rectangles `(r X c)`, with `c` chunks of `r` length, separated by spaces. +For phrases that are `n` characters short of the perfect rectangle, pad each of the last `n` chunks with a single trailing space. + +```text +"imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " +``` + +Notice that were we to stack these, we could visually decode the ciphertext back in to the original message: + +```text +"imtgdvs" +"fearwer" +"mayoogo" +"anouuio" +"ntnnlvt" +"wttddes" +"aohghn " +"sseoau " +``` diff --git a/exercises/practice/crypto-square/.meta/config.json b/exercises/practice/crypto-square/.meta/config.json new file mode 100644 index 0000000..e56dbfb --- /dev/null +++ b/exercises/practice/crypto-square/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "impl.mips" + ], + "test": [ + "runner.mips" + ], + "example": [ + ".meta/example.mips" + ] + }, + "blurb": "Implement the classic method for composing secret messages called a square code.", + "source": "J Dalbey's Programming Practice problems", + "source_url": "https://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html" +} diff --git a/exercises/practice/crypto-square/.meta/example.mips b/exercises/practice/crypto-square/.meta/example.mips new file mode 100644 index 0000000..72b0c34 --- /dev/null +++ b/exercises/practice/crypto-square/.meta/example.mips @@ -0,0 +1,96 @@ +# | Register | Usage | Type | Description | +# | -------- | ------------ | ------- | ---------------------------------- | +# | `$a0` | input | address | null-terminated input string | +# | `$a1` | input/output | address | null-terminated output string | +# | `$t0` | temporary | integer | count of alphanumeric characters | +# | `$t1` | temporary | integer | number of input columns | +# | `$t2` | temporary | integer | number of input rows, plus 1 | +# | `$t3` | temporary | integer | product, then output row number | +# | `$t4` | temporary | address | start of input string | +# | `$t5` | temporary | address | pointer into output | +# | `$t6` | temporary | byte | '0' | +# | `$t7` | temporary | byte | '9' | +# | `$t8` | temporary | byte | 'a' | +# | `$t9` | temporary | byte | 'z' | +# | `$v0` | temporary | byte | character in string | +# | `$v1` | temporary | address | return address | + +.globl ciphertext + +ciphertext: + move $v1, $ra # save return address + move $t4, $a0 # start of input string + li $t6, '0' + li $t7, '9' + li $t8, 'a' + li $t9, 'z' + + li $t0, -1 +count_alphanumeric: + addi $t0, $t0, 1 # count of alphanumeric characters + jal get_input # return next alphanumeric, or null terminator + bnez $v0, count_alphanumeric + + beqz $t0, return_empty # output an empty string when count is 0 + move $a0, $t4 # start of input string + + move $t1, $zero +increment_columns: + addi $t1, $t1, 1 # number of columns + mulu $t3, $t1, $t1 + blt $t3, $t0, increment_columns # repeat while columns * column < count + + subi $t2, $t1, 2 +increment_rows: + addi $t2, $t2, 1 # number of rows + mulu $t3, $t2, $t1 + blt $t3, $t0, increment_rows # repeat while rows * column < count + + add $t3, $t3, $t1 + subi $t3, $t3, 1 # output length is (rows + 1) * columns - 1 + + addi $t2, $t2, 1 # rows + 1 + add $t5, $a1, $t3 + sb $zero, 0($t5) # write null terminator + li $v0, ' ' + +write_space: + subi $t5, $t5, 1 + sb $v0, 0($t5) + bne $t5, $a1, write_space + +next_output_column: + move $t5, $a1 + addi $a1, $a1, 1 + + move $t3, $zero +next_output_row: + addi $t3, $t3, 1 # 1-based output row number + jal get_input + sb $v0, 0($t5) # output alphanumeric byte + subi $t0, $t0, 1 + beqz $t0, return # return when decremented count is 0 + add $t5, $t5, $t2 + blt $t3, $t1, next_output_row + j next_output_column + +return_empty: + sb $zero, 0($a1) # write null terminator + +return: + jr $v1 + +check_input: + blt $v0, $t6, get_input # reject if < '0' + ble $v0, $t7, accept_input # accept if numeric + ori $v0, 0x20 # convert to lower case + blt $v0, $t8, get_input # reject if < 'a' + ble $v0, $t9, accept_input # accept if alphabetic + +get_input: + lb $v0, 0($a0) # read input byte + addi $a0, $a0, 1 + bnez $v0, check_input + +accept_input: + jr $ra diff --git a/exercises/practice/crypto-square/.meta/tests.toml b/exercises/practice/crypto-square/.meta/tests.toml new file mode 100644 index 0000000..085d142 --- /dev/null +++ b/exercises/practice/crypto-square/.meta/tests.toml @@ -0,0 +1,34 @@ +# 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. + +[407c3837-9aa7-4111-ab63-ec54b58e8e9f] +description = "empty plaintext results in an empty ciphertext" + +[aad04a25-b8bb-4304-888b-581bea8e0040] +description = "normalization results in empty plaintext" + +[64131d65-6fd9-4f58-bdd8-4a2370fb481d] +description = "Lowercase" + +[63a4b0ed-1e3c-41ea-a999-f6f26ba447d6] +description = "Remove spaces" + +[1b5348a1-7893-44c1-8197-42d48d18756c] +description = "Remove punctuation" + +[8574a1d3-4a08-4cec-a7c7-de93a164f41a] +description = "9 character plaintext results in 3 chunks of 3 characters" + +[a65d3fa1-9e09-43f9-bcec-7a672aec3eae] +description = "8 character plaintext results in 3 chunks, the last one with a trailing space" + +[fbcb0c6d-4c39-4a31-83f6-c473baa6af80] +description = "54 character plaintext results in 7 chunks, the last two with trailing spaces" diff --git a/exercises/practice/crypto-square/impl.mips b/exercises/practice/crypto-square/impl.mips new file mode 100644 index 0000000..b399170 --- /dev/null +++ b/exercises/practice/crypto-square/impl.mips @@ -0,0 +1,10 @@ +# | Register | Usage | Type | Description | +# | -------- | ------------ | ------- | ----------------------------- | +# | `$a0` | input | address | null-terminated input string | +# | `$a1` | input/output | address | null-terminated output string | +# | `$t0-9` | temporary | any | used for temporary storage | + +.globl ciphertext + +ciphertext: + jr $ra diff --git a/exercises/practice/crypto-square/runner.mips b/exercises/practice/crypto-square/runner.mips new file mode 100644 index 0000000..3ab01e5 --- /dev/null +++ b/exercises/practice/crypto-square/runner.mips @@ -0,0 +1,136 @@ +# +# Test ciphertext with some examples +# +# a0 - input string, for callee +# a1 - pointer to output string, for callee +# s0 - num of tests left to run +# s1 - address of input string +# s2 - address of expected output string +# s3 - copy of output location +# t0 - char byte of expected output +# t1 - char byte of actual output + +.eqv BUFFER_SIZE 64 + +.data + +# number of test cases +n: .word 8 +# input values (null terminated) +ins: .asciiz + "", + "... --- ...", + "A", + " b ", + "@1,%!", + "This is fun!", + "Chill out.", + "If man was meant to stay on the ground, god would have given us roots." +# expected output values (null terminated) +outs: .asciiz + "", + "", + "a", + "b", + "1", + "tsf hiu isn", + "clu hlt io ", + "imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau " + +failmsg: .asciiz "failed for test input: \"" +expectedmsg: .asciiz "\". expected \"" +tobemsg: .asciiz "\" to be \"" +endmsg: .asciiz "\"." +okmsg: .asciiz "all tests passed" + + +.text + +runner: + lw $s0, n + la $s1, ins + la $s2, outs + + li $v0, 9 # code for allocating heap memory + li $a0, BUFFER_SIZE # specify length of longest expected output + syscall + move $s3, $v0 # location of allocated memory is where callee writes + +run_test: + jal clear_output # zero out output location + move $a0, $s1 # load input value into a0 + move $a1, $s3 # load destination address into a1 + jal ciphertext # call subroutine under test + move $a1, $s3 + move $s4, $s2 # expected output string + +scan: + lb $t0, 0($s2) # load one byte of the expectation + lb $t1, 0($a1) # load one byte of the actual + bne $t0, $t1, exit_fail # if the two differ, the test has failed + addi $s2, $s2, 1 # point to next expectation byte + addi $a1, $a1, 1 # point to next actual byte + bne $t0, $zero, scan # if one char (and therefore the other) was not null, loop + +input_scan: + lb $t0, 0($s1) + addi $s1, $s1, 1 + bne $t0, $zero, input_scan + +done_scan: + sub $s0, $s0, 1 # decrement num of tests left to run + bgt $s0, $zero, run_test # if more than zero tests to run, jump to run_test + +exit_ok: + la $a0, okmsg # put address of okmsg into a0 + li $v0, 4 # 4 is print string + syscall + + li $v0, 10 # 10 is exit with zero status (clean exit) + syscall + +exit_fail: + la $a0, failmsg # put address of failmsg into a0 + li $v0, 4 # 4 is print string + syscall + + move $a0, $s1 # print input that failed on + li $v0, 4 + syscall + + la $a0, expectedmsg + li $v0, 4 + syscall + + move $a0, $s3 # print actual that failed on + li $v0, 4 + syscall + + la $a0, tobemsg + li $v0, 4 + syscall + + move $a0, $s4 # print expected value that failed on + li $v0, 4 + syscall + + la $a0, endmsg + li $v0, 4 + syscall + + li $a0, 1 # set error code to 1 + li $v0, 17 # 17 is exit with error + syscall + +clear_output: + # zero out output by storing zeros + addi $t0, $s3, BUFFER_SIZE # pointer to end of output buffer + +clear: + subi $t0, $t0, 4 # decrement pointer + sw $zero, 0($t0) # store a 0 word + bne $t0, $s3, clear # repeat util we have reached the start of the buffer + jr $ra + +# # Include your implementation here if you wish to run this from the MARS GUI. +# .include "impl.mips"