|
| 1 | +use v6; |
| 2 | + |
| 3 | +=begin pod |
| 4 | +
|
| 5 | +=head1 DESCRIPTION |
| 6 | +
|
| 7 | +Looking at the table below, it is easy to verify that the maximum possible sum |
| 8 | +of adjacent numbers in any direction (horizontal, vertical, diagonal or |
| 9 | +anti-diagonal) is 16 (= 8 + 7 + 1). −253 2 9−651 3273 −18−4 8 |
| 10 | +
|
| 11 | +Now, let us repeat the search, b ut on a |
| 12 | +much larger scale: |
| 13 | +
|
| 14 | +First, generate four million pseudo-random numbers using a specific form of |
| 15 | +what is known as a "Lagged Fibonacci Generator": |
| 16 | +
|
| 17 | +For 1 ≤ k ≤ 55, sk = [100003 − 200003k + 300007k3] (modulo 1000000) − 500000. |
| 18 | +For 56 ≤ k ≤ 4000000, sk = [sk−24 + sk−55 + 1000000] (modulo 1000000) − 500000. |
| 19 | +
|
| 20 | +Thus, s10 = −393027 and s100 = 86613. |
| 21 | +
|
| 22 | +The terms of s are then arranged in a 2000×2000 table, using the first 2000 |
| 23 | +numbers to fill the first row (sequentially), the next 2000 numbers to fill the |
| 24 | +second row, and so on. |
| 25 | +
|
| 26 | +Finally, find the greatest sum of (any number of) adjacent entries in any |
| 27 | +direction (horizontal, vertical, diagonal or anti-diagonal). |
| 28 | +
|
| 29 | +=end pod |
| 30 | + |
| 31 | +# use integer; |
| 32 | + |
| 33 | +# use Math::BigInt "lib" => "GMP"; |
| 34 | + |
| 35 | +class FiboRand { |
| 36 | + has $.k is rw = 1; |
| 37 | + has @.last_nums is rw; |
| 38 | + |
| 39 | + method fetch() { |
| 40 | + my $k = $.k; |
| 41 | + my $s_k; |
| 42 | + |
| 43 | + if ($k <= 55) |
| 44 | + { |
| 45 | + $s_k = (((100003 - 200003*$k + 300007*($k**3)) % 1000000) - 500000); |
| 46 | + } |
| 47 | + else |
| 48 | + { |
| 49 | + $s_k = (((@.last_nums[*-24] + @.last_nums[*-55] + 1000000) % 1000000) - 500000); |
| 50 | + shift(@.last_nums); |
| 51 | + } |
| 52 | + push @.last_nums, $s_k; |
| 53 | + $.k++; |
| 54 | + |
| 55 | + return $s_k; |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +# Unit test to the randomizer. |
| 60 | +{ |
| 61 | + my $rand = FiboRand.new; |
| 62 | + |
| 63 | + for 1 .. 9 -> $k |
| 64 | + { |
| 65 | + $rand.fetch(); |
| 66 | + } |
| 67 | + |
| 68 | + if ($rand.fetch() != -393027) |
| 69 | + { |
| 70 | + die "Wrong s10!"; |
| 71 | + } |
| 72 | + |
| 73 | + for 11 .. 99 -> $k |
| 74 | + { |
| 75 | + $rand.fetch(); |
| 76 | + } |
| 77 | + |
| 78 | + if ($rand.fetch() != 86613) |
| 79 | + { |
| 80 | + die "Wrong s100!"; |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +class Max |
| 85 | +{ |
| 86 | + has $.s is rw = 0; |
| 87 | + has $.e is rw = 0; |
| 88 | + method add($n) |
| 89 | + { |
| 90 | + $.s = max($.s, ($.e = max($.e + $n, 0))); |
| 91 | + |
| 92 | + return; |
| 93 | + } |
| 94 | + |
| 95 | + # g = get() |
| 96 | + method g() |
| 97 | + { |
| 98 | + return $.s; |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +my $rand = FiboRand.new; |
| 103 | + |
| 104 | +my $SIZE = 2_000; |
| 105 | + |
| 106 | +my $max_max = 0; |
| 107 | +my @vert_max = map { Max.new }, (1 .. $SIZE); |
| 108 | +my @diag_max = map { Max.new }, (1 .. $SIZE); |
| 109 | +my @anti_diag_max = map { Max.new }, (1 .. $SIZE); |
| 110 | + |
| 111 | +my $diag_offset = 0; |
| 112 | +my $anti_diag_offset = 0; |
| 113 | + |
| 114 | +sub handle_row() |
| 115 | +{ |
| 116 | + my $horiz = Max.new; |
| 117 | + # First row. |
| 118 | + for 0 .. $SIZE-1 -> $x |
| 119 | + { |
| 120 | + my $s = $rand.fetch(); |
| 121 | + |
| 122 | + @vert_max[$x].add($s); |
| 123 | + $horiz.add($s); |
| 124 | + @diag_max[($x+$diag_offset) % $SIZE].add($s); |
| 125 | + @anti_diag_max[($x+$anti_diag_offset) % $SIZE].add($s); |
| 126 | + } |
| 127 | + |
| 128 | + $max_max = max( |
| 129 | + $max_max, $horiz.g(), @diag_max[0].g(), @anti_diag_max[*-1].g() |
| 130 | + ); |
| 131 | + |
| 132 | + @diag_max[0] = Max.new; |
| 133 | + $diag_offset++; |
| 134 | + |
| 135 | + @anti_diag_max[*-1] = Max.new; |
| 136 | + $anti_diag_offset--; |
| 137 | + |
| 138 | + return; |
| 139 | +} |
| 140 | + |
| 141 | +for 1 .. $SIZE -> $y |
| 142 | +{ |
| 143 | + print "Y=$y\n"; |
| 144 | + handle_row(); |
| 145 | +} |
| 146 | + |
| 147 | + |
| 148 | +print "Result = ", max( |
| 149 | + $max_max, (map { $_.g() }, @vert_max, @diag_max, @anti_diag_max |
| 150 | + ) |
| 151 | +), "\n"; |
| 152 | + |
| 153 | +# vim: ft=perl6 |
0 commit comments