aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xchallenge-218/e-choroba/perl/ch-1.pl59
-rwxr-xr-xchallenge-218/e-choroba/perl/ch-2.pl74
2 files changed, 133 insertions, 0 deletions
diff --git a/challenge-218/e-choroba/perl/ch-1.pl b/challenge-218/e-choroba/perl/ch-1.pl
new file mode 100755
index 0000000000..6e03c400c4
--- /dev/null
+++ b/challenge-218/e-choroba/perl/ch-1.pl
@@ -0,0 +1,59 @@
+#! /usr/bin/perl
+use warnings;
+use strict;
+use experimental qw( signatures );
+
+# Optimisation: Select the 3 least and 3 greatest numbers and build
+# the maximum product from them by trying all the possibilities. The
+# least numbers are needed as they might introduce negative numbers.
+sub maximum_product (@list) {
+ return maximum_product_simple(@list) if @list <= 6;
+ return maximum_product_simple((sort { $a <=> $b } @list)[0, 1, 2, -3, -2, -1])
+}
+
+sub maximum_product_simple (@list) {
+ return product(@list) if 3 == @list;
+
+ my $max_product = product(@list[0, 1, 2]);
+ for my $i (0 .. $#list - 2) {
+ for my $j ($i + 1 .. $#list - 1) {
+ my $p_ij = product(@list[$i, $j]);
+ for my $k ($j + 1 .. $#list) {
+ my $prod = $p_ij * $list[$k];
+ $max_product = $prod if $prod > $max_product;
+ }
+ }
+ }
+ return $max_product
+}
+
+sub product {
+ my $p = 1;
+ $p *= $_ for @_;
+ $p
+}
+
+use Test::More tests => 2 * 4 + 1;
+
+for my $maximum_product (*maximum_product{CODE},
+ *maximum_product_simple{CODE}
+) {
+ is $maximum_product->(3, 1, 2), 6, 'Example 1';
+ is $maximum_product->(4, 1, 3, 2), 24, 'Example 2';
+ is $maximum_product->(-1, 0, 1, 3, 1), 3, 'Example 3';
+ is $maximum_product->(-8, 2, -9, 0, -4, 3), 216, 'Example 4';
+}
+
+my @long = map int(rand 100) - 50, 1 .. 20;
+is maximum_product(@long), maximum_product_simple(@long), "same @long";
+
+use Benchmark qw{ cmpthese };
+cmpthese(-3, {
+ simple => sub { maximum_product_simple(@long) },
+ preselect => sub { maximum_product(@long) },
+});
+
+__END__
+ Rate simple preselect
+simple 8665/s -- -94%
+preselect 140390/s 1520% --
diff --git a/challenge-218/e-choroba/perl/ch-2.pl b/challenge-218/e-choroba/perl/ch-2.pl
new file mode 100755
index 0000000000..20714112d9
--- /dev/null
+++ b/challenge-218/e-choroba/perl/ch-2.pl
@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use experimental qw( signatures );
+
+sub matrix_score($m) {
+ my $height = @$m;
+ my $width = @{ $m->[0] };
+ my $ser = serialise($m);
+ my %agenda = my %done = ($ser => undef);
+ my $max = score($ser, $width);
+
+ while (%agenda) {
+ my %next;
+ for my $s (keys %agenda) {
+ for my $i (0 .. ($width, $height)[$width < $height] - 1) {
+ my @flips;
+ push @flips, flip_col($s, $i, $width, $height) if $i < $width;
+ push @flips, flip_row($s, $i, $width, $height) if $i < $height;
+ for my $f (@flips) {
+ unless (exists $done{$f}) {
+ my $score = score($f, $width);
+ $max = $score if $score > $max;
+ undef $next{$f};
+ undef $done{$f};
+ }
+ }
+ }
+ }
+ %agenda = %next;
+ }
+ return $max
+}
+
+sub serialise($m) { join "", map @$_, map @$_, @_ }
+
+sub flip_col($s, $x, $width, $height) {
+ for my $y (0 .. $height - 1) {
+ my $pos = $x + $y * $width;
+ substr $s, $pos, 1, substr($s, $pos, 1) ? 0 : 1;
+ }
+ return $s
+}
+sub flip_row($s, $y, $width, $height) {
+ my $pos = $y * $width;
+ for my $x (0 .. $width - 1) {
+ substr $s, $pos, 1, substr($s, $pos, 1) ? 0 : 1;
+ ++$pos;
+ }
+ return $s
+}
+
+sub score($s, $width) {
+ my $score = 0;
+ my $pos = 0;
+ while (length(my $row = substr $s, $pos, $width)) {
+ $score += oct "0b$row";
+ } continue {
+ $pos += $width;
+ }
+ return $score
+}
+
+use Test::More tests => 3 + 2;
+
+is score('111110011111', 4), 39, 'score';
+is flip_col('001110', 1, 3, 2), '011100', 'flip column';
+is flip_row('001110', 1, 3, 2), '001001', 'flip row';
+
+is matrix_score([ [0,0,1,1],
+ [1,0,1,0],
+ [1,1,0,0], ]), 39, 'Example 1';
+
+is matrix_score([ [0] ]), 1, 'Example 2';