aboutsummaryrefslogtreecommitdiff
path: root/challenge-162
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2022-05-02 00:38:09 +0100
committerGitHub <noreply@github.com>2022-05-02 00:38:09 +0100
commitd51db3e52a7b29c245245e427d96237ba29237a2 (patch)
treeae2729324a7eea6b3960b1e961c5bf11b8a5caa5 /challenge-162
parentf677098515ea60add06ee12993635f9a7b974a7b (diff)
parent10d7f4ae073e07c0e18bf29cc07f310240bda2a2 (diff)
downloadperlweeklychallenge-club-d51db3e52a7b29c245245e427d96237ba29237a2.tar.gz
perlweeklychallenge-club-d51db3e52a7b29c245245e427d96237ba29237a2.tar.bz2
perlweeklychallenge-club-d51db3e52a7b29c245245e427d96237ba29237a2.zip
Merge pull request #6038 from dcw803/master
imported my solutions to this week's 2 tasks
Diffstat (limited to 'challenge-162')
-rw-r--r--challenge-162/duncan-c-white/C/.build2
-rw-r--r--challenge-162/duncan-c-white/C/Makefile13
-rw-r--r--challenge-162/duncan-c-white/C/README3
-rw-r--r--challenge-162/duncan-c-white/C/ch-1.c99
-rw-r--r--challenge-162/duncan-c-white/README57
-rwxr-xr-xchallenge-162/duncan-c-white/perl/ch-1.pl54
-rwxr-xr-xchallenge-162/duncan-c-white/perl/ch-2.pl181
7 files changed, 373 insertions, 36 deletions
diff --git a/challenge-162/duncan-c-white/C/.build b/challenge-162/duncan-c-white/C/.build
new file mode 100644
index 0000000000..7a8295430e
--- /dev/null
+++ b/challenge-162/duncan-c-white/C/.build
@@ -0,0 +1,2 @@
+BUILD = ch-1
+#CFLAGS = -g
diff --git a/challenge-162/duncan-c-white/C/Makefile b/challenge-162/duncan-c-white/C/Makefile
new file mode 100644
index 0000000000..61dae2a678
--- /dev/null
+++ b/challenge-162/duncan-c-white/C/Makefile
@@ -0,0 +1,13 @@
+BUILD = ch-1
+CC = gcc
+CFLAGS = #-g
+
+all: $(BUILD)
+
+clean:
+ /bin/rm -f $(BUILD) *.o core a.out
+
+ch-1: ch-1.o
+ $(CC) $(CFLAGS) ch-1.o -o ch-1
+
+ch-1.o: ch-1.c
diff --git a/challenge-162/duncan-c-white/C/README b/challenge-162/duncan-c-white/C/README
new file mode 100644
index 0000000000..61d52a58c0
--- /dev/null
+++ b/challenge-162/duncan-c-white/C/README
@@ -0,0 +1,3 @@
+Thought I'd also have a go at translating ch-1.pl into C..
+
+Produces identical (non-debugging) output to my ch-1.pl:-)
diff --git a/challenge-162/duncan-c-white/C/ch-1.c b/challenge-162/duncan-c-white/C/ch-1.c
new file mode 100644
index 0000000000..c263422dbf
--- /dev/null
+++ b/challenge-162/duncan-c-white/C/ch-1.c
@@ -0,0 +1,99 @@
+/*
+ * TASK #1 - ISBN-13
+ *
+ * Write a script to generate the check digit of given ISBN-13 code. Please
+ * refer to
+ *
+ * https://en.wikipedia.org/wiki/ISBN#ISBN-13_check_digit_calculation
+ *
+ * for more information. In summary, take each of the first 12 digits of
+ * an ISBN code, from left to right, multiple 1st, 3rd, 5th etc by 1, and
+ * the 2nd, 4th, 6th etc by 3, sum the result. Mod 10 the sum. Subtract
+ * the sum from 10. Mod 10 the result.
+ *
+ * Example
+ *
+ * ISBN-13 check digit for '978-0-306-40615-7' is 7.
+ *
+ * MY NOTES: ok. Pretty easy.
+ *
+ * GUEST LANGUAGE: THIS IS THE C VERSION.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+
+
+bool debug=false;
+
+
+int main( int argc, char **argv )
+{
+ if( argc != 2 )
+ {
+ fprintf( stderr, "Usage: isbn-13 isbn-number\n" );
+ exit(1);
+ }
+ char *input = argv[1];
+ char isbn[14];
+
+ // copy input to isbn, omitting the dashes
+ char *dst = isbn;
+ char *src = input;
+ while( *src )
+ {
+ if( *src != '-' )
+ {
+ *dst++ = *src;
+ }
+ src++;
+ }
+ if( debug )
+ {
+ printf( "debug: isbn w/o dashes = %s\n", isbn );
+ }
+
+ // chop off the last digit if len==13, check length
+ int len = strlen(isbn);
+ if( len==13 )
+ {
+ isbn[12] = '\0';
+ len--;
+ }
+ if( debug )
+ {
+ printf( "debug: isbn w/o checkdigit = %s\n", isbn );
+ }
+ if( len != 12 )
+ {
+ fprintf( stderr,
+ "isbn-checker: length of %s (should be 12) is %d\n",
+ isbn, len );
+ exit(1);
+ }
+
+ int scale = 3;
+ int total = 0;
+ for( src = isbn; *src; src++ )
+ {
+ scale = 4-scale;
+ total += scale * (*src-'0');
+ }
+ total %= 10;
+ total = 10-total;
+ total %= 10;
+
+ printf( "%d\n", total );
+
+ return 0;
+}
diff --git a/challenge-162/duncan-c-white/README b/challenge-162/duncan-c-white/README
index a10c12ba95..4b5c1a964f 100644
--- a/challenge-162/duncan-c-white/README
+++ b/challenge-162/duncan-c-white/README
@@ -1,52 +1,37 @@
-TASK #1 - Abecedarian Words
+TASK #1 - ISBN-13
-An abecedarian word is a word whose letters are arranged in alphabetical
-order. For example, 'knotty' is an abecedarian word, but 'knots'
-is not. Output or return a list of all abecedarian words in the
-dictionary, sorted in decreasing order of length.
+Write a script to generate the check digit of given ISBN-13 code. Please
+refer to
-Optionally, using only abecedarian words, leave a short comment in your code to make your reviewer smile.
-
-MY NOTES: ok. Pretty easy.
-
-GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl into C,
-look in the C directory for that.
+https://en.wikipedia.org/wiki/ISBN#ISBN-13_check_digit_calculation
+for more information. In summary, take each of the first 12 digits of
+an ISBN code, from left to right, multiple 1st, 3rd, 5th etc by 1, and
+the 2nd, 4th, 6th etc by 3, sum the result. Mod 10 the sum. Subtract
+the sum from 10. Mod 10 the result.
-TASK #2 - Pangrams
+Example
-A pangram is a sentence or phrase that uses every letter in the English
-alphabet at least once. For example, perhaps the most well known
-pangram is:
+ISBN-13 check digit for '978-0-306-40615-7' is 7.
-the quick brown fox jumps over the lazy dog
-
-Using the provided dictionary, so that you don't need to include
-individual copy, generate at least one pangram.
+MY NOTES: ok. Pretty easy.
-Your pangram does not have to be a syntactically valid English sentence
-(doing so would require far more work, and a dictionary of nouns, verbs,
-adjectives, adverbs, and conjunctions). Also note that repeated letters,
-and even repeated words, are permitted.
+GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl into C,
+look in the C directory for that.
-BONUS: Constrain or optimize for something interesting (completely up
-to you), such as:
-Shortest possible pangram (difficult)
+TASK #2 - Wheatstone-Playfair
-Pangram which contains only abecedarian words (see challenge 1)
+Implement encryption and decryption using the Wheatstone-Playfair cipher:
-Pangram such that each word "solves" exactly one new letter. For example,
-such a pangram might begin with (newly solved letters in bold):
- a ah hi hid die ice tea ...
+https://en.wikipedia.org/wiki/Playfair_cipher
- (What is the longest possible pangram generated with this method? All
- solutions will contain 26 words, so focus on the letter count.)
+Examples:
-Pangrams that have the weirdest (PG-13) Google image search results
+(These combine I and J, and use X as padding.)
-Anything interesting goes!
+encrypt("playfair example", "hide the gold in the tree stump") = "bmodzbxdnabekudmuixmmouvif"
+decrypt("perl and raku", "siderwrdulfipaarkcrw") = "thewexeklychallengex"
-MY NOTES: hmmm. Pretty easy to find a pangram in a brute force fashion,
-but anything more constrained sounds pretty hard.
+MY NOTES: hmmm. Not too hard.
diff --git a/challenge-162/duncan-c-white/perl/ch-1.pl b/challenge-162/duncan-c-white/perl/ch-1.pl
new file mode 100755
index 0000000000..2bcad8f22a
--- /dev/null
+++ b/challenge-162/duncan-c-white/perl/ch-1.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+#
+# TASK #1 - ISBN-13
+#
+# Write a script to generate the check digit of given ISBN-13 code. Please
+# refer to
+#
+# https://en.wikipedia.org/wiki/ISBN#ISBN-13_check_digit_calculation
+#
+# for more information. In summary, take each of the first 12 digits of
+# an ISBN code, from left to right, multiple 1st, 3rd, 5th etc by 1, and
+# the 2nd, 4th, 6th etc by 3, sum the result. Mod 10 the sum. Subtract
+# the sum from 10. Mod 10 the result.
+#
+# Example
+#
+# ISBN-13 check digit for '978-0-306-40615-7' is 7.
+#
+# MY NOTES: ok. Pretty easy.
+#
+# GUEST LANGUAGE: As a bonus, I also had a go at translating ch-1.pl into C,
+# look in the C directory for that.
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Data::Dumper;
+use List::Util qw(sum0);
+
+my $debug=0;
+die "Usage: isbn-13-checker [--debug] isbn-number\n"
+ unless GetOptions( "debug"=>\$debug ) && @ARGV==1;
+
+my $isbn = shift;
+$isbn =~ tr/-//d;
+my $len = length($isbn);
+if( $len==13 )
+{
+ $isbn =~ s/.$//;
+ $len--;
+}
+
+die "isbn-13 checker: $isbn (len $len) should be 12 chars long\n"
+ unless $len == 12;
+
+my $scale = 3;
+my $total = sum0( map { $scale = 4-$scale; $scale * $_; } split(//,$isbn) );
+$total %= 10;
+$total = 10-$total;
+$total %= 10;
+
+say $total;
diff --git a/challenge-162/duncan-c-white/perl/ch-2.pl b/challenge-162/duncan-c-white/perl/ch-2.pl
new file mode 100755
index 0000000000..b4e9ec6c5a
--- /dev/null
+++ b/challenge-162/duncan-c-white/perl/ch-2.pl
@@ -0,0 +1,181 @@
+#!/usr/bin/perl
+#
+# TASK #2 - Wheatstone-Playfair
+#
+# Implement encryption and decryption using the Wheatstone-Playfair cipher:
+#
+# https://en.wikipedia.org/wiki/Playfair_cipher
+#
+# Examples:
+#
+# (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"
+#
+# MY NOTES: hmmm. Not too hard.
+#
+
+use strict;
+use warnings;
+use feature 'say';
+use Getopt::Long;
+use Function::Parameters;
+use List::Util qw(min max);
+use Data::Dumper;
+
+my $debug=0;
+die "Usage: playfair-cipher [--debug] encrypt|decrypt sentence key\n"
+ unless GetOptions( "debug"=>\$debug ) && @ARGV==3;
+my( $mode, $text, $key ) = @ARGV;
+die "bad mode $mode\n" unless $mode eq "encrypt" || $mode eq "decrypt";
+
+=pod
+
+=head2 my @table = make_table( $key );
+
+Make the Playfair 5x5 table from the key.
+
+=cut
+fun make_table( $key )
+{
+ $key = uc($key);
+ $key =~ s/J/I/g;
+ $key =~ tr/ //d;
+
+ my %used = (); # set of letters we've used
+
+ my $tabstr;
+ foreach my $letter (split(//,$key))
+ {
+ next if $used{$letter};
+ $tabstr .= $letter;
+ $used{$letter}++;
+ }
+ $used{J}++ if $used{I};
+ $used{I}++ if $used{J};
+
+ foreach my $letter ('A'..'Z')
+ {
+ next if $used{$letter};
+ $tabstr .= $letter;
+ }
+
+ # convert $tabstr to the final table..
+ my $len = length($tabstr);
+ die "make_table: table string $tabstr (len $len) should be len 25\n"
+ unless $len == 25;
+ my @result = map { $tabstr =~ s/^(.....)//; $1; } 1..5;
+ return @result;
+}
+
+
+=pod
+
+=head2 my @pairs = split_pairs( $text );
+
+Split $text into 2-letter pairs, obeying the special
+Playfair rules described in the wikipedia page.
+
+=cut
+fun split_pairs( $text )
+{
+ $text = uc($text);
+ $text =~ tr/ //d;
+ my @result;
+ while( length($text)>0 )
+ {
+ my $len = length($text);
+ my $fst = substr($text,0,1);
+ my $scd = $len>1 ? substr($text,1,1) : 'X';
+ say "debug: text=$text, len=$len, fst=$fst, scd=$scd" if $debug;
+ if( $fst eq $scd )
+ {
+ push @result, "${fst}X";
+ $text =~ s/^.//;
+ } else
+ {
+ push @result, "$fst$scd";
+ $text =~ s/^..?//;
+ }
+ }
+ return @result;
+}
+
+
+=pod
+
+=head2 my( $r, $c ) = find_in_table( $letter, $tableref );
+
+Find $letter in the 5x5 table @$tableref, returning
+the ( row, column ) position.
+
+=cut
+fun find_in_table( $letter, $tableref )
+{
+ $letter = 'I' if $letter eq 'J';
+ foreach my $r (0..4)
+ {
+ foreach my $c (0..4)
+ {
+ return ( $r, $c ) if
+ $letter eq substr( $tableref->[$r], $c, 1 );
+ }
+ }
+}
+
+
+=pod
+
+=head2 my $ecpair = e_d( $pair, $tableref, $mode );
+
+Encrypt (or decrypt if $mode is 'decrypt') the
+given 2-letter pair $pair, using $tableref as
+a reference to the 5x5 table. Return the result.
+
+=cut
+fun e_d( $pair, $tableref, $mode )
+{
+ my $offset = 1;
+ $offset = -1 if $mode eq 'decrypt';
+
+ my $fst = substr($pair,0,1);
+ my $snd = substr($pair,1,1);
+ my( $fr, $fc ) = find_in_table( $fst, $tableref );
+ my( $sr, $sc ) = find_in_table( $snd, $tableref );
+ #die "debug e_d, pair=$pair, fst=$fst, snd=$snd, fr=$fr, fc=$fc, sr=$sr, sc=$sc\n";
+
+ if( $fr==$sr ) # on same row
+ {
+ $fc += $offset; $fc %= 5;
+ $sc += $offset; $sc %= 5;
+ return substr( $tableref->[$fr], $fc, 1 ).
+ substr( $tableref->[$fr], $sc, 1 );
+ } elsif( $fc==$sc ) # on same column
+ {
+ $fr += $offset; $fr %= 5;
+ $sr += $offset; $sr %= 5;
+ return substr( $tableref->[$fr], $fc, 1 ).
+ substr( $tableref->[$sr], $fc, 1 );
+ } else # form a rectangle
+ {
+ # (fr,fc) is one corner, (sr,sc) the other
+ return substr( $tableref->[$fr], $sc, 1 ).
+ substr( $tableref->[$sr], $fc, 1 );
+ }
+}
+
+
+my @table = make_table( $key );
+#die Dumper \@table;
+
+my @pairs = split_pairs( $text );
+#die Dumper \@pairs;
+
+my $result = "";
+foreach my $pair (@pairs)
+{
+ $result .= e_d( $pair, \@table, $mode );
+}
+say $result;