]> www.fi.muni.cz Git - aoc.git/blob - 2019/25.pl
Day 25: examining the input
[aoc.git] / 2019 / 25.pl
1 #!/usr/bin/perl -w
2 #!/usr/bin/perl -w
3
4 use v5.16;
5
6 package IntComp;
7 use bigint;
8
9 sub new {
10         my ($class, $mem, $inputs) = @_;
11         my $self = {
12                 mem => [ @$mem ],
13                 pc  => 0,
14                 want_input => undef,
15                 base => 0,
16         };
17         $self->{inputs} = [ @$inputs ]
18                 if defined $inputs;
19         bless $self, $class;
20 }
21
22 sub m2val {
23         my ($self, $off, $mode) = @_;
24         if ($mode == 0) {
25                 return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ] // 0;
26         } elsif ($mode == 1) {
27                 return $self->{mem}->[$self->{pc} + $off] // 0;
28         } elsif ($mode == 2) {
29                 return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off ] + $self->{base} ] // 0;
30         }
31 }
32
33 sub m2pos {
34         my ($self, $off, $mode) = @_;
35         if ($mode == 0) {
36                 return $self->{mem}->[$self->{pc} + $off];
37         } elsif ($mode == 2) {
38                 return $self->{mem}->[$self->{pc} + $off] + $self->{base};
39         }
40 }
41
42 sub input {
43         my ($self, @input) = @_;
44         push @{ $self->{inputs} }, @input;
45 }
46
47 sub run {
48         my ($self, @input) = @_;
49         my $mem = $self->{mem};
50
51         push @{ $self->{inputs} }, @input;
52         if (defined $self->{want_input}) {
53                 $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
54                 $self->{want_input} = undef;
55         }
56
57         while (1) {
58                 my $opcode = $mem->[$self->{pc}];
59                 # say "pc=", $self->{pc}, " opcode=$opcode";
60                 # say "mem=", join(',', map { $_ // '_' } @{ $self->{mem} });
61                 my $op = int($opcode % 100);
62                 my $m1 = int($opcode / 100) % 10;
63                 my $m2 = int($opcode / 1000) % 10;
64                 my $m3 = int($opcode / 10000) % 10;
65                 if ($op == 1) {
66                         $mem->[ m2pos($self, 3, $m3) ]
67                                 = m2val($self, 1, $m1)
68                                 + m2val($self, 2, $m2);
69                         $self->{pc} += 4;
70                 } elsif ($op == 2) {
71                         $mem->[ m2pos($self, 3, $m3) ]
72                                 = m2val($self, 1, $m1)
73                                 * m2val($self, 2, $m2);
74                         $self->{pc} += 4;
75                 } elsif ($op == 3) {
76                         if (@{ $self->{inputs} }) {
77                                 $mem->[ m2pos($self, 1, $m1) ]
78                                         = shift @{ $self->{inputs} };
79                                 $self->{pc} += 2;
80                         } else {
81                                 $self->{want_input} = m2pos($self, 1, $m1);
82                                 $self->{pc} += 2;
83                                 return undef;
84                         }
85                 } elsif ($op == 4) {
86                         my $val = m2val($self, 1, $m1);
87                         $self->{pc} += 2;
88                         return $val;
89                 } elsif ($op == 5) {
90                         if (m2val($self, 1, $m1)) {
91                                 $self->{pc} = m2val($self, 2, $m2);
92                         } else {
93                                 $self->{pc} += 3;
94                         }
95                 } elsif ($op == 6) {
96                         if (!m2val($self, 1, $m1)) {
97                                 $self->{pc} = m2val($self, 2, $m2);
98                         } else {
99                                 $self->{pc} += 3;
100                         }
101                 } elsif ($op == 7) {
102                         $mem->[ m2pos($self, 3, $m3) ] =
103                                 m2val($self, 1, $m1)
104                                 < m2val($self, 2, $m2) ? 1 : 0;
105                         $self->{pc} += 4;
106                 } elsif ($op == 8) {
107                         $mem->[ m2pos($self, 3, $m3) ] =
108                                 m2val($self, 1, $m1)
109                                 == m2val($self, 2, $m2) ? 1 : 0;
110                         $self->{pc} += 4;
111                 } elsif ($op == 9) {
112                         $self->{base} += m2val($self, 1, $m1);
113                         $self->{pc} += 2;
114                 } elsif ($op == 99) {
115                         return undef;
116                 }
117         }
118 }
119
120 package main;
121
122 chomp (my @mem = split /,/, <>);
123
124 $; = ',';
125
126 my %m;
127 my @out;
128
129 my $comp =  IntComp->new(\@mem);
130 while (defined(my $rv = $comp->run)) {
131         push @out, $rv;
132         if (@out == 3) {
133                 $m{$out[0],$out[1]} = $out[2];
134                 @out = ();
135         }
136 }
137
138 say scalar grep { $_ == 2 } values %m;
139