diff options
| author | Jörg Sommrey <28217714+jo-37@users.noreply.github.com> | 2023-03-27 20:39:23 +0200 |
|---|---|---|
| committer | Jörg Sommrey <28217714+jo-37@users.noreply.github.com> | 2023-04-19 17:15:36 +0200 |
| commit | ec262302b6392eae88df06834c81f54d725e2205 (patch) | |
| tree | ddd1345563c949eea40514124e0a0a37981e2150 | |
| parent | a3eb071a6c6b14e66f413c1cab3a6cbe76a6cfe3 (diff) | |
| download | perlweeklychallenge-club-ec262302b6392eae88df06834c81f54d725e2205.tar.gz perlweeklychallenge-club-ec262302b6392eae88df06834c81f54d725e2205.tar.bz2 perlweeklychallenge-club-ec262302b6392eae88df06834c81f54d725e2205.zip | |
Challenge 038 task 2
| -rwxr-xr-x | challenge-038/jo-37/perl/ch-2.pl | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/challenge-038/jo-37/perl/ch-2.pl b/challenge-038/jo-37/perl/ch-2.pl new file mode 100755 index 0000000000..2c695d2d8a --- /dev/null +++ b/challenge-038/jo-37/perl/ch-2.pl @@ -0,0 +1,103 @@ +#!/usr/bin/perl -s + +use v5.16; +use autodie; +use warnings; +use List::Util qw(sample sum); +use List::UtilsBy 'max_by'; + +use constant TILES => 7; +use constant DICT => '/usr/share/dict/words'; + +our ($help, $dict, $tiles); +$dict ||= DICT; +$tiles ||= TILES; + +die <<EOS if $help; +usage: $0 [-dict=DICTIONARY] [-tiles=TILES] [-help] + +-dict=DICTIONARY + read words from DICTIONARY. Default: /usr/share/dict/words + +-tiles=TILES + number of tiles taken from heap. + +-help + this help text + +EOS + + +### Input and Output + +main: { + my @selection = selection($tiles); + say "@selection"; + my ($score, $word) = word_game($dict, @selection); + say "$word ($score)"; +} + + +### Implementation + +sub word_game { + my $dictfile = shift; + my @matches; + open my $dict, '<', $dictfile; + while (<$dict>) { + # Prepare read word. + chomp; + $_ = uc $_; + # Build the initial content of a Bracketed Character class. A + # single character '!' is added that will never match and + # prevent the string from becoming empty. + my $board = '!' . join '', @_; + # Match the next character of the current word against the + # character class and remove the matched character. + $board =~ s/$1// while /\G([$board])/gc; + # Record the current word if it can be build from the letters on + # the board. + push @matches, $_ if /\G$/ + } + close $dict; + # Reverse the points-to-letter map into a letter-to-points map. + my $points = points(); + # Find the highest scored match. + my $best = max_by {score($points, $_)} @matches; + + # Return score and word. + (score($points, $best), $best) +} + +# Calculate the score of a word. +sub score { + my $points = shift; + sum map {$points->{$_}} split //, shift; +} + +BEGIN { + my %tiles = ( + 1 => [('A') x 8, ('G') x 3, ('I') x 5, ('S') x 7, ('U') x 5, + ('X') x 2, ('Z') x 5], + 2 => [('E') x 9, ('J') x 3, ('L') x 3, ('R') x 3, ('V') x 3, + ('Y') x 5], + 3 => [('F') x 3, ('D') x 3, ('P') x 5, ('W') x 5], + 4 => [('B') x 5, ('N') x 4], + 5 => [('T') x 5, ('O') x 3, ('H') x 3, ('M') x 4, ('C') x 4], + 10 => [('K') x 2, ('Q') x 2]); + + # Random selection of tiles. + sub selection { + my $tiles = shift; + sample $tiles, map {(@$_)} values %tiles; + } + + # Reverse the points-to-letter map into a letter-to-points map. + sub points { + my %points; + while (my ($p, $l) = each %tiles) { + $points{$_} = $p foreach @$l; + } + \%points; + } +} |
