]> www.fi.muni.cz Git - aoc.git/blobdiff - 2017/36.pl
The rest of Year 2017
[aoc.git] / 2017 / 36.pl
diff --git a/2017/36.pl b/2017/36.pl
new file mode 100755 (executable)
index 0000000..2f4e59c
--- /dev/null
@@ -0,0 +1,63 @@
+#!/usr/bin/perl
+
+use v5.30;
+use strict;
+
+my @code = map { chomp; [ split /\s+/ ] } <>;
+
+sub execute {
+       my ($regs, $pc, $qsnd, $qrecv, $nsnd) = @_;
+       while ($$pc < @code) {
+               my ($ins, $a1, $a2) = @{ $code[$$pc] };
+               my $v1 = $a1 =~ /[a-z]/ ? $regs->{$a1} : $a1
+                       if defined $a1;
+               my $v2 = $a2 =~ /[a-z]/ ? $regs->{$a2} : $a2
+                       if defined $a2;
+               if ($ins eq 'snd') {
+                       push @$qsnd, $v1;
+                       $$nsnd++ if defined $nsnd;
+                       $$pc++;
+                       return 0;
+               } elsif ($ins eq 'set') {
+                       $regs->{$a1} = $v2;
+               } elsif ($ins eq 'add') {
+                       $regs->{$a1} += $v2;
+               } elsif ($ins eq 'mul') {
+                       $regs->{$a1} *= $v2;
+               } elsif ($ins eq 'mod') {
+                       $regs->{$a1} %= $v2;
+               } elsif ($ins eq 'rcv') {
+                       if (@$qrecv) {
+                               $regs->{$a1} = shift @$qrecv;
+                       } else {
+                               return 1;
+                       }
+               } elsif ($ins eq 'jgz') {
+                       $$pc += $v2-1 if $v1 > 0;
+               } else {
+                       die "unknown insn $ins";
+               }
+               $$pc++;
+       }
+       return 2;
+}
+
+my (@q0to1, @q1to0);
+my %regs0 = (p => 0);
+my %regs1 = (p => 1);
+my ($pc0, $pc1) = (0, 0);
+my ($s0, $s1) = (0, 0);
+my $nsnd = 0;
+while (1) {
+       if ($s0 == 0 || ($s0 == 1 && @q1to0)) {
+               $s0 = execute(\%regs0, \$pc0, \@q0to1, \@q1to0);
+               # say "p0 state $s0 at $pc0";
+       }
+       if ($s1 == 0 || ($s1 == 1 && @q0to1)) {
+               $s1 = execute(\%regs1, \$pc1, \@q1to0, \@q0to1, \$nsnd);
+               # say "p1 state $s1 at $pc1";
+       }
+       last if ($s0 >= 1 && $s1 >= 1);
+}
+
+say $nsnd;