1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
#!/usr/bin/perl -w
use v5.16;
use File::Slurper 'read_text';
use List::Util qw'all max reduce';
# https://stackoverflow.com/a/637914
sub permute (&@) {
my $code = shift;
my @idx = 0..$#_;
while ( $code->(@_[@idx]) ) {
my $p = $#idx;
--$p while $idx[$p-1] > $idx[$p];
my $q = $p or return;
push @idx, reverse splice @idx, $p;
++$q while $idx[$p-1] > $idx[$q];
@idx[$p-1,$q]=@idx[$q,$p-1];
}
}
sub permutemap (&@) {
my $code = shift;
my @a;
permute { push @a, $code->(@_) } @_;
@a;
}
say max permutemap {
reduce {
my $c = IntCode->new('day07');
$c->input([$b, $a]);
until ($c->done) {
$c->step;
}
$c->output->[-1];
} 0, @_;
} (0..4);
say max permutemap {
my @cs = map { IntCode->new('day07')->push($_) } @_;
$cs[$_]->pipe($cs[$_+1]) for (0..$#cs - 1);
$cs[-1]->pipe($cs[0]);
$cs[0]->push(0);
until (all { $_->done } @cs) {
$_->step for @cs;
}
$cs[-1]->output->[-1];
} (5..9);
package IntCode;
use Class::Tiny qw( input output code ip );
use File::Slurper 'read_text';
sub BUILDARGS {
my $class = shift;
return { input => [],
output => [],
code => [ split ",", read_text(shift) ],
ip => 0 };
};
sub done {
my $self = shift;
$self->code->[$self->ip] == 99;
}
sub pipe {
my ($self, $other) = @_;
$self->{output} = $other->{input};
$self;
}
sub push {
my $self = shift;
push @{$self->{input}}, @_;
$self;
}
sub step {
my $self = shift;
no warnings 'uninitialized';
my ($pm3, $pm2, $pm1, $op1, $op2) =
split '', sprintf("%05d", $self->code->[$self->ip]);
my $op = $op1 . $op2;
my $p1 = $pm1 ? $self->code->[$self->ip + 1] :
$self->code->[$self->code->[$self->ip + 1]];
my $p2 = $pm2 ? $self->code->[$self->ip+2] :
$self->code->[$self->code->[$self->ip + 2]];
my $p3 = $pm3 ? $self->code->[$self->ip+3] :
$self->code->[$self->code->[$self->ip + 3]];
if ($op == 1) { $self->code->[$self->code->[$self->ip+3]] = $p1 + $p2;
$self->{ip} += 4; }
elsif ($op == 2) { $self->code->[$self->code->[$self->ip+3]] = $p1 * $p2;
$self->{ip} += 4; }
elsif ($op == 3) { return unless (@{$self->{input}}); # stall
$self->code->[$self->code->[$self->ip+1]] =
shift @{$self->{input}};
$self->{ip} += 2; }
elsif ($op == 4) { CORE::push @{$self->{output}}, $p1;
$self->{ip} += 2; }
elsif ($op == 5) { $self->{ip} = $p1 ? $p2 : $self->ip + 3; }
elsif ($op == 6) { $self->{ip} = !$p1 ? $p2 : $self->ip + 3; }
elsif ($op == 7) { $self->code->[$self->code->[$self->ip+3]] = $p1 < $p2;
$self->{ip} += 4; }
elsif ($op == 8) { $self->code->[$self->code->[$self->ip+3]] = $p1 == $p2;
$self->{ip} += 4; }
$self;
}
1;
|