aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbigail <abigail@abigail.be>2021-02-25 14:13:21 +0100
committerAbigail <abigail@abigail.be>2021-02-25 14:13:21 +0100
commitda2f7e48f7f8c0ecc2653bf233f2c724f35e48f9 (patch)
treef1a94c613020653a49f49944f557c71fb17ee8e9
parentbb123a18ffd0376c3a306f0cbd6b5746bbf4956b (diff)
downloadperlweeklychallenge-club-da2f7e48f7f8c0ecc2653bf233f2c724f35e48f9.tar.gz
perlweeklychallenge-club-da2f7e48f7f8c0ecc2653bf233f2c724f35e48f9.tar.bz2
perlweeklychallenge-club-da2f7e48f7f8c0ecc2653bf233f2c724f35e48f9.zip
Perl solution for week 101, part 1
-rw-r--r--challenge-101/abigail/README.md1
-rw-r--r--challenge-101/abigail/perl/ch-1.pl108
2 files changed, 109 insertions, 0 deletions
diff --git a/challenge-101/abigail/README.md b/challenge-101/abigail/README.md
index 7707028ada..48c4c6976e 100644
--- a/challenge-101/abigail/README.md
+++ b/challenge-101/abigail/README.md
@@ -62,6 +62,7 @@ or
~~~~
### Solutions
+* [Perl](perl/ch-1.pl)
### Blog
diff --git a/challenge-101/abigail/perl/ch-1.pl b/challenge-101/abigail/perl/ch-1.pl
new file mode 100644
index 0000000000..0b7dfa3352
--- /dev/null
+++ b/challenge-101/abigail/perl/ch-1.pl
@@ -0,0 +1,108 @@
+#!/opt/perl/bin/perl
+
+use 5.032;
+
+use strict;
+use warnings;
+no warnings 'syntax';
+
+use experimental 'signatures';
+use experimental 'lexical_subs';
+
+use List::Util 'max';
+
+#
+# See ../README.md
+#
+
+#
+# Run as: perl ch-1.pl < input-file
+#
+
+#
+# This is a really hard problem to do efficiently, as it involves
+# factorizing numbers. And if we can do that efficiently, we can
+# break many public key encryption schemes, including RSA.
+#
+# We do, however, use a simplistic method to find the optimal width
+# and height for the matrix, by starting at the square root of the
+# number of elements, and trying each number (while counting down)
+# till we have found a divisor.
+#
+# This is O (sqrt (N)), where N is the number of elements.
+# However, we're already spending linear time reading the input.
+#
+
+my $RIGHT = 0;
+my $UP = 1;
+my $LEFT = 2;
+my $DOWN = 3;
+
+#
+# Read in the data; we're assuming the elements are separated by whitespace.
+# We can easily change this without effecting the rest of the program.
+#
+my @elements = split ' ' => scalar <>;
+
+#
+# Find optimal sizes: width $w and height $h
+# We start at the square root, and count downwards till we
+# have a divider.
+#
+my $h = int sqrt @elements;
+for (; @elements % $h;) {
+ $h --;
+}
+
+my $w = @elements / $h;
+
+
+#
+# Fill a matrix, starting from the bottom left.
+#
+my $matrix;
+my ($min_x, $max_x, $min_y, $max_y) = (0, $h - 1, 0, $w - 1);
+my $x = $max_x;
+my $y = $min_y;
+my $direction = $RIGHT;
+foreach my $element (@elements) {
+ $$matrix [$x] [$y] = $element;
+ my $turn = 0;
+ if ($direction == $RIGHT) {
+ if ($y >= $max_y) {$turn = 1; $x --; $max_x --}
+ else {$y ++}
+ }
+ if ($direction == $UP) {
+ if ($x <= $min_x) {$turn = 1; $y --; $max_y --}
+ else {$x --}
+ }
+ if ($direction == $LEFT) {
+ if ($y <= $min_y) {$turn = 1; $x ++; $min_x ++}
+ else {$y --}
+ }
+ if ($direction == $DOWN) {
+ if ($x >= $max_x) {$turn = 1; $y ++; $min_y ++}
+ else {$x ++}
+ }
+ if ($turn) {
+ $direction ++;
+ $direction %= 4;
+ }
+}
+
+#
+# Pretty print array; we're making sure all the columns are aligned.
+#
+
+my @widths = map {my $y = $_;
+ max map {length $$matrix [$_] [$y]} 0 .. $h - 1} 0 .. $w - 1;
+
+foreach my $row (@$matrix) {
+ for (my $y = 0; $y < @$row; $y ++) {
+ my $width = $widths [$y];
+ printf "%s%${width}s" => $y ? " " : "", $$row [$y];
+ }
+ print "\n";
+}
+
+__END__