aboutsummaryrefslogtreecommitdiff
path: root/challenge-025
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2019-09-23 11:12:49 +0100
committerGitHub <noreply@github.com>2019-09-23 11:12:49 +0100
commit98a7ab6ebfcfa9425fbff18eef43b77d3ba64d5b (patch)
treeea153095bac5e294192b7e5744ec96c3d0517fa3 /challenge-025
parent9a7a969ebcb0058362faadd2a4df13f8289dc41c (diff)
parentb809d0e1f86602649b6468d305a2023c5c9571f8 (diff)
downloadperlweeklychallenge-club-98a7ab6ebfcfa9425fbff18eef43b77d3ba64d5b.tar.gz
perlweeklychallenge-club-98a7ab6ebfcfa9425fbff18eef43b77d3ba64d5b.tar.bz2
perlweeklychallenge-club-98a7ab6ebfcfa9425fbff18eef43b77d3ba64d5b.zip
Merge pull request #660 from dcw803/master
hi manwar, forgot to submit PR last night
Diffstat (limited to 'challenge-025')
-rw-r--r--challenge-025/duncan-c-white/README52
-rw-r--r--challenge-025/duncan-c-white/blog.txt1
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/ch-1.pl212
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v0.pl44
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v1.pl102
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v15.pl224
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v16-with-histo.pl278
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v16.pl227
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v17.pl220
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v18.pl219
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v19.pl214
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v2.pl106
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v20.pl212
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v3.pl108
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v4.pl115
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v5.pl125
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v6.pl127
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v7.pl178
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v8.pl191
-rwxr-xr-xchallenge-025/duncan-c-white/perl5/v9.pl186
20 files changed, 3112 insertions, 29 deletions
diff --git a/challenge-025/duncan-c-white/README b/challenge-025/duncan-c-white/README
index 4cd2bbfe01..49002c5fc3 100644
--- a/challenge-025/duncan-c-white/README
+++ b/challenge-025/duncan-c-white/README
@@ -1,36 +1,30 @@
-Challenge 1: "Create a script that prints nth order forward difference
-series. You should be a able to pass the list of numbers and order number
-as command line parameters. Let me show you with an example:
+Challenge 1: "Generate a longest sequence of the following "English Pokemon"
+ names where each name starts with the last letter of the previous name:
-Suppose we have list (X) of numbers: 5, 9, 2, 8, 1, 6 and we would like
-to create 1st order forward difference series (Y). So using the formula
-Y(i) = X(i+1) - X(i), we get the following numbers: (9-5), (2-9), (8-2),
-(1-8), (6-1), ie 4, -7, 6, -7, 5.
-If you noticed, it has one less number than the original series.
-Similarly you can generate the 2nd order forward difference series like:
-(-7-4), (6+7), (-7-6), (5+7) => -11, 13, -13, 12.
+ audino bagon baltoy banette bidoof braviary bronzor carracosta
+ charmeleon cresselia croagunk darmanitan deino emboar emolga
+ exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+ jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+ lumineon lunatone machamp magnezone mamoswine nosepass petilil
+ pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+ registeel relicanth remoraid rufflet sableye scolipede scrafty
+ seaking sealeo silcoon simisear snivy snorlax spoink starly
+ tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+ wartortle whismur wingull yamask"
-My notes: Clearly defined, very easy - let's have a go..
+My notes: Clearly defined, nice, potentially tricky, let's have a go -
+ and try some optimization experiments.
-Challenge 2: "Create a script that prints Prime Decomposition of a
-given number. The prime decomposition of a number is defined as a list
-of prime numbers which when all multiplied together, are equal to that
-number. For example, the Prime decomposition of 228 is 2,2,3,19 as 228 =
-2 * 2 * 3 * 19."
+Challenge 2: "Create script to implement Chaocipher. Please checkout
+https://en.wikipedia.org/wiki/Chaocipher for more information."
-My notes: So, prime factors then. Very easy again. In fact, haven't I
-already solved this in one of the other prime-based questions?
+My notes: That wikipedia page is very light on details, but refers you
+to the following PDF document for a full explanation:
+http://www.chaocipher.com/ActualChaocipher/Chaocipher-Revealed-Algorithm.pdf
-Challenge 3: "Write a script to use Random Poems API:
-https://www.poemist.com/api/v1/randompoems
-This is the easiset API, I have come across so far. You don't need API
-key for this. They have only route to work with (GET). The API task is
-optional but we would love to see your solution."
-
-My notes: ok, even I can't argue that obtaining an API key for an API
-I will literally never use again is too much hassle - when I don't need
-an API key, and the whole program appears to be an LWP::Simple get..
-
-update: well, apart from the Unicode in the response, complicating life.
+reading that, it gives a clear description of the algorithm. but then
+shows you the canonical solution - in beautifully clean Perl 5. So, umm,
+what is the point in me doing it again?
+I already solved this in one of the other prime-based questions?
diff --git a/challenge-025/duncan-c-white/blog.txt b/challenge-025/duncan-c-white/blog.txt
new file mode 100644
index 0000000000..03df97d466
--- /dev/null
+++ b/challenge-025/duncan-c-white/blog.txt
@@ -0,0 +1 @@
+https://www.doc.ic.ac.uk/~dcw/PSD/article13/
diff --git a/challenge-025/duncan-c-white/perl5/ch-1.pl b/challenge-025/duncan-c-white/perl5/ch-1.pl
new file mode 100755
index 0000000000..a8dc4aa651
--- /dev/null
+++ b/challenge-025/duncan-c-white/perl5/ch-1.pl
@@ -0,0 +1,212 @@
+#!/usr/bin/perl
+#
+# Challenge 1: "Generate a longest sequence of the following "English Pokemon"
+# names where each name starts with the last letter of the previous name:
+#
+# audino bagon baltoy banette bidoof braviary bronzor carracosta
+# charmeleon cresselia croagunk darmanitan deino emboar emolga
+# exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+# jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+# lumineon lunatone machamp magnezone mamoswine nosepass petilil
+# pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+# registeel relicanth remoraid rufflet sableye scolipede scrafty
+# seaking sealeo silcoon simisear snivy snorlax spoink starly
+# tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+# wartortle whismur wingull yamask"
+#
+# My notes: Clearly defined, nice, potentially tricky, let's do it.
+#
+# optimization v20: turned for loop that pushes into push map...
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug = @ARGV>0;
+
+my @words = qw(audino bagon baltoy banette bidoof braviary bronzor carracosta
+ charmeleon cresselia croagunk darmanitan deino emboar emolga
+ exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+ jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+ lumineon lunatone machamp magnezone mamoswine nosepass petilil
+ pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+ registeel relicanth remoraid rufflet sableye scolipede scrafty
+ seaking sealeo silcoon simisear snivy snorlax spoink starly
+ tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+ wartortle whismur wingull yamask);
+#@words = qw(hello ollie excellent thanks shelter runaround set to);
+
+#die scalar(@words);
+
+my %sw; # hash from letter L to list of word nos of words STARTING with L
+
+my @stopword;# list of stop word nos (word nos of words with no outwords)
+
+my %ew; # hash from letter L to list of word nos of words ENDING with L
+
+my @inword; # array from word no N to array of wordnos of words going "in"
+ # to word N, i.e. ending with the first letter of word N
+ # if there are no such words, then []
+
+# build %sw
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /^(.)/;
+ my $firstletter = $1;
+ $sw{$firstletter} //= [];
+ push @{$sw{$firstletter}}, $wn;
+}
+#die Dumper \%sw;
+
+# build %ew
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /(.)$/;
+ my $lastletter = $1;
+ $ew{$lastletter} //= [];
+ push @{$ew{$lastletter}}, $wn;
+}
+#die Dumper \%ew;
+
+# build @stopword, using %sw
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /(.)$/;
+ my $lastletter = $1;
+ my $aref = $sw{$lastletter} // [];
+ push @stopword, $wn if @$aref==0;
+}
+#die Dumper [ map { $words[$_] } @stopword ];
+
+# build @inword, using %ew
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /^(.)/;
+ my $firstletter = $1;
+ my $aref = $ew{$firstletter} // [];
+ $inword[$wn]= $aref;
+}
+#die Dumper \@inword;
+
+# No longer need %sw or %ew..
+undef %sw;
+undef %ew;
+
+my @seqs = findall();
+
+show_seqs( @seqs ) if $debug;
+
+exit 0;
+
+
+#
+# my @seqs = findall();
+# Find all sequences, starting with sequences of length 1 (stop words),
+# then working back, i.e. prepending words onto the front of existing
+# sequences.
+# Delivers the list of all maximal-length sequences, each sequence is
+# a comma-separated string of word numbers.
+#
+fun findall()
+{
+ my $currpaths = []; # list of all paths for sequences of length N
+ # each path entry is now a triple:
+ # [ inwordarrayref, seqstr, availarrayref ]
+ # note that seqstr, representing the sequence,
+ # is asingle string comprising the
+ # comma-separated list of word nos
+ my $N = 1; # length starts at 1 and is increased..
+
+ # convert each stopword word no into a path triple
+ @$currpaths = map { [ $inword[$_], $_, availset($_) ] } @stopword;
+ #die Dumper $currpaths;
+
+ for(;;)
+ {
+ #die Dumper $currpaths;
+ my $nseq = @$currpaths;
+ print "Have $nseq sequences of length $N\n";
+ #show_paths( @$currpaths );
+
+ #
+ # Now let's take every path of length N,
+ # and lengthen them to length n+1, by prepending a
+ # word number to the start of each sequence. This will
+ # be possible unless all sequences in currpaths are
+ # already at their maximal length - when that happens,
+ # we break out of the loop.
+ #
+ my $newpaths = []; # paths of length N+1
+ foreach my $path (@$currpaths) # foreach current path
+ {
+ my( $inwords, $s, $avail ) = @$path;
+
+ # extend path s by each unused word no in the inwords
+ push @$newpaths,
+ map {
+ # word no $_ no longer available.
+ my $newavail = $avail;
+ substr( $newavail, $_, 1 ) = 0;
+
+ # build a whole new path, length N+1
+ [ $inword[$_], "$_,$s", $newavail ]
+ }
+ grep { substr($avail,$_,1) eq '1' } @$inwords;
+ }
+ last if @$newpaths == 0;
+ $N++;
+ $currpaths = $newpaths;
+ #die Dumper $currpaths;
+ }
+
+ # now extract and return all the maximal length sequences
+ return map { $_->[1] } @$currpaths;
+}
+
+
+
+#
+# my $set = availset( $wno );
+# Form a set in which all word nos are available, except $wno.
+#
+fun availset( $wno )
+{
+ my $set = 1 x scalar(@words);
+ substr( $set, $wno, 1 ) = 0;
+ return $set;
+}
+
+
+#
+# show_paths( @paths );
+# Show the sequences (as words, not word nos) contained in @paths
+#
+fun show_paths( @paths )
+{
+ foreach my $p (@paths)
+ {
+ my $str = join( ',', map { $words[$_] } split(/,/,$p->[1]) );
+ say $str;
+ }
+}
+
+
+#
+# show_seqs( @seqs );
+# Show the sequence of word numbers (as words, not word nos)
+#
+fun show_seqs( @seqs )
+{
+ foreach my $s (@seqs)
+ {
+ my $str = join( ',', map { $words[$_] } split(/,/,$s) );
+ say $str;
+ }
+}
diff --git a/challenge-025/duncan-c-white/perl5/v0.pl b/challenge-025/duncan-c-white/perl5/v0.pl
new file mode 100755
index 0000000000..8172dd4212
--- /dev/null
+++ b/challenge-025/duncan-c-white/perl5/v0.pl
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+#
+# Challenge 1: "Generate a longest sequence of the following "English Pokemon"
+# names where each name starts with the last letter of the previous name:
+#
+# audino bagon baltoy banette bidoof braviary bronzor carracosta
+# charmeleon cresselia croagunk darmanitan deino emboar emolga
+# exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+# jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+# lumineon lunatone machamp magnezone mamoswine nosepass petilil
+# pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+# registeel relicanth remoraid rufflet sableye scolipede scrafty
+# seaking sealeo silcoon simisear snivy snorlax spoink starly
+# tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+# wartortle whismur wingull yamask"
+#
+# My notes: Clearly defined, nice, potentially tricky, let's do it.
+#
+# optimization v1: baseline code before starting to optimize: 32.6s.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+#use Data::Dumper;
+
+my $debug = @ARGV>0;
+
+my @words = qw(audino bagon baltoy banette bidoof braviary bronzor carracosta
+ charmeleon cresselia croagunk darmanitan deino emboar emolga
+ exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+ jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+ lumineon lunatone machamp magnezone mamoswine nosepass petilil
+ pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+ registeel relicanth remoraid rufflet sableye scolipede scrafty
+ seaking sealeo silcoon simisear snivy snorlax spoink starly
+ tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+ wartortle whismur wingull yamask);
+#@words = qw(hello ollie excellent thanks shelter runaround set to);
+
+say "Pokemon names starting with c:";
+my @startwords = grep { /^c/ } @words;
+say for @startwords;
diff --git a/challenge-025/duncan-c-white/perl5/v1.pl b/challenge-025/duncan-c-white/perl5/v1.pl
new file mode 100755
index 0000000000..b48b6a28b5
--- /dev/null
+++ b/challenge-025/duncan-c-white/perl5/v1.pl
@@ -0,0 +1,102 @@
+#!/usr/bin/perl
+#
+# Challenge 1: "Generate a longest sequence of the following "English Pokemon"
+# names where each name starts with the last letter of the previous name:
+#
+# audino bagon baltoy banette bidoof braviary bronzor carracosta
+# charmeleon cresselia croagunk darmanitan deino emboar emolga
+# exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+# jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+# lumineon lunatone machamp magnezone mamoswine nosepass petilil
+# pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+# registeel relicanth remoraid rufflet sableye scolipede scrafty
+# seaking sealeo silcoon simisear snivy snorlax spoink starly
+# tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+# wartortle whismur wingull yamask"
+#
+# My notes: Clearly defined, nice, potentially tricky, let's do it.
+#
+# optimization v1: baseline code before starting to optimize: 32.6s.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug = @ARGV>0;
+
+my @words = qw(audino bagon baltoy banette bidoof braviary bronzor carracosta
+ charmeleon cresselia croagunk darmanitan deino emboar emolga
+ exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+ jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+ lumineon lunatone machamp magnezone mamoswine nosepass petilil
+ pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+ registeel relicanth remoraid rufflet sableye scolipede scrafty
+ seaking sealeo silcoon simisear snivy snorlax spoink starly
+ tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+ wartortle whismur wingull yamask);
+#@words = qw(hello ollie excellent thanks shelter runaround set to);
+
+my %sw; # hash from letter to list of words starting with that letter.
+
+foreach my $word (@words)
+{
+ $word =~ /^(.)/;
+ my $letter = $1;
+ $sw{$letter} //= [];
+ push @{$sw{$letter}}, $word;
+}
+
+#die Dumper \%sw;
+
+my @longseq = (); # longest sequence found so far..
+
+# search for sequences starting with each word in turn..
+foreach my $sw (@words)
+{
+ findseq( $sw, () );
+}
+
+my $longest = @longseq;
+
+print "\nlongest sequence is length $longest: @longseq\n";
+exit 0;
+
+
+#
+# findseq( $currw, @seq );
+# Find all sequences of words from $currw onwards,
+# given that we've already visited words in @seq,
+# and update the global @longseq if any sequences
+# we find are longer than that.
+#
+fun findseq( $currw, @seq )
+{
+ push @seq, $currw; # extend @seq sequence
+
+ my %used = map { $_ => 1 } @seq; # convert to set
+
+ $currw =~ /(.)$/; # find the last letter of currw
+ my $lastletter = $1;
+
+ my $nextw = $sw{$lastletter}; # all words starting with lastletter
+ if( defined $nextw ) # if there are any, try each word
+ {
+ foreach my $nextword (@$nextw)
+ {
+ findseq( $nextword, @seq )
+ unless $used{$nextword};
+ }
+ } else # @seq is finished
+ {
+ #print "found sequence @seq\n";
+ my $len = @seq;
+ if( $len > @longseq )
+ {
+ print "longest seq so far (len $len): @seq\n" if $debug;
+ @longseq = @seq;
+ }
+ }
+}
diff --git a/challenge-025/duncan-c-white/perl5/v15.pl b/challenge-025/duncan-c-white/perl5/v15.pl
new file mode 100755
index 0000000000..156466391f
--- /dev/null
+++ b/challenge-025/duncan-c-white/perl5/v15.pl
@@ -0,0 +1,224 @@
+#!/usr/bin/perl
+#
+# Challenge 1: "Generate a longest sequence of the following "English Pokemon"
+# names where each name starts with the last letter of the previous name:
+#
+# audino bagon baltoy banette bidoof braviary bronzor carracosta
+# charmeleon cresselia croagunk darmanitan deino emboar emolga
+# exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+# jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+# lumineon lunatone machamp magnezone mamoswine nosepass petilil
+# pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+# registeel relicanth remoraid rufflet sableye scolipede scrafty
+# seaking sealeo silcoon simisear snivy snorlax spoink starly
+# tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+# wartortle whismur wingull yamask"
+#
+# My notes: Clearly defined, nice, potentially tricky, let's do it.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use Data::Dumper;
+
+my $debug = @ARGV>0;
+
+my @words = qw(audino bagon baltoy banette bidoof braviary bronzor carracosta
+ charmeleon cresselia croagunk darmanitan deino emboar emolga
+ exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+ jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+ lumineon lunatone machamp magnezone mamoswine nosepass petilil
+ pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+ registeel relicanth remoraid rufflet sableye scolipede scrafty
+ seaking sealeo silcoon simisear snivy snorlax spoink starly
+ tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+ wartortle whismur wingull yamask);
+#@words = qw(hello ollie excellent thanks shelter runaround set to);
+
+#die scalar(@words);
+
+my %sw; # hash from letter L to list of word nos of words STARTING with L
+
+my @outword; # array from word no N to array of wordnos of words going "out"
+ # from word N, i.e. starting with the last letter of word N
+ # if there are no such words, then []
+
+my @stopword;# list of stop word nos (word nos of words with no outwords)
+
+my %ew; # hash from letter L to list of word nos of words ENDING with L
+
+my @inword; # array from word no N to array of wordnos of words going "in"
+ # to word N, i.e. ending with the first letter of word N
+ # if there are no such words, then []
+
+# build %sw
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /^(.)/;
+ my $firstletter = $1;
+ $sw{$firstletter} //= [];
+ push @{$sw{$firstletter}}, $wn;
+}
+#die Dumper \%sw;
+
+# build %ew
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /(.)$/;
+ my $lastletter = $1;
+ $ew{$lastletter} //= [];
+ push @{$ew{$lastletter}}, $wn;
+}
+#die Dumper \%ew;
+
+# build @outword and @stopword, using %sw
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /(.)$/;
+ my $lastletter = $1;
+ my $aref = $sw{$lastletter} // [];
+ $outword[$wn]= $aref;
+ push @stopword, $wn if @$aref==0;
+}
+#die Dumper \@outword;
+#die Dumper [ map { $words[$_] } @stopword ];
+
+# build @inword, using %ew
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /^(.)/;
+ my $firstletter = $1;
+ my $aref = $ew{$firstletter} // [];
+ $inword[$wn]= $aref;
+}
+#die Dumper \@inword;
+
+# No longer need %sw or %ew..
+
+my @seqs = findall();
+
+show_seqs( @seqs ) if $debug;
+
+exit 0;
+
+
+#
+# my @seqs = findall();
+# Find all sequences, starting with sequences of length 1 (stop words),
+# then working back, i.e. prepending words onto the front of existing
+# sequences. Delivers the list of all maximal-length sequences.
+#
+fun findall( )
+{
+ my @sus; # array of two SU lists, sus[curr] stores the current
+ # list of all SUs for sequences of length N,
+ # sus[1-curr] builds the NEW list of
+ # all SUs for sequences of length N+1
+ # each SU entry is a [ seqarrayref, usedarrayref ] pair
+ my $N = 1; # length starts at 1 and is increased..
+ my $curr = 0; # start using sus[0] for curr, sus[1] for new..
+
+ # convert each stopword word no into a SU pair
+ @sus = ( [], [] );
+ @{$sus[0]} = map { [ [ $_ ], [ suset($_) ] ] } @stopword;
+
+ for(;;)
+ {
+ my $currsus = $sus[$curr];
+ #die Dumper $currsus;
+ my $nseq = @$currsus;
+ print "Have $nseq sequences of length $N\n";
+ #show_sus( @$currsus );
+
+ #
+ # Now let's take every SU (sequence and used set) in
+ # sus[curr], and lengthen them (storing the results
+ # in sus[1-curr]), prepending a word number to the start
+ # of each sequence. This will be possible unless all
+ # sequences in sus[curr] are already at their maximal
+ # length - when that happens, we break out of the loop.
+ #
+
+ my $newsus = $sus[1-$curr];
+ @$newsus = ();
+ foreach my $su (@$currsus) # foreach current SU
+ {
+ my( $s, $used ) = @$su;
+ my $firstwno = $s->[0];
+
+ # list of word nos into s[0]
+ my $list = $inword[$firstwno];
+
+ foreach my $wno (grep { ! $used->[$_] } @$list)
+ {
+ # make length N+1 sequence, cons(wno,oldseq)
+ my @oneseq = @$s;
+ unshift @oneseq, $wno;
+
+ # alter the used array, marking $wno used.
+ $used->[$wno] = 1;
+
+ # it's a whole new SU!
+ push @$newsus, [ \@oneseq, [ @$used ] ];
+
+ # alter used back
+ $used->[$wno] = 0;
+ }
+ }
+ last if @$newsus == 0;
+ $N++;
+ $curr = 1-$curr;
+ }
+
+ # now extract and return all the maximal length sequences
+
+ my $currsus = $sus[$curr];
+ return map { $_->[0] } @$currsus;
+}
+
+
+
+#
+# my @suset = suset( $wno );
+# Form a SUset in which all word nos are unused, except $wno.
+#
+fun suset( $wno )
+{
+ my @suset = (0) x scalar(@words);
+ $suset[$wno] = 1;
+ return @suset;
+}
+
+
+#
+# show_sus( @sus );
+# Show the sequences (as words, not word nos) contained in SUlist @sus
+#
+fun show_sus( @sus )
+{
+ foreach my $s (@sus)
+ {
+ my $str = join( ',', map { $words[$_->[0]] } @$s );
+ print "$str\n";
+ }
+}
+
+
+#
+# show_seqs( @seqs );
+# Show the sequences (as words, not word nos)
+#
+fun show_seqs( @seqs )
+{
+ foreach my $s (@seqs)
+ {
+ my $str = join( ',', map { $words[$_] } @$s );
+ print "$str\n";
+ }
+}
diff --git a/challenge-025/duncan-c-white/perl5/v16-with-histo.pl b/challenge-025/duncan-c-white/perl5/v16-with-histo.pl
new file mode 100755
index 0000000000..0a9650debb
--- /dev/null
+++ b/challenge-025/duncan-c-white/perl5/v16-with-histo.pl
@@ -0,0 +1,278 @@
+#!/usr/bin/perl
+#
+# Challenge 1: "Generate a longest sequence of the following "English Pokemon"
+# names where each name starts with the last letter of the previous name:
+#
+# audino bagon baltoy banette bidoof braviary bronzor carracosta
+# charmeleon cresselia croagunk darmanitan deino emboar emolga
+# exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+# jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+# lumineon lunatone machamp magnezone mamoswine nosepass petilil
+# pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+# registeel relicanth remoraid rufflet sableye scolipede scrafty
+# seaking sealeo silcoon simisear snivy snorlax spoink starly
+# tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+# wartortle whismur wingull yamask"
+#
+# My notes: Clearly defined, nice, potentially tricky, let's do it.
+#
+
+use v5.10; # to get "say"
+use strict;
+use warnings;
+use Function::Parameters;
+use Data::Dumper;
+use FindBin qw($Bin);
+
+use lib "$Bin/../lib";
+use lib "$ENV{HOME}/lib";
+use lib ".";
+use Histo;
+
+my $debug = @ARGV>0;
+
+my @words = qw(audino bagon baltoy banette bidoof braviary bronzor carracosta
+ charmeleon cresselia croagunk darmanitan deino emboar emolga
+ exeggcute gabite girafarig gulpin haxorus heatmor heatran ivysaur
+ jellicent jumpluff kangaskhan kricketune landorus ledyba loudred
+ lumineon lunatone machamp magnezone mamoswine nosepass petilil
+ pidgeotto pikachu pinsir poliwrath poochyena porygon2 porygonz
+ registeel relicanth remoraid rufflet sableye scolipede scrafty
+ seaking sealeo silcoon simisear snivy snorlax spoink starly
+ tirtouga trapinch treecko tyrogue vigoroth vulpix wailord
+ wartortle whismur wingull yamask);
+#@words = qw(hello ollie excellent thanks shelter runaround set to);
+
+#die scalar(@words);
+
+my %sw; # hash from letter L to list of word nos of words STARTING with L
+
+my @outword; # array from word no N to array of wordnos of words going "out"
+ # from word N, i.e. starting with the last letter of word N
+ # if there are no such words, then []
+
+my @stopword;# list of stop word nos (word nos of words with no outwords)
+
+my %ew; # hash from letter L to list of word nos of words ENDING with L
+
+my @inword; # array from word no N to array of wordnos of words going "in"
+ # to word N, i.e. ending with the first letter of word N
+ # if there are no such words, then []
+
+# build %sw
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /^(.)/;
+ my $firstletter = $1;
+ $sw{$firstletter} //= [];
+ push @{$sw{$firstletter}}, $wn;
+}
+#die Dumper \%sw;
+
+# build %ew
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /(.)$/;
+ my $lastletter = $1;
+ $ew{$lastletter} //= [];
+ push @{$ew{$lastletter}}, $wn;
+}
+#die Dumper \%ew;
+
+# build @outword and @stopword, using %sw
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /(.)$/;
+ my $lastletter = $1;
+ my $aref = $sw{$lastletter} // [];
+
+ # need to exclude $wn from @w if present
+ my @w = grep { $_ ne $wn } @$aref;
+
+ $outword[$wn]= \@w;
+ push @stopword, $wn if @w==0;
+}
+#die Dumper \@outword;
+#die Dumper [ map { $words[$_] } @stopword ];
+
+# build @inword, using %ew
+foreach my $wn (0..$#words)
+{
+ my $word = $words[$wn];
+ $word =~ /^(.)/;
+ my $firstletter = $1;
+ my $aref = $ew{$firstletter} // [];
+
+ # need to exclude $wn from @w if present
+ my @w = grep { $_ ne $wn } @$aref;
+
+ $inword[$wn]= \@w;
+}
+#die Dumper \@inword;
+
+# No longer need %sw or %ew..
+
+my @seqs = findall();
+
+show_seqs( @seqs ) if $debug;
+
+exit 0;
+
+
+#
+# my @seqs = findall();
+# Find all sequences, starting with sequences of length 1 (stop words),
+# then working back, i.e. prepending words onto the front of existing
+# sequences. Delivers the list of all maximal-length sequences.
+#
+fun findall( )
+{
+ my @sus; # array of two SU lists, sus[curr] stores the current
+ # list of all SUs for sequences of length N,
+ # sus[1-curr] builds the NEW list of
+ # all SUs for sequences of length N+1
+ # each SU entry is now a triple:
+ # [ firstwno, seqstr, usedarrayref ]
+ # (where the sequence is now seqstr, a single string
+ # comprising the comma-separated list of word nos,
+ # always starting with firstwno)
+ my $N = 1; # length starts at 1 and is increased..
+ my $curr = 0; # start using sus[0] for curr, sus[1] for new..
+
+ # convert each stopword word no into a SU triple
+ @sus = ( [], [] );
+ @{$sus[0]} = map { [ $_, $_, [ suset($_) ] ] } @stopword;
+
+ my $maxnused = 0;
+ my $total = 0;
+ my $outer = 0;
+ my $inner = 0;
+ my %freq;
+
+ my $histo = Histo->new( BINWIDTH => 1 );
+ my $histo2 = Histo->new( BINWIDTH => 1 );
+
+ for(;;)
+ {
+ my $currsus = $sus[$curr];
+ #die Dumper $currsus;
+ my $nseq = @$currsus;
+ print "Have $nseq sequences of length $N\n";
+ #show_sus( @$currsus );
+
+ #
+ # Now let's take every SU (firstwno/sequence/used set) in
+ # sus[curr], and lengthen them (storing the results
+ # in sus[1-curr]), prepending a word number to the start
+ # of each sequence. This will be possible unless all
+ # sequences in sus[curr] are already at their maximal
+ # length - when that happens, we break out of the loop.
+ #
+ my $newsus = $sus[1-$curr];
+ @$newsus = ();
+ foreach my $su (@$currsus) # foreach current SU
+ {
+ my( $firstwno, $s, $used ) = @$su;
+
+ # find the list of word nos into firstwno
+ my $list = $inword[$firstwno];
+
+$total += @$list;
+$outer++;
+
+my $nused = my @u = grep { $used->[$_] } @$list;
+$maxnused = $nused if $nused > $maxnused;
+#warn "found $nused used (@u), list=@$list, with firstwno=$firstwno, s=$s!!\n" if $nused > 0;
+#warn "all $nused used (@u), list=@$list, with firstwno=$firstwno, s=$s!!\n" if $nused>0 && $nused == @$list;
+
+ # for each unused word no going into firstwno
+ $histo2->add( scalar(@$list) );
+ my @x = grep { ! $used->[$_] } @$list;
+ # want histogram scalar(@x)
+ $histo->add( scalar(@x) );
+ $freq{ scalar(@x) }++;
+
+ foreach my $wno (@x)
+ {
+ $inn