aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2019-12-08 21:30:28 +0100
committerLeah Neukirchen <leah@vuxu.org>2019-12-08 21:30:28 +0100
commit62ddf8eb1da577429cc08d18ccfc7ca30eead73e (patch)
treee4998f7fdc631227760a4969ac107c0741405e8d
parent8fbcd639714c54245c8bbb479d85e75c5aa4f4b0 (diff)
downloadadventofcode2019-62ddf8eb1da577429cc08d18ccfc7ca30eead73e.tar.gz
adventofcode2019-62ddf8eb1da577429cc08d18ccfc7ca30eead73e.tar.xz
adventofcode2019-62ddf8eb1da577429cc08d18ccfc7ca30eead73e.zip
day07
-rw-r--r--day07.pl121
1 files changed, 121 insertions, 0 deletions
diff --git a/day07.pl b/day07.pl
new file mode 100644
index 0000000..9bd3b6b
--- /dev/null
+++ b/day07.pl
@@ -0,0 +1,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;