]> www.fi.muni.cz Git - aoc.git/blob - 2019/14.pl
Day 25: examining the input
[aoc.git] / 2019 / 14.pl
1 #!/usr/bin/perl -w
2
3 use v5.16;
4
5 package IntComp;
6
7 sub new {
8         my ($class, $mem, $inputs) = @_;
9         my $self = {
10                 mem => [ @$mem ],
11                 pc  => 0,
12                 want_input => undef,
13         };
14         $self->{inputs} = [ @$inputs ]
15                 if defined $inputs;
16         bless $self, $class;
17 }
18
19 sub m2val {
20         my ($self, $off, $mode) = @_;
21         if ($mode == 0) {
22                 return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ];
23         } elsif ($mode == 1) {
24                 return $self->{mem}->[$self->{pc} + $off];
25         }
26 }
27
28 sub input {
29         my ($self, @input) = @_;
30         push @{ $self->{inputs} }, @input;
31 }
32
33 sub run {
34         my ($self, @input) = @_;
35         my $mem = $self->{mem};
36
37         push @{ $self->{inputs} }, @input;
38         if (defined $self->{want_input}) {
39                 $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
40                 $self->{want_input} = undef;
41         }
42
43         while (1) {
44                 my $opcode = $mem->[$self->{pc}];
45                 say "pc=", $self->{pc}, " opcode=$opcode";
46                 say "mem=", join(',', @{ $self->{mem} });
47                 my $op = int($opcode % 100);
48                 my $m1 = int($opcode / 100) % 10;
49                 my $m2 = int($opcode / 1000) % 10;
50                 if ($op == 1) {
51                         $mem->[ $mem->[$self->{pc}+3] ]
52                                 = m2val($self, 1, $m1)
53                                 + m2val($self, 2, $m2);
54                         $self->{pc} += 4;
55                 } elsif ($op == 2) {
56                         $mem->[ $mem->[$self->{pc}+3] ]
57                                 = m2val($self, 1, $m1)
58                                 * m2val($self, 2, $m2);
59                         $self->{pc} += 4;
60                 } elsif ($op == 3) {
61                         if (@{ $self->{inputs} }) {
62                                 $mem->[ $mem->[$self->{pc} + 1] ]
63                                         = shift @{ $self->{inputs} };
64                                 $self->{pc} += 2;
65                         } else {
66                                 $self->{want_input} = $self->{pc} + 1;
67                                 $self->{pc} += 2;
68                                 return undef;
69                         }
70                 } elsif ($op == 4) {
71                         my $val = m2val($self, 1, $m1);
72                         $self->{pc} += 2;
73                         return $val;
74                 } elsif ($op == 5) {
75                         if (m2val($self, 1, $m1)) {
76                                 $self->{pc} = m2val($self, 2, $m2);
77                         } else {
78                                 $self->{pc} += 3;
79                         }
80                 } elsif ($op == 6) {
81                         if (!m2val($self, 1, $m1)) {
82                                 $self->{pc} = m2val($self, 2, $m2);
83                         } else {
84                                 $self->{pc} += 3;
85                         }
86                 } elsif ($op == 7) {
87                         $mem->[ $mem->[$self->{pc}+3] ] =
88                                 m2val($self, 1, $m1)
89                                 < m2val($self, 2, $m2) ? 1 : 0;
90                         $self->{pc} += 4;
91                 } elsif ($op == 8) {
92                         $mem->[ $mem->[$self->{pc}+3] ] =
93                                 m2val($self, 1, $m1)
94                                 == m2val($self, 2, $m2) ? 1 : 0;
95                         $self->{pc} += 4;
96                 } elsif ($op == 99) {
97                         return undef;
98                 }
99         }
100 }
101
102 package main;
103
104 chomp (my @mem = split /,/, <>);
105
106 my $max;
107 sub run_all {
108         my @perm = @_;
109         my @interps;
110
111         for my $p (@perm) {
112                 push @interps, IntComp->new(\@mem, [ $p ]);
113         }
114
115         my $last_rv;
116         my $rv = 0;
117         ROUND:
118         while (1) {
119                 say "Starting from 0";
120                 for my $int (@interps) {
121                         if (defined $rv) {
122                                 $int->input($rv);
123                         }
124                         $rv = $int->run;
125                         say "Interp returned ", $rv // '_';
126                         next ROUND if !defined $rv && $int->{want_input};
127                 }
128                 if (defined $rv) {
129                         say "Loop returned $rv";
130                         $last_rv = $rv;
131                         next ROUND;
132                 }
133                 last if !defined $rv;
134         }
135         return $last_rv;
136 }
137
138 my $max = 0;
139 sub permute {
140         my ($rem, $used) = @_;
141         for my $i (0 .. $#$rem) {
142                 my @nr = @$rem;
143                 my @in = ($nr[$i], @$used);
144                 splice(@nr, $i, 1);
145                 
146                 if (@nr) {
147                         permute(\@nr, \@in);
148                 } else {
149                         say "Running with perm ", join(',', @in);
150                         my $rv = run_all(@in);
151                         say $rv;
152                         $max = $rv if $max < $rv;
153                 }
154         }
155 }
156
157 permute([ 5 .. 9 ], []);
158
159 say $max;
160