]> www.fi.muni.cz Git - aoc.git/blobdiff - 2019/37.pl
2019 day 19
[aoc.git] / 2019 / 37.pl
diff --git a/2019/37.pl b/2019/37.pl
new file mode 100755 (executable)
index 0000000..fed338f
--- /dev/null
@@ -0,0 +1,149 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+package IntComp;
+use bigint;
+
+sub new {
+       my ($class, $mem, $inputs) = @_;
+       my $self = {
+               mem => [ @$mem ],
+               pc  => 0,
+               want_input => undef,
+               base => 0,
+       };
+       $self->{inputs} = [ @$inputs ]
+               if defined $inputs;
+       bless $self, $class;
+}
+
+sub clone {
+       my ($class, $other) = @_;
+       my $self = {
+               mem => [ @{ $other->{mem} } ],
+               pc  => $other->{pc},
+               want_input => undef,
+               base => $other->{base},
+               inputs => [ ],
+       };
+       bless $self, $class;
+}
+
+sub m2val {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ] // 0;
+       } elsif ($mode == 1) {
+               return $self->{mem}->[$self->{pc} + $off] // 0;
+       } elsif ($mode == 2) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off ] + $self->{base} ] // 0;
+       }
+}
+
+sub m2pos {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[$self->{pc} + $off];
+       } elsif ($mode == 2) {
+               return $self->{mem}->[$self->{pc} + $off] + $self->{base};
+       }
+}
+
+sub input {
+       my ($self, @input) = @_;
+       push @{ $self->{inputs} }, @input;
+}
+
+sub run {
+       my ($self, @input) = @_;
+       my $mem = $self->{mem};
+
+       push @{ $self->{inputs} }, @input;
+       if (defined $self->{want_input}) {
+               $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
+               $self->{want_input} = undef;
+       }
+
+       while (1) {
+               my $opcode = $mem->[$self->{pc}];
+               # say "pc=", $self->{pc}, " opcode=$opcode";
+               # say "mem=", join(',', map { $_ // '_' } @{ $self->{mem} });
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               my $m3 = int($opcode / 10000) % 10;
+               if ($op == 1) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               + m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 2) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               * m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 3) {
+                       if (@{ $self->{inputs} }) {
+                               $mem->[ m2pos($self, 1, $m1) ]
+                                       = shift @{ $self->{inputs} };
+                               $self->{pc} += 2;
+                       } else {
+                               $self->{want_input} = m2pos($self, 1, $m1);
+                               $self->{pc} += 2;
+                               return undef;
+                       }
+               } elsif ($op == 4) {
+                       my $val = m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+                       return $val;
+               } elsif ($op == 5) {
+                       if (m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               < m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 8) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               == m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 9) {
+                       $self->{base} += m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+               } elsif ($op == 99) {
+                       return undef;
+               }
+       }
+}
+
+package main;
+
+chomp (my @mem = split /,/, <>);
+
+$; = ',';
+
+my $sum;
+
+for my $x (0 .. 49) {
+for my $y (0 .. 49) {
+       my $comp = IntComp->new(\@mem, [ $x, $y ]);
+       my $rv = $comp->run;
+       $sum++ if $rv;
+       print $rv ? '#' : '.';
+}
+print "\n";
+}
+
+say $sum;