aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Sommrey <28217714+jo-37@users.noreply.github.com>2023-03-31 14:41:29 +0200
committerJörg Sommrey <28217714+jo-37@users.noreply.github.com>2023-03-31 14:41:29 +0200
commitb1dbb201a295d2cc047a10e8c2f07fba8ff57b98 (patch)
treebfb8661acd93c5b07a377ce8cf972c0a09894197
parent8915a66de2cb2a724aee5e55ddfc15580cfdf1d5 (diff)
parent02acd68ba59a08522e2ab6549cc5ca635079666a (diff)
downloadperlweeklychallenge-club-b1dbb201a295d2cc047a10e8c2f07fba8ff57b98.tar.gz
perlweeklychallenge-club-b1dbb201a295d2cc047a10e8c2f07fba8ff57b98.tar.bz2
perlweeklychallenge-club-b1dbb201a295d2cc047a10e8c2f07fba8ff57b98.zip
Solutions to challenge 210
-rwxr-xr-xchallenge-210/jo-37/perl/ch-1.pl64
-rwxr-xr-xchallenge-210/jo-37/perl/ch-2.pl100
2 files changed, 164 insertions, 0 deletions
diff --git a/challenge-210/jo-37/perl/ch-1.pl b/challenge-210/jo-37/perl/ch-1.pl
new file mode 100755
index 0000000000..8a8aef7f2e
--- /dev/null
+++ b/challenge-210/jo-37/perl/ch-1.pl
@@ -0,0 +1,64 @@
+#!/usr/bin/perl -s
+
+use v5.16;
+use Test2::V0;
+use List::Util qw(sum max);
+use List::UtilsBy qw(count_by);
+
+our ($tests, $examples);
+
+run_tests() if $tests || $examples; # does not return
+
+die <<EOS unless @ARGV;
+usage: $0 [-examples] [-tests] [--] [N...]
+
+-examples
+ run the examples from the challenge
+
+-tests
+ run some tests
+
+N...
+ list of numbers
+
+EOS
+
+
+### Input and Output
+
+say kill_and_win(@ARGV);
+
+
+### Implementation
+
+# Brute force implementation.
+
+sub kill_and_win {
+ # Create a map from values to their frequencies.
+ my %freq = count_by {$_} @_;
+ # Find the maximum over three consectutive values.
+ max map {
+ sum map {$_ * ($freq{$_} // 0)} $_ - 1, $_, $_ + 1
+ } keys %freq;
+}
+
+
+### Examples and tests
+
+sub run_tests {
+ SKIP: {
+ skip "examples" unless $examples;
+
+ is kill_and_win(2, 3, 1), 6, 'example 1';
+ is kill_and_win(1, 1, 2, 2, 2, 3), 11, 'example 2';
+ }
+
+ SKIP: {
+ skip "tests" unless $tests;
+
+ is kill_and_win(1, 1, 2, 2, 3, 3, 13), 13, 'single large value';
+ }
+
+ done_testing;
+ exit;
+}
diff --git a/challenge-210/jo-37/perl/ch-2.pl b/challenge-210/jo-37/perl/ch-2.pl
new file mode 100755
index 0000000000..8354c1fbd7
--- /dev/null
+++ b/challenge-210/jo-37/perl/ch-2.pl
@@ -0,0 +1,100 @@
+#!/usr/bin/perl -s
+
+use v5.22;
+use Test2::V0;
+use List::MoreUtils 'zip6';
+use experimental 'refaliasing';
+
+our ($tests, $examples);
+
+run_tests() if $tests || $examples; # does not return
+
+die <<EOS unless @ARGV;
+usage: $0 [-examples] [-tests] [--] [NUM...]
+
+-examples
+ run the examples from the challenge
+
+-tests
+ run some tests
+
+NUM...
+ list of numbers
+
+EOS
+
+
+### Input and Output
+
+say "(@{number_collision(@ARGV)})";
+
+
+### Implementation
+
+# Maybe there is a way to solve this puzzle just by looking at the
+# numbers. I don't see one. So we're going play the game to find the
+# result.
+
+sub number_collision {
+ # Distribute the numbers onto two arrays depending on the sign,
+ # which defines the moving direction. Inserting 'undef' to keep
+ # every number's position.
+ my (@right, @left);
+ for (@_) {
+ push @left, $_ < 0 ? $_ : undef;
+ push @right, $_ < 0 ? undef : $_;
+ }
+ # Our 'frame of reference' is given by the numbers moving left, i.e.
+ # negative values never change their position, whereas positive
+ # number are shifted to the right.
+ # Initialise two index positions of
+ # - the leftmost positive number
+ # - the rightmost negative number
+ my ($r, $l) = (0, 'inf');
+ # As long as the first index is smaller than the second, there are
+ # collisions ahead.
+ while ($r < $l) {
+ ($r, $l) = ('inf', 0);
+ # Move right.
+ unshift @right, undef;
+ # Process all number pairs.
+ for my $i (0 .. $#right) {
+ # Get a shorthand for the pair.
+ \my ($ri, $li) = \($right[$i], $left[$i]);
+ # Get the pair's values with default.
+ my ($ri_d, $li_d) = ($ri // -1, $li // 1);
+ # Find the result of a collision.
+ ($ri, $li) = ( $ri_d <= -$li_d ? undef : $ri,
+ -$li_d <= $ri_d ? undef : $li);
+ # Adjust indices.
+ $r = $i if defined $ri && $i < $r;
+ $l = $i if defined $li;
+ }
+ }
+ [map $_->[0] // $_->[1] // (), zip6 @right, @left];
+
+}
+
+
+### Examples and tests
+
+sub run_tests {
+ SKIP: {
+ skip "examples" unless $examples;
+
+ is number_collision(2, 3, -1), [2, 3], 'example 1';
+ is number_collision(2, 3, -4), [-4], 'example 2';
+ is number_collision(1, -1), [], 'example 3';
+ }
+
+ SKIP: {
+ skip "tests" unless $tests;
+
+ is number_collision(0), [0], 'surviving zero';
+ is number_collision(1, -2, 3, 1, -3, 4, 2, -4, 5, 3, 1, -6),
+ [-2, -6], 'the big pwc number massacre';
+ }
+
+ done_testing;
+ exit;
+}