Skip to content

Commit 67cfab0

Browse files
committed
Add my solution to Euler#551.
Somewhat based on the python solution in https://github.com/shlomif/project-euler , but somewhat cleaner and much slower (sigh).
1 parent d997e40 commit 67cfab0

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

categories/euler/prob551-shlomif.p6

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
2+
use v6;
3+
use MONKEY-TYPING;
4+
5+
my $NUM_DIGITS = 30;
6+
7+
my $NUM_FMT = '%0' ~ $NUM_DIGITS ~ 'd';
8+
9+
augment class Int
10+
{
11+
method digits-sum() returns Int
12+
{
13+
return [+] self.comb;
14+
}
15+
16+
method _format_n() returns Str
17+
{
18+
return $NUM_FMT.sprintf(self);
19+
}
20+
}
21+
22+
my $A0 = 1;
23+
24+
class Point
25+
{
26+
has Int $.n;
27+
# The digits sum.
28+
has Int $.s;
29+
# The index.
30+
has Int $.i;
31+
32+
method _format() returns Str
33+
{
34+
return self.n._format_n;
35+
}
36+
}
37+
38+
my @calced_arr;
39+
40+
my $a_n = Point.new(n => $A0, i => 1, s => $A0.digits-sum);
41+
42+
# Short for insert.
43+
sub ins()
44+
{
45+
@calced_arr.push($a_n.clone);
46+
47+
return;
48+
}
49+
50+
ins();
51+
52+
53+
my @cache = [{} xx ($NUM_DIGITS+1)] xx ($NUM_DIGITS*9+1);
54+
55+
sub calc_next()
56+
{
57+
my $new_n = $a_n.n + $a_n.s;
58+
$a_n = Point.new(n => $new_n, i => $a_n.i+1, s => $new_n.digits-sum);
59+
60+
return;
61+
}
62+
63+
sub _common_len(Str $s, Str $e)
64+
{
65+
return -1 + (0 .. $NUM_DIGITS).first: { $s.substr($^a, 1) ne $e.substr($^a, 1) };
66+
}
67+
68+
sub cache_delta()
69+
{
70+
# Start and end.
71+
my $i = @calced_arr-2;
72+
my $s = @calced_arr[*-2];
73+
my $e = @calced_arr[*-1];
74+
my $s_digits = $s._format;
75+
my $e_digits = $e._format;
76+
my $l = _common_len($s_digits, $e_digits);
77+
for 1 .. $l -> $ll
78+
{
79+
@cache[$s.s][$ll]{$s_digits.substr($ll)} = $i;
80+
}
81+
return;
82+
}
83+
84+
calc_next;
85+
ins;
86+
cache_delta;
87+
88+
# my $LIM = 1_000_000;
89+
my $LIM = 1_000_000_000_000_000;
90+
91+
sub _print_me()
92+
{
93+
say "a[%d] = %d".sprintf($a_n.i, $a_n.n);
94+
}
95+
96+
while $a_n.i < $LIM
97+
{
98+
_print_me;
99+
my $a_s = $a_n._format;
100+
my $to_proc = sub {
101+
for 1 .. $NUM_DIGITS-1 -> $i
102+
{
103+
my $sub_s = $a_s.substr($i);
104+
my $lookup = @cache[$a_n.s][$i];
105+
if $lookup{$sub_s}:exists
106+
{
107+
my $start_arr_i = $lookup{$sub_s};
108+
my $get_prefix = sub ($idx) {
109+
return @calced_arr[$idx]._format().substr(0,$i);
110+
};
111+
my $prefix = $get_prefix.($start_arr_i);
112+
my $base_idx = $a_n.i - @calced_arr[$start_arr_i].i;
113+
my $end_arr_i = $start_arr_i + 1;
114+
my $new_idx = sub () { return $base_idx + @calced_arr[$end_arr_i].i };
115+
while $end_arr_i < @calced_arr and $get_prefix.($end_arr_i) eq $prefix and $new_idx.() <= $LIM
116+
{
117+
$end_arr_i++;
118+
}
119+
$end_arr_i--;
120+
if $end_arr_i > $start_arr_i
121+
{
122+
$a_n = Point.new(
123+
n => $a_n.n + @calced_arr[$end_arr_i].n - @calced_arr[$start_arr_i].n,
124+
i => $new_idx.(),
125+
s => @calced_arr[$end_arr_i].s
126+
);
127+
return False;
128+
}
129+
}
130+
}
131+
return True;
132+
}.();
133+
134+
if $to_proc
135+
{
136+
calc_next;
137+
}
138+
139+
ins;
140+
cache_delta;
141+
}
142+
143+
_print_me;

0 commit comments

Comments
 (0)