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