aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-161/alexander-pankoff/perl/DictReader.pm30
-rw-r--r--challenge-161/alexander-pankoff/perl/My/List/Util.pm24
-rwxr-xr-xchallenge-161/alexander-pankoff/perl/ch-1.pl48
-rwxr-xr-xchallenge-161/alexander-pankoff/perl/ch-2.pl128
4 files changed, 230 insertions, 0 deletions
diff --git a/challenge-161/alexander-pankoff/perl/DictReader.pm b/challenge-161/alexander-pankoff/perl/DictReader.pm
new file mode 100644
index 0000000000..e1dd09f749
--- /dev/null
+++ b/challenge-161/alexander-pankoff/perl/DictReader.pm
@@ -0,0 +1,30 @@
+
+package DictReader;
+use strict;
+use warnings;
+use autodie;
+use feature qw'say state signatures';
+no warnings qw'experimental::signatures';
+
+use FindBin ();
+use File::Spec ();
+
+use Exporter qw(import);
+
+our @EXPORT_OK = qw(read_dict);
+
+use constant DICTIONARY =>
+ File::Spec->catfile( $FindBin::RealBin, qw/.. .. .. data dictionary.txt/ );
+
+sub read_dict() {
+ my @dict = slurp(DICTIONARY);
+}
+
+sub slurp($file) {
+ open( my $fh, '<', $file );
+ chomp( my @in = <$fh> );
+ close $fh;
+ return @in;
+}
+
+1;
diff --git a/challenge-161/alexander-pankoff/perl/My/List/Util.pm b/challenge-161/alexander-pankoff/perl/My/List/Util.pm
new file mode 100644
index 0000000000..c9957786da
--- /dev/null
+++ b/challenge-161/alexander-pankoff/perl/My/List/Util.pm
@@ -0,0 +1,24 @@
+package My::List::Util;
+
+use strict;
+use warnings;
+use feature qw'signatures';
+no warnings qw'experimental::signatures';
+
+use List::Util qw(reduce);
+use Exporter qw(import);
+
+our @EXPORT_OK = qw(group_by);
+
+sub group_by ( $fn, @xs ) {
+ reduce(
+ sub {
+ push @{ $a->{ $fn->($b) } }, $b;
+ return $a;
+ },
+ {},
+ @xs
+ );
+}
+
+1;
diff --git a/challenge-161/alexander-pankoff/perl/ch-1.pl b/challenge-161/alexander-pankoff/perl/ch-1.pl
new file mode 100755
index 0000000000..d7e1873dd8
--- /dev/null
+++ b/challenge-161/alexander-pankoff/perl/ch-1.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use autodie;
+use feature qw'say state signatures';
+no warnings qw'experimental::signatures';
+
+# Task 1: Abecedarian Words
+# Submitted by: Ryan J Thompson
+#
+# 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.
+#
+# Optionally, using only abecedarian words, leave a short comment in your code
+# to make your reviewer smile.
+
+use FindBin ();
+
+use lib $FindBin::RealBin;
+
+use DictReader qw(read_dict);
+use My::List::Util qw(group_by);
+
+run() unless caller();
+
+sub run() {
+ my @dict = read_dict();
+
+ # filter abecedarian words and group them by length.
+ my $abecedarian_by_length = group_by( sub($a) { return length $a },
+ grep( is_abecedarian($_), @dict ) );
+
+ # output them sorted by length (shortest first). Since the input dict is
+ # sorted lexically, all words of them same length will be output in lexical
+ # order as well.
+ say
+ for map { @{ $abecedarian_by_length->{$_} } }
+ sort { $a <=> $b } keys %{$abecedarian_by_length};
+}
+
+sub is_abecedarian($word) {
+
+ # To find out if a word is abecedarian we sort it lexically and compare to
+ # the input words.
+ return join( '', sort ( split( //, $word ) ) ) eq $word;
+}
diff --git a/challenge-161/alexander-pankoff/perl/ch-2.pl b/challenge-161/alexander-pankoff/perl/ch-2.pl
new file mode 100755
index 0000000000..374f797e0a
--- /dev/null
+++ b/challenge-161/alexander-pankoff/perl/ch-2.pl
@@ -0,0 +1,128 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use feature qw'say state signatures';
+no warnings qw'experimental::signatures';
+
+# Task 2: Pangrams
+# Submitted by: Ryan J Thompson
+#
+# 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:
+#
+# 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.
+#
+# 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.
+
+# BONUS: Constrain or optimize for something interesting (completely up to you),
+# such as:
+#
+# * Shortest possible pangram (difficult)
+# * Pangram which contains only abecedarian words (see challenge 1)
+# * 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 ...
+# * What is the longest possible pangram generated with this method? (All
+# solutions will contain 26 words, so focus on the letter count.)
+# * Pangrams that have the weirdest (PG-13) Google image search results
+# Anything interesting goes!
+
+use FindBin ();
+use File::Spec ();
+use List::Util qw(any max);
+
+use lib $FindBin::RealBin;
+
+use DictReader qw(read_dict);
+use My::List::Util qw(group_by);
+
+package challenge1 {
+ ## we want to reuse `is_abecedarian` from challenge 1
+
+ BEGIN {
+ require File::Spec->catfile( $FindBin::Bin, 'ch-1.pl' );
+ }
+}
+
+run() unless caller();
+
+sub run() {
+ my @dict = read_dict();
+
+ say find_pangram_naive(@dict);
+ say find_pangram_most_new_chars_used(@dict);
+
+ my @abecedarian = grep ( challenge1::is_abecedarian($_), @dict );
+
+ say find_pangram_naive(@abecedarian);
+ say find_pangram_most_new_chars_used(@abecedarian);
+}
+
+sub find_pangram_naive(@dict) {
+ ## Walks the dict in order. As soon as we encounter a word with unused
+ ## chars it is added to the pangram.
+
+ my @unused = 'a' .. 'z';
+ my @pangram;
+ for my $word (@dict) {
+ my @new_chars = grep { contains( $word, $_ ) } @unused;
+ push @pangram, $word if @new_chars;
+ @unused = without( \@unused, \@new_chars );
+ if ( !@unused ) {
+ return join( " ", @pangram );
+ }
+ }
+
+ die "No pangram found";
+}
+
+sub find_pangram_most_new_chars_used(@dict) {
+ ## In every step we find words with the most unused characters and add the
+ ## shorted to the pangram.
+
+ my @unused = 'a' .. 'z';
+
+ my @pangram;
+ while (@unused) {
+ my $cur = find_word_with_most_unused_chars( \@dict, \@unused );
+ @unused = without( \@unused, [ explode($cur) ] );
+ push @pangram, $cur;
+ }
+
+ return join( " ", @pangram );
+}
+
+sub find_word_with_most_unused_chars ( $dict, $unused ) {
+ my $words_by_unused = group_by(
+ sub ($word) {
+ scalar grep { contains( $word, $_ ) } @$unused;
+ },
+ @$dict
+ );
+
+ my $shortest = ( sort { length $a <=> length $b }
+ @{ $words_by_unused->{ max( keys %$words_by_unused ) } } )[0];
+
+ return $shortest;
+}
+
+sub contains ( $word, $char ) {
+ return $word =~ m/\Q$char\E/;
+}
+
+sub without ( $as, $bs ) {
+ grep {
+ my $a = $_;
+ !any { $_ eq $a } @$bs
+ } @$as;
+}
+
+sub explode($str) {
+ split( m//, $str );
+}