aboutsummaryrefslogtreecommitdiff
path: root/challenge-038/dave-jacoby
diff options
context:
space:
mode:
authorDave Jacoby <jacoby.david@gmail.com>2019-12-10 18:59:59 -0500
committerDave Jacoby <jacoby.david@gmail.com>2019-12-10 18:59:59 -0500
commitc0b8e1b35874b7c7a8f8e352110c5c576e2fadb0 (patch)
tree304678c43f01b6ac59c025b854cff24948d73433 /challenge-038/dave-jacoby
parent0b62deca1509247bdda0bb45d529677343f7b578 (diff)
downloadperlweeklychallenge-club-c0b8e1b35874b7c7a8f8e352110c5c576e2fadb0.tar.gz
perlweeklychallenge-club-c0b8e1b35874b7c7a8f8e352110c5c576e2fadb0.tar.bz2
perlweeklychallenge-club-c0b8e1b35874b7c7a8f8e352110c5c576e2fadb0.zip
SOLVED!
Diffstat (limited to 'challenge-038/dave-jacoby')
-rw-r--r--challenge-038/dave-jacoby/blog.txt1
-rw-r--r--challenge-038/dave-jacoby/perl5/ch-1.pl59
-rw-r--r--challenge-038/dave-jacoby/perl5/ch-2.pl161
3 files changed, 221 insertions, 0 deletions
diff --git a/challenge-038/dave-jacoby/blog.txt b/challenge-038/dave-jacoby/blog.txt
new file mode 100644
index 0000000000..ff2f5895b1
--- /dev/null
+++ b/challenge-038/dave-jacoby/blog.txt
@@ -0,0 +1 @@
+https://jacoby.github.io/2019/12/10/words-and-dates-which-is-more-fun.html \ No newline at end of file
diff --git a/challenge-038/dave-jacoby/perl5/ch-1.pl b/challenge-038/dave-jacoby/perl5/ch-1.pl
new file mode 100644
index 0000000000..a0ba00dcd4
--- /dev/null
+++ b/challenge-038/dave-jacoby/perl5/ch-1.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use utf8;
+use feature qw{ postderef say signatures state switch };
+no warnings
+ qw{ experimental::postderef experimental::smartmatch experimental::signatures };
+
+use Carp;
+use DateTime;
+use Try::Tiny;
+
+# handle command-line input
+if (@ARGV) { say date_finder( $ARGV[0] ) }
+# testing data
+else {
+ for my $string (qw{2230120 1230120 1230231}) {
+ say date_finder($string)
+ }
+}
+exit;
+
+# break the date string into constituent parts, which will cause errors
+# if ill-formatted, and then feed that into DateTime, for formatting, but
+# also for catching non-existent dates, like 2220931, for example.
+sub date_finder ( $string ) {
+ my ( $century, $year, $month, $day ) = $string =~ m{
+ ^ # start of string
+ (\d) # century value 1-2
+ (\d{2}) # year value 00-99
+ (\d{2}) # month value 01-12
+ (\d{2}) # day value 01-31, plus
+ $ # end of string
+ }mx;
+
+ croak qq{Bad value: Century $century} if $century != 2 && $century != 1;
+ croak qq{Bad value: Month $month} if $month < 1 || $month > 12;
+ croak qq{Bad value: Day $day} if $day < 1 || $day > 31;
+
+ try {
+ # here we make a DateTime object with the values give us
+ # and if those values are invalid, DateTime croaks, which
+ # we catch
+ my $y = ( $century == 2 ? '19' : '20' ) . $year;
+ my $date = DateTime->new(
+ year => $y,
+ month => $month,
+ day => $day,
+ time_zone => 'floating'
+ );
+ return $date->ymd;
+ }
+ catch {
+ # catching the death of DateTime just to die our own way
+ # MIGHT be antisocial, but I accept it for now.
+ croak "Bad value: Input is not a day ($string)";
+ };
+}
diff --git a/challenge-038/dave-jacoby/perl5/ch-2.pl b/challenge-038/dave-jacoby/perl5/ch-2.pl
new file mode 100644
index 0000000000..5199c56bee
--- /dev/null
+++ b/challenge-038/dave-jacoby/perl5/ch-2.pl
@@ -0,0 +1,161 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+use utf8;
+use feature qw{ postderef say signatures state switch };
+no warnings
+ qw{ experimental::postderef experimental::smartmatch experimental::signatures };
+
+use List::Util qw{ sum0 uniq };
+use Getopt::Long;
+
+my $verbose = 0;
+GetOptions(
+ 'verbose' => \$verbose,
+);
+
+my @tiles = get_tiles();
+@tiles = sort @tiles;
+say join ' ', @tiles;
+say '-------------';
+
+my @list = permute_array(\@tiles);
+my @list2;
+
+for my $array ( @list ) {
+ for my $l ( 0 .. 6 ) {
+ state $dict;
+ my @array2 = map { $array->[$_] } 0 .. $l;
+ my $word2 = join '', @array2;
+ next if $dict->{$word2}++;
+ push @list2, \@array2;
+ }
+}
+
+my $best = '';
+my $top = 0;
+for my $r ( @list2 ) {
+ my $word = join '', $r->@*;
+ my $score = score_word($word);
+ next if $score <1;
+ say join "\t", '', $score,$word if $verbose;
+ if ( $score > $top ) {
+ $best = $word;
+ $top = $score;
+ }
+}
+
+say qq{ $best ($top)};
+
+sub permute_array ( $array ) {
+ return $array if scalar $array->@* == 1;
+ my @response = map {
+ my $i = $_;
+ my $d = $array->[$i];
+ my $copy->@* = $array->@*;
+ splice $copy->@*, $i, 1;
+ my @out = map { unshift $_->@*, $d; $_ } permute_array($copy);
+ @out
+ } 0 .. scalar $array->@* - 1;
+ return @response;
+}
+
+sub get_tiles {
+ state $counts = counts();
+ my @letters = split //, join '', map { $_ x $counts->{$_} } 'a' .. 'z';
+ my @output;
+ for ( 1 .. 7 ) {
+ my $n = int rand scalar @letters;
+ my $l = $letters[$n];
+ splice @letters, $n, 1;
+ push @output, $l;
+ }
+ return wantarray ? @output : \@output;
+}
+
+sub score_word( $word ) {
+ state $words = words();
+ state $counts = counts();
+ state $scores = scores();
+ return 0 unless length $word <= 7;
+ return 0 unless $words->{$word};
+ for my $letter ( 'a' .. 'z' ) {
+ if ( $word =~ /$letter/ ) {
+ my $count = () = $word =~ /$letter/gi;
+ return 0 if $count > $counts->{$letter};
+ }
+ }
+ return sum0 map { $scores->{$_} } split //, $word;
+}
+
+sub words {
+ my $file = '/usr/share/dict/words';
+ my $words;
+ if ( -f $file && open my $fh, '<', $file ) {
+ for my $word ( map { chomp; lc $_ } <$fh> ) {
+ $words->{$word} = 1;
+ }
+ }
+ return $words;
+}
+
+sub counts {
+ my $counts;
+ map { $counts->{$_} = 2 } qw{ k q x };
+ map { $counts->{$_} = 3 } qw{ d f g h j l o r v };
+ map { $counts->{$_} = 4 } qw{ c m n };
+ map { $counts->{$_} = 5 } qw{ b i p t u w y z };
+ map { $counts->{$_} = 7 } qw{ s };
+ map { $counts->{$_} = 8 } qw{ a };
+ map { $counts->{$_} = 9 } qw{ e };
+ return $counts;
+}
+
+sub scores {
+ my $scores;
+ map { $scores->{$_} = 1 } qw{ a g i s u x z };
+ map { $scores->{$_} = 2 } qw{ e j l r v y };
+ map { $scores->{$_} = 3 } qw{ f d p w };
+ map { $scores->{$_} = 4 } qw{ b n };
+ map { $scores->{$_} = 5 } qw{ t o h m c };
+ map { $scores->{$_} = 10 } qw{ k q };
+ return $scores;
+}
+
+__DATA__
+
+
+
+Lets assume we have tiles as listed below, with an alphabet (A..Z)
+printed on them. Each tile has a value, e.g. A (1 point),
+B (4 points) etc. You are allowed to draw 7 tiles from the
+lot randomly. Then try to form a word using the 7 tiles with
+maximum points altogether. You don’t have to use all the 7 tiles
+to make a word. You should try to use as many tiles as possible
+to get the maximum points.
+
+For example, A (x8) means there are 8 tiles with letter A.
+1 point
+
+ A (x8), G (x3), I (x5), S (x7), U (x5), X (x2), Z (x5)
+
+2 points
+
+ E (x9), J (x3), L (x3), R (x3), V (x3), Y (x5)
+
+3 points
+
+ F (x3), D (x3), P (x5), W (x5)
+
+4 points
+
+ B (x5), N (x4)
+
+5 points
+
+ T (x5), O (x3), H (x3), M (x4), C (x4)
+
+10 points
+
+ K (x2), Q (x2)