diff options
| author | E. Choroba <choroba@matfyz.cz> | 2022-04-28 00:28:47 +0200 |
|---|---|---|
| committer | E. Choroba <choroba@matfyz.cz> | 2022-04-28 00:28:47 +0200 |
| commit | c574b6d326319822b7b319d2f61c30e49f8f08c3 (patch) | |
| tree | 3df1c74e9cedb75499a2e62320afcc2a02900325 | |
| parent | 08aefdd0ab8feb7c00fe5ca9b23f67331dc3858e (diff) | |
| download | perlweeklychallenge-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-x | challenge-162/e-choroba/perl/ch-1.pl | 22 | ||||
| -rwxr-xr-x | challenge-162/e-choroba/perl/ch-2.pl | 95 |
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'; |
