Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Euler No. 149 #10

Merged
merged 1 commit into from

2 participants

@shlomif
Collaborator

I added a solution for Euler No. 149. Probably not the most idiomatic Perl 6 code. It runs very slowly on Rakudo, and much faster on Niecza. The Perl 5 version (here: https://bitbucket.org/shlomif/project-euler/src/4e8f95dee1328f9cf84593333fe377bdfd849960/project-euler/149?at=default ) is still faster.

@colomon colomon merged commit 3036039 into perl6:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 5, 2012
  1. @shlomif
This page is out of date. Refresh to see the latest.
Showing with 153 additions and 0 deletions.
  1. +153 −0 euler/prob149-shlomif.pl
View
153 euler/prob149-shlomif.pl
@@ -0,0 +1,153 @@
+use v6;
+
+=begin pod
+
+=head1 DESCRIPTION
+
+Looking at the table below, it is easy to verify that the maximum possible sum
+of adjacent numbers in any direction (horizontal, vertical, diagonal or
+anti-diagonal) is 16 (= 8 + 7 + 1). −253 2 9−651 3273 −18−4 8
+
+Now, let us repeat the search, b ut on a
+much larger scale:
+
+First, generate four million pseudo-random numbers using a specific form of
+what is known as a "Lagged Fibonacci Generator":
+
+For 1 ≤ k ≤ 55, sk = [100003 − 200003k + 300007k3] (modulo 1000000) − 500000.
+For 56 ≤ k ≤ 4000000, sk = [sk−24 + sk−55 + 1000000] (modulo 1000000) − 500000.
+
+Thus, s10 = −393027 and s100 = 86613.
+
+The terms of s are then arranged in a 2000×2000 table, using the first 2000
+numbers to fill the first row (sequentially), the next 2000 numbers to fill the
+second row, and so on.
+
+Finally, find the greatest sum of (any number of) adjacent entries in any
+direction (horizontal, vertical, diagonal or anti-diagonal).
+
+=end pod
+
+# use integer;
+
+# use Math::BigInt "lib" => "GMP";
+
+class FiboRand {
+ has $.k is rw = 1;
+ has @.last_nums is rw;
+
+ method fetch() {
+ my $k = $.k;
+ my $s_k;
+
+ if ($k <= 55)
+ {
+ $s_k = (((100003 - 200003*$k + 300007*($k**3)) % 1000000) - 500000);
+ }
+ else
+ {
+ $s_k = (((@.last_nums[*-24] + @.last_nums[*-55] + 1000000) % 1000000) - 500000);
+ shift(@.last_nums);
+ }
+ push @.last_nums, $s_k;
+ $.k++;
+
+ return $s_k;
+ }
+}
+
+# Unit test to the randomizer.
+{
+ my $rand = FiboRand.new;
+
+ for 1 .. 9 -> $k
+ {
+ $rand.fetch();
+ }
+
+ if ($rand.fetch() != -393027)
+ {
+ die "Wrong s10!";
+ }
+
+ for 11 .. 99 -> $k
+ {
+ $rand.fetch();
+ }
+
+ if ($rand.fetch() != 86613)
+ {
+ die "Wrong s100!";
+ }
+}
+
+class Max
+{
+ has $.s is rw = 0;
+ has $.e is rw = 0;
+ method add($n)
+ {
+ $.s = max($.s, ($.e = max($.e + $n, 0)));
+
+ return;
+ }
+
+ # g = get()
+ method g()
+ {
+ return $.s;
+ }
+}
+
+my $rand = FiboRand.new;
+
+my $SIZE = 2_000;
+
+my $max_max = 0;
+my @vert_max = map { Max.new }, (1 .. $SIZE);
+my @diag_max = map { Max.new }, (1 .. $SIZE);
+my @anti_diag_max = map { Max.new }, (1 .. $SIZE);
+
+my $diag_offset = 0;
+my $anti_diag_offset = 0;
+
+sub handle_row()
+{
+ my $horiz = Max.new;
+ # First row.
+ for 0 .. $SIZE-1 -> $x
+ {
+ my $s = $rand.fetch();
+
+ @vert_max[$x].add($s);
+ $horiz.add($s);
+ @diag_max[($x+$diag_offset) % $SIZE].add($s);
+ @anti_diag_max[($x+$anti_diag_offset) % $SIZE].add($s);
+ }
+
+ $max_max = max(
+ $max_max, $horiz.g(), @diag_max[0].g(), @anti_diag_max[*-1].g()
+ );
+
+ @diag_max[0] = Max.new;
+ $diag_offset++;
+
+ @anti_diag_max[*-1] = Max.new;
+ $anti_diag_offset--;
+
+ return;
+}
+
+for 1 .. $SIZE -> $y
+{
+ print "Y=$y\n";
+ handle_row();
+}
+
+
+print "Result = ", max(
+ $max_max, (map { $_.g() }, @vert_max, @diag_max, @anti_diag_max
+ )
+), "\n";
+
+# vim: ft=perl6
Something went wrong with that request. Please try again.