aboutsummaryrefslogtreecommitdiff
path: root/challenge-161
diff options
context:
space:
mode:
authorFlavio Poletti <flavio@polettix.it>2022-04-19 22:36:47 +0200
committerFlavio Poletti <flavio@polettix.it>2022-04-19 22:36:47 +0200
commitb6961c307f4f474347720f3c25044652ecce060e (patch)
tree7426f01cb8e920ebc7402908eaa9031010eb6dcd /challenge-161
parentccb9e0b8e0008e5fa71768a88620ec0478a8ffaf (diff)
downloadperlweeklychallenge-club-b6961c307f4f474347720f3c25044652ecce060e.tar.gz
perlweeklychallenge-club-b6961c307f4f474347720f3c25044652ecce060e.tar.bz2
perlweeklychallenge-club-b6961c307f4f474347720f3c25044652ecce060e.zip
Add polettix's solution to challenge-161
Diffstat (limited to 'challenge-161')
-rw-r--r--challenge-161/polettix/blog.txt1
-rw-r--r--challenge-161/polettix/blog1.txt1
-rw-r--r--challenge-161/polettix/perl/ch-1.pl20
-rw-r--r--challenge-161/polettix/perl/ch-2.pl65
-rw-r--r--challenge-161/polettix/raku/ch-1.raku19
-rw-r--r--challenge-161/polettix/raku/ch-2.raku56
6 files changed, 162 insertions, 0 deletions
diff --git a/challenge-161/polettix/blog.txt b/challenge-161/polettix/blog.txt
new file mode 100644
index 0000000000..a3ed1c7ff8
--- /dev/null
+++ b/challenge-161/polettix/blog.txt
@@ -0,0 +1 @@
+https://github.polettix.it/ETOOBUSY/2022/04/19/pwc161-abecedarian-words/
diff --git a/challenge-161/polettix/blog1.txt b/challenge-161/polettix/blog1.txt
new file mode 100644
index 0000000000..e9277bccbf
--- /dev/null
+++ b/challenge-161/polettix/blog1.txt
@@ -0,0 +1 @@
+https://github.polettix.it/ETOOBUSY/2022/04/20/pwc161-pangrams/
diff --git a/challenge-161/polettix/perl/ch-1.pl b/challenge-161/polettix/perl/ch-1.pl
new file mode 100644
index 0000000000..6df98b1cf7
--- /dev/null
+++ b/challenge-161/polettix/perl/ch-1.pl
@@ -0,0 +1,20 @@
+#!/usr/bin/env perl
+use v5.24;
+use warnings;
+use experimental 'signatures';
+no warnings 'experimental::signatures';
+
+say join ' ', all_sorted_abecedarian_in(shift);
+
+sub all_sorted_abecedarian_in ($dictionary) {
+ sort { length($a) <=> length($b) } all_abecedarian_in($dictionary);
+}
+
+sub all_abecedarian_in ($dictionary) {
+ open my $fh, '<:encoding(utf-8)', $dictionary or die "open(): $!\n";
+ grep { is_abecedarian($_) } map { s{\s+\z}{}rmxs } readline $fh;
+}
+
+sub is_abecedarian ($word) {
+ fc $word eq join '', sort split m{}mxs, fc $word;
+}
diff --git a/challenge-161/polettix/perl/ch-2.pl b/challenge-161/polettix/perl/ch-2.pl
new file mode 100644
index 0000000000..3dd7ee14ee
--- /dev/null
+++ b/challenge-161/polettix/perl/ch-2.pl
@@ -0,0 +1,65 @@
+#!/usr/bin/env perl
+use v5.24;
+use warnings;
+use experimental 'signatures';
+no warnings 'experimental::signatures';
+
+use HTTP::Tiny;
+use constant DEFAULT_BOOK_URL =>
+ 'https://www.gutenberg.org/cache/epub/308/pg308.txt';
+use FindBin '$Bin';
+use List::Util 'sum';
+
+# Assume Unixish filesystem
+my $dictionary_file = shift // "$Bin/../../../data/dictionary.txt";
+my $book_url = shift // DEFAULT_BOOK_URL;
+
+my $dictionary = read_dictionary($dictionary_file);
+my $book = get_stuff($book_url);
+my $model = markov_model($book, $dictionary);
+
+my ($src, $word, %hits, @trail);
+while (keys(%hits) < 26) {
+ $src = $model->{$word // ''} // $dictionary;
+ push @trail, $word = random_word_draw($src);
+ ++$hits{$_} for split m{}mxs, $word;
+}
+
+say join ' ', @trail;
+
+sub random_word_draw ($weighted_candidates) {
+ my $total = sum values $weighted_candidates->%*;
+ my $draw = rand $total; # definitely space for improvement...
+ for my $word (keys $weighted_candidates->%*) {
+ $draw -= $weighted_candidates->{$word};
+ return $word if $draw < 0;
+ }
+ die "unreached, hopefully\n";
+}
+
+sub read_dictionary ($filename) {
+ open my $fh, '<:encoding(utf-8)', $filename or die "open(): $!\n";
+ return { map {chomp; $_ => 1} readline $fh };
+}
+
+sub get_stuff ($url) {
+ my $response = HTTP::Tiny->new->get($url);
+ die "$response->{status} $response->{reason}\n"
+ unless $response->{success};
+ return $response->{content};
+}
+
+sub markov_model ($text, $dictionary) {
+ my $previous = undef;
+ my %successors_for;
+ for my $word (split m{[^a-z]+}mxs, lc $text) {
+ if ($dictionary->{$word}) {
+ $successors_for{$previous}{$word}++ if defined $previous;
+ $previous = $word;
+ }
+ else {
+ $previous = undef; # restart
+ }
+ }
+ return \%successors_for;
+}
diff --git a/challenge-161/polettix/raku/ch-1.raku b/challenge-161/polettix/raku/ch-1.raku
new file mode 100644
index 0000000000..0ca3310b45
--- /dev/null
+++ b/challenge-161/polettix/raku/ch-1.raku
@@ -0,0 +1,19 @@
+#!/usr/bin/env raku
+use v6;
+sub MAIN (Str:D $dictionary) {
+ all-sorted-abecedarian-in($dictionary).put;
+}
+
+sub all-sorted-abecedarian-in (Str $dictionary) {
+ all-abecedarian-in($dictionary).sort({$^a.chars <=> $^b.chars}).Array;
+}
+
+sub all-abecedarian-in (Str $dictionary) {
+ $dictionary.IO.lines.grep({is-abecedarian($_)}).Array;
+}
+
+sub is-abecedarian (Str $word) {
+ $word.fc.comb.sort.join('') eq $word.fc;
+}
+
+# be chill or annoy forty bossy nosy cops
diff --git a/challenge-161/polettix/raku/ch-2.raku b/challenge-161/polettix/raku/ch-2.raku
new file mode 100644
index 0000000000..248be9c7b5
--- /dev/null
+++ b/challenge-161/polettix/raku/ch-2.raku
@@ -0,0 +1,56 @@
+#!/usr/bin/env raku
+use v6;
+use HTTP::Tiny;
+
+constant \DEFAULT_BOOK_URL =
+ 'https://www.gutenberg.org/cache/epub/308/pg308.txt';
+
+sub MAIN (Str:D $dictionary-file, Str:D $book-url = DEFAULT_BOOK_URL) {
+ my $dictionary = read-dictionary($dictionary-file);
+ my $book = get-stuff($book-url);
+ my $model = markov-model($book, $dictionary);
+
+ my ($src, $word, %hits);
+ my @trail = gather while %hits.elems < 26 {
+ $src = $model{$word // ''} // $dictionary;
+ take $word = random-word-draw($src);
+ ++%hits{$_} for $word.comb;
+ };
+ @trail.join(' ').put;
+}
+
+sub random-word-draw ($weighted-candidates) {
+ my $total = $weighted-candidates.values.sum;
+ my $draw = $total.rand;
+ for $weighted-candidates.kv -> $word, $weight {
+ $draw -= $weight;
+ return $word if $draw < 0;
+ }
+ die "unreached, hopefully\n";
+}
+
+sub read-dictionary ($filename) {
+ $filename.IO.words.map({$_ => 1}).Hash;
+}
+
+sub get-stuff ($url) {
+ my $response = HTTP::Tiny.new.get($url);
+ die "$response<status> $response<reason>\n"
+ unless $response<success>;
+ return $response<content>.decode;
+}
+
+sub markov-model ($text, $dictionary) {
+ my $previous = Nil;
+ my $successors-for;
+ for $text.lc.split(/<-[ a..z ]>/) -> $word {
+ if $dictionary{$word}:exists {
+ $successors-for{$previous}{$word}++ if defined $previous;
+ $previous = $word;
+ }
+ else {
+ $previous = Nil; # restart
+ }
+ }
+ return $successors-for;
+}