Skip to content

Commit

Permalink
Add rotational-cipher exercise (#690)
Browse files Browse the repository at this point in the history
  • Loading branch information
glennj authored Nov 18, 2024
1 parent e2fe854 commit 5705fb9
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 2
},
{
"slug": "rotational-cipher",
"name": "Rotational Cipher",
"uuid": "dbc46c87-97d4-4739-ad31-e9fbc2ec7c1e",
"practices": [],
"prerequisites": [],
"difficulty": 3
}
]
},
Expand Down
29 changes: 29 additions & 0 deletions exercises/practice/rotational-cipher/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Instructions

Create an implementation of the rotational cipher, also sometimes called the Caesar cipher.

The Caesar cipher is a simple shift cipher that relies on transposing all the letters in the alphabet using an integer key between `0` and `26`.
Using a key of `0` or `26` will always yield the same output due to modular arithmetic.
The letter is shifted for as many values as the value of the key.

The general notation for rotational ciphers is `ROT + <key>`.
The most commonly used rotational cipher is `ROT13`.

A `ROT13` on the Latin alphabet would be as follows:

```text
Plain: abcdefghijklmnopqrstuvwxyz
Cipher: nopqrstuvwxyzabcdefghijklm
```

It is stronger than the Atbash cipher because it has 27 possible keys, and 25 usable keys.

Ciphertext is written out in the same formatting as the input including spaces and punctuation.

## Examples

- ROT5 `omg` gives `trl`
- ROT0 `c` gives `c`
- ROT26 `Cool` gives `Cool`
- ROT13 `The quick brown fox jumps over the lazy dog.` gives `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.`
- ROT13 `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` gives `The quick brown fox jumps over the lazy dog.`
22 changes: 22 additions & 0 deletions exercises/practice/rotational-cipher/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"authors": [
"glennj"
],
"contributors": [
"m-dango"
],
"files": {
"solution": [
"lib/RotationalCipher.pm"
],
"test": [
"t/rotational-cipher.t"
],
"example": [
".meta/solutions/lib/RotationalCipher.pm"
]
},
"blurb": "Create an implementation of the rotational cipher, also sometimes called the Caesar cipher.",
"source": "Wikipedia",
"source_url": "https://en.wikipedia.org/wiki/Caesar_cipher"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package RotationalCipher;

use strict;
use warnings;
use experimental qw<signatures postderef postderef_qq>;

use Exporter qw<import>;
our @EXPORT_OK = qw<caesar_cipher>;

# from https://perldoc.pl/perlop#tr/SEARCHLIST/REPLACEMENTLIST/cdsr
# > Because the transliteration table is built at compile time, neither the
# > SEARCHLIST nor the REPLACEMENTLIST are subjected to double quote
# > interpolation. That means that if you want to use variables, you must
# > use an eval()

sub caesar_cipher ( $text, $shift ) {
my $alpha = 'abcdefghijklmnopqrstuvwxyz';
my $rotated = substr( $alpha, $shift % 26 ) . substr( $alpha, 0, $shift % 26 );
$alpha .= uc $alpha;
$rotated .= uc $rotated;

return eval "\$text =~ tr/$alpha/$rotated/r";
}

1;
33 changes: 33 additions & 0 deletions exercises/practice/rotational-cipher/.meta/template-data.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
subs: caesar_cipher
properties:
rotate:
test: |-
use Data::Dmp;
sprintf(<<'END', dmp($case->{input}{text}), $case->{input}{shiftKey}, dmp($case->{expected}), dmp($case->{description}));
is(
caesar_cipher(%s, %s),
%s,
%s
);
END
stub: |-
sub caesar_cipher ($text, $shift_key) {
return undef;
}
example: |-
# from https://perldoc.pl/perlop#tr/SEARCHLIST/REPLACEMENTLIST/cdsr
# > Because the transliteration table is built at compile time, neither the
# > SEARCHLIST nor the REPLACEMENTLIST are subjected to double quote
# > interpolation. That means that if you want to use variables, you must
# > use an eval()
sub caesar_cipher ($text, $shift) {
my $alpha = 'abcdefghijklmnopqrstuvwxyz';
my $rotated = substr($alpha, $shift % 26) . substr($alpha, 0, $shift % 26);
$alpha .= uc $alpha;
$rotated .= uc $rotated;
return eval "\$text =~ tr/$alpha/$rotated/r";
}
40 changes: 40 additions & 0 deletions exercises/practice/rotational-cipher/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 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.

[74e58a38-e484-43f1-9466-877a7515e10f]
description = "rotate a by 0, same output as input"

[7ee352c6-e6b0-4930-b903-d09943ecb8f5]
description = "rotate a by 1"

[edf0a733-4231-4594-a5ee-46a4009ad764]
description = "rotate a by 26, same output as input"

[e3e82cb9-2a5b-403f-9931-e43213879300]
description = "rotate m by 13"

[19f9eb78-e2ad-4da4-8fe3-9291d47c1709]
description = "rotate n by 13 with wrap around alphabet"

[a116aef4-225b-4da9-884f-e8023ca6408a]
description = "rotate capital letters"

[71b541bb-819c-4dc6-a9c3-132ef9bb737b]
description = "rotate spaces"

[ef32601d-e9ef-4b29-b2b5-8971392282e6]
description = "rotate numbers"

[32dd74f6-db2b-41a6-b02c-82eb4f93e549]
description = "rotate punctuation"

[9fb93fe6-42b0-46e6-9ec1-0bf0a062d8c9]
description = "rotate all letters"
12 changes: 12 additions & 0 deletions exercises/practice/rotational-cipher/lib/RotationalCipher.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package RotationalCipher;

use v5.40;

use Exporter qw<import>;
our @EXPORT_OK = qw<caesar_cipher>;

sub caesar_cipher ( $text, $shift_key ) {
return undef;
}

1;
69 changes: 69 additions & 0 deletions exercises/practice/rotational-cipher/t/rotational-cipher.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/usr/bin/env perl
use Test2::V0;

use FindBin qw<$Bin>;
use lib "$Bin/../lib", "$Bin/../local/lib/perl5";

use RotationalCipher qw<caesar_cipher>;

is( # begin: 74e58a38-e484-43f1-9466-877a7515e10f
caesar_cipher( "a", 0 ),
"a",
"rotate a by 0, same output as input"
); # end: 74e58a38-e484-43f1-9466-877a7515e10f

is( # begin: 7ee352c6-e6b0-4930-b903-d09943ecb8f5
caesar_cipher( "a", 1 ),
"b",
"rotate a by 1"
); # end: 7ee352c6-e6b0-4930-b903-d09943ecb8f5

is( # begin: edf0a733-4231-4594-a5ee-46a4009ad764
caesar_cipher( "a", 26 ),
"a",
"rotate a by 26, same output as input"
); # end: edf0a733-4231-4594-a5ee-46a4009ad764

is( # begin: e3e82cb9-2a5b-403f-9931-e43213879300
caesar_cipher( "m", 13 ),
"z",
"rotate m by 13"
); # end: e3e82cb9-2a5b-403f-9931-e43213879300

is( # begin: 19f9eb78-e2ad-4da4-8fe3-9291d47c1709
caesar_cipher( "n", 13 ),
"a",
"rotate n by 13 with wrap around alphabet"
); # end: 19f9eb78-e2ad-4da4-8fe3-9291d47c1709

is( # begin: a116aef4-225b-4da9-884f-e8023ca6408a
caesar_cipher( "OMG", 5 ),
"TRL",
"rotate capital letters"
); # end: a116aef4-225b-4da9-884f-e8023ca6408a

is( # begin: 71b541bb-819c-4dc6-a9c3-132ef9bb737b
caesar_cipher( "O M G", 5 ),
"T R L",
"rotate spaces"
); # end: 71b541bb-819c-4dc6-a9c3-132ef9bb737b

is( # begin: ef32601d-e9ef-4b29-b2b5-8971392282e6
caesar_cipher( "Testing 1 2 3 testing", 4 ),
"Xiwxmrk 1 2 3 xiwxmrk",
"rotate numbers"
); # end: ef32601d-e9ef-4b29-b2b5-8971392282e6

is( # begin: 32dd74f6-db2b-41a6-b02c-82eb4f93e549
caesar_cipher( "Let's eat, Grandma!", 21 ),
"Gzo'n zvo, Bmviyhv!",
"rotate punctuation"
); # end: 32dd74f6-db2b-41a6-b02c-82eb4f93e549

is( # begin: 9fb93fe6-42b0-46e6-9ec1-0bf0a062d8c9
caesar_cipher( "The quick brown fox jumps over the lazy dog.", 13 ),
"Gur dhvpx oebja sbk whzcf bire gur ynml qbt.",
"rotate all letters"
); # end: 9fb93fe6-42b0-46e6-9ec1-0bf0a062d8c9

done_testing;

0 comments on commit 5705fb9

Please sign in to comment.