Perl Weekly Challenge: Week 162

Challenge 1:


Write a script to generate the check digit of given ISBN-13 code. Please refer wikipedia for more information.

Example 1:
ISBN-13 check digit for '978-0-306-40615-7' is 7.

One feature I like a lot about Raku is you can do complex validation of parameters dirrectly in the function parameters. I used this in my solution to make sure it is passed a valid ISBN.

sub MAIN (
    Str $isbn where { /(\d ** 3) \- (\d) \- (\d ** 3) \- (\d ** 5) \- (\d) /} #= An ISBN in the format nnn-n-nnn-nnnnn-n
) {

Actually in some real books I looked at the ISBN did not contain hyphens. So to make this script robust I should have made them optional.

Then I took the captured parts from the ISBN, combined them into a string and then split that string ending up with an array of digits.

    my @digits = $/.list.join(q{}).comb;

Some digits in the ISBN have to be multiplied by 1 and some by 3. Rather than hard code each operation I made a table of multipliers which will be used in the next line.

    my @multipliers = (1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3);

We can ignore the 13th digit for now so we take a slice of the first 12 digits of the @digits array and multiply them with consecutive values from the @multipliers array using the Z* operator. This produces an array of results which are totalled together using the [+] operator. We take the modulus 10 of that total and subtract it from 10. That produces the check digit.

    my $checkdigit = 10 - ([+] (@digits[0 .. 11] Z* @multipliers)) % 10;

We print the expected check digit and compare it with the actual check digit (the 13th digit of the ISBN.) If the two are equal, this ia a valid ISBN otherwise it is invalid. This status is also printed.

    say $checkdigit, ($checkdigit == @digits[12] ?? ' (valid)' !! ' (invalid)');

(Full code on Github.)

As is often the case, most of the work in producing the Perl solution consisted of replacing features from Raku that Perl lacks. And as is happily also the case, that just means cutting and pasting code I already wrote for previous challenges. This time I dusted off the sum() and Zmultiply() functions to replace [+] and Z* respectively. The result was this:

my $isbn = shift // usage();

if ( $isbn !~ /(\d{3}) \- (\d) \- (\d{3}) \- (\d{5}) \- (\d) /msx ) {

my @digits = split //, (join q{}, @{^CAPTURE}); 
my @multipliers = (1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3);

my $checkdigit = 10 - sum([Zmultiply([@digits[0 .. 11]], \@multipliers)]) % 10;
say $checkdigit, ($checkdigit == $digits[12] ? ' (valid)' : ' (invalid)');

(Full code on Github.)

Challenge 2:


Implement encryption and decryption using the Wheatstone-Playfair cipher.

(These combine I and J, and use X as padding.)

encrypt("playfair example", "hide the gold in the tree stump") = "bmodzbxdnabekudmuixmmouvif"

decrypt("perl and raku", "siderwrdulfipaarkcrw") = "thewexeklychallengex"

Unfortunately, as I write this, I have run out of time to solve this challenge though I hope to do it soon.