]> www.fi.muni.cz Git - aoc.git/blob - 2019/46.pl
Rest of 2019
[aoc.git] / 2019 / 46.pl
1 #!/usr/bin/perl -w
2
3 use v5.16;
4
5 package IntComp;
6 use bigint;
7
8 sub new {
9         my ($class, $mem, $inputs) = @_;
10         my $self = {
11                 mem => [ @$mem ],
12                 pc  => 0,
13                 want_input => undef,
14                 base => 0,
15         };
16         $self->{inputs} = [ @$inputs ]
17                 if defined $inputs;
18         bless $self, $class;
19 }
20
21 sub clone {
22         my ($class, $other) = @_;
23         my $self = {
24                 mem => [ @{ $other->{mem} } ],
25                 pc  => $other->{pc},
26                 want_input => undef,
27                 base => $other->{base},
28                 inputs => [ ],
29         };
30         bless $self, $class;
31 }
32
33 sub m2val {
34         my ($self, $off, $mode) = @_;
35         if ($mode == 0) {
36                 return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ] // 0;
37         } elsif ($mode == 1) {
38                 return $self->{mem}->[$self->{pc} + $off] // 0;
39         } elsif ($mode == 2) {
40                 return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off ] + $self->{base} ] // 0;
41         }
42 }
43
44 sub m2pos {
45         my ($self, $off, $mode) = @_;
46         if ($mode == 0) {
47                 return $self->{mem}->[$self->{pc} + $off];
48         } elsif ($mode == 2) {
49                 return $self->{mem}->[$self->{pc} + $off] + $self->{base};
50         }
51 }
52
53 sub input {
54         my ($self, @input) = @_;
55         push @{ $self->{inputs} }, @input;
56 }
57
58 sub run {
59         my ($self, @input) = @_;
60         my $mem = $self->{mem};
61
62         push @{ $self->{inputs} }, @input;
63         if (defined $self->{want_input}) {
64                 $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
65                 $self->{want_input} = undef;
66         }
67
68         while (1) {
69                 my $opcode = $mem->[$self->{pc}];
70                 # say "pc=", $self->{pc}, " opcode=$opcode";
71                 # say "mem=", join(',', map { $_ // '_' } @{ $self->{mem} });
72                 my $op = int($opcode % 100);
73                 my $m1 = int($opcode / 100) % 10;
74                 my $m2 = int($opcode / 1000) % 10;
75                 my $m3 = int($opcode / 10000) % 10;
76                 if ($op == 1) {
77                         $mem->[ m2pos($self, 3, $m3) ]
78                                 = m2val($self, 1, $m1)
79                                 + m2val($self, 2, $m2);
80                         $self->{pc} += 4;
81                 } elsif ($op == 2) {
82                         $mem->[ m2pos($self, 3, $m3) ]
83                                 = m2val($self, 1, $m1)
84                                 * m2val($self, 2, $m2);
85                         $self->{pc} += 4;
86                 } elsif ($op == 3) {
87                         if (@{ $self->{inputs} }) {
88                                 $mem->[ m2pos($self, 1, $m1) ]
89                                         = shift @{ $self->{inputs} };
90                                 $self->{pc} += 2;
91                         } else {
92                                 $self->{want_input} = m2pos($self, 1, $m1);
93                                 $self->{pc} += 2;
94                                 return undef;
95                         }
96                 } elsif ($op == 4) {
97                         my $val = m2val($self, 1, $m1);
98                         $self->{pc} += 2;
99                         return $val;
100                 } elsif ($op == 5) {
101                         if (m2val($self, 1, $m1)) {
102                                 $self->{pc} = m2val($self, 2, $m2);
103                         } else {
104                                 $self->{pc} += 3;
105                         }
106                 } elsif ($op == 6) {
107                         if (!m2val($self, 1, $m1)) {
108                                 $self->{pc} = m2val($self, 2, $m2);
109                         } else {
110                                 $self->{pc} += 3;
111                         }
112                 } elsif ($op == 7) {
113                         $mem->[ m2pos($self, 3, $m3) ] =
114                                 m2val($self, 1, $m1)
115                                 < m2val($self, 2, $m2) ? 1 : 0;
116                         $self->{pc} += 4;
117                 } elsif ($op == 8) {
118                         $mem->[ m2pos($self, 3, $m3) ] =
119                                 m2val($self, 1, $m1)
120                                 == m2val($self, 2, $m2) ? 1 : 0;
121                         $self->{pc} += 4;
122                 } elsif ($op == 9) {
123                         $self->{base} += m2val($self, 1, $m1);
124                         $self->{pc} += 2;
125                 } elsif ($op == 99) {
126                         return undef;
127                 }
128         }
129 }
130
131 package main;
132
133 chomp (my @mem = split /,/, <>);
134
135 $; = ',';
136
137 my @comps;
138 for (0 .. 49) {
139         push @comps, IntComp->new(\@mem, [ $_ ]);
140 }
141
142 my @queues;
143 push @queues, [] for 1 .. 50;
144
145 my @nat;
146 my $prev_y;
147
148 while(1) {
149         my $idle = 1;
150         for my $i (0 .. 49) {
151                 my $c = $comps[$i];
152                 my $dst = $c->run;
153                 if (!defined $dst) {
154                         say "$i wants input";
155                         my $q = $queues[$i];
156                         if (defined $q->[0]) {
157                                 my $in = shift @$q;
158                                 $c->input(@$in);
159                                 say "$i received @$in";
160                                 $idle = 0;
161                         } else {
162                                 say "$i queue empty";
163                                 $c->input(-1);
164                         }
165                 } else {
166                         my ($x, $y) = ($c->run, $c->run);
167
168                         say "$i sends $dst $x $y";
169                         $idle = 0;
170                         if ($dst == 255) {
171                                 @nat = ($x, $y);
172                         } else {
173                                 my $q = $queues[$dst];
174                                 push @$q, [$x, $y];
175                         }
176                 }
177         }
178         if ($idle) {
179                 say "all idle, sending ", join(' ', @nat), " to 0";
180                 $comps[0]->input(@nat);
181                 if (defined $prev_y && $nat[1] == $prev_y) {
182                         say "$prev_y sent second time";
183                         exit 0;
184                 }
185                 $prev_y = $nat[1];
186         }
187 }