aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorE. Choroba <choroba@matfyz.cz>2022-04-28 00:28:47 +0200
committerE. Choroba <choroba@matfyz.cz>2022-04-28 00:28:47 +0200
commitc574b6d326319822b7b319d2f61c30e49f8f08c3 (patch)
tree3df1c74e9cedb75499a2e62320afcc2a02900325
parent08aefdd0ab8feb7c00fe5ca9b23f67331dc3858e (diff)
downloadperlweeklychallenge-club-c574b6d326319822b7b319d2f61c30e49f8f08c3.tar.gz
perlweeklychallenge-club-c574b6d326319822b7b319d2f61c30e49f8f08c3.tar.bz2
perlweeklychallenge-club-c574b6d326319822b7b319d2f61c30e49f8f08c3.zip
Add solutions to 162: ISBN-13 & Wheatstone-Playfair by E. Choroba
-rwxr-xr-xchallenge-162/e-choroba/perl/ch-1.pl22
-rwxr-xr-xchallenge-162/e-choroba/perl/ch-2.pl95
2 files changed, 117 insertions, 0 deletions
diff --git a/challenge-162/e-choroba/perl/ch-1.pl b/challenge-162/e-choroba/perl/ch-1.pl
new file mode 100755
index 0000000000..c16b708909
--- /dev/null
+++ b/challenge-162/e-choroba/perl/ch-1.pl
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+use List::Util qw{ sum };
+
+sub isbn_13_check_digit {
+ my ($isbn) = @_;
+ $isbn =~ s/-//g;
+ substr $isbn, -1, 1, "" if 13 == length $isbn;
+ my $i = 0;
+ return 10 - ((sum(map $_ * (1 + 2 * ($i++ % 2)),
+ split //, $isbn)
+ % 10) || 10);
+}
+
+use Test::More tests => 3;
+
+is isbn_13_check_digit('978-0-306-40615-7'), 7, 'Example';
+
+is isbn_13_check_digit('978-0-306-40615'), 7, 'Without the last digit';
+is isbn_13_check_digit('978-3-16-148410-0'), 0, 'Another example';
diff --git a/challenge-162/e-choroba/perl/ch-2.pl b/challenge-162/e-choroba/perl/ch-2.pl
new file mode 100755
index 0000000000..d9ca336b63
--- /dev/null
+++ b/challenge-162/e-choroba/perl/ch-2.pl
@@ -0,0 +1,95 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+{ package Wheatstone::Playfair;
+ use Moo;
+
+ has alphabet => (is => 'lazy');
+
+ sub encrypt {
+ my ($self, $passphrase, $message) = @_;
+ $self->_crypt($passphrase, $message, 1);
+ }
+
+ sub decrypt {
+ my ($self, $passphrase, $message) = @_;
+ $self->_crypt($passphrase, $message, -1);
+ }
+
+ sub _crypt {
+ my ($self, $passphrase, $message, $step) = @_;
+
+ tr/A-Z/a-z/, s/[^a-z]//g, s/j/i/g for $passphrase, $message;
+
+ my %seen;
+ my $table_string = "";
+ for my $char (split //, $passphrase . $self->alphabet) {
+ unless ($seen{$char}++) {
+ $table_string .= $char;
+ }
+ }
+
+ my %table;
+ for my $y (0 .. 4) {
+ for my $x (0 .. 4) {
+ my $char = substr $table_string, 0, 1, "";
+ $table{$char} = [$x, $y];
+ $table{$x}{$y} = $char;
+ }
+ }
+
+ 1 while $message =~ s/^(?:..)*?\K(.)\1/$1x$1/;
+ $message .= 'x' if length($message) % 2;
+ my $out = "";
+ while (length $message) {
+ $message =~ s/^(.)(.{1}+)//;
+ my ($ch1, $ch2) = ($1, $2);
+ my ($x1, $y1) = @{ $table{$ch1} };
+ my ($x2, $y2) = @{ $table{$ch2} };
+ my ($ch1_out, $ch2_out);
+
+ if ($x1 != $x2 && $y1 != $y2) {
+ ($x1, $x2) = ($x2, $x1);
+ } elsif ($x1 == $x2) {
+ $_ = ($_ + $step) % 5 for $y1, $y2;
+ } else {
+ $_ = ($_ + $step) % 5 for $x1, $x2;
+ }
+
+ $ch1_out = $table{$x1}{$y1};
+ $ch2_out = $table{$x2}{$y2};
+ $out .= "$ch1_out$ch2_out";
+ }
+ return $out
+ }
+
+ sub _build_alphabet {
+ join "", grep $_ ne 'j', 'a' .. 'z'
+ }
+}
+
+use Test::More tests => 4;
+my $wp = 'Wheatstone::Playfair'->new;
+
+is $wp->encrypt('playfair example', 'hide the gold in the tree stump'),
+ 'bmodzbxdnabekudmuixmmouvif',
+ 'Example 1';
+
+is $wp->decrypt('perl and raku', 'siderwrdulfipaarkcrw'),
+ 'thewexeklychallengex',
+ 'Example 2';
+
+is $wp->decrypt(
+ 'playfair example',
+ $wp->encrypt('playfair example', 'hide the gold in the tree stump')
+ ),
+ 'hidethegoldinthetrexestump',
+ 'Roundtrip 1';
+
+is $wp->encrypt(
+ 'perl and raku',
+ $wp->decrypt('perl and raku', 'siderwrdulfipaarkcrw'),
+ ),
+ 'siderwrdulfipaarkcrw',
+ 'Roundtrip 2';