]> www.fi.muni.cz Git - aoc.git/blob - 2019/26.pl
Day 25: examining the input
[aoc.git] / 2019 / 26.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 my ($maxx, $maxy);
129
130 $mem[0] = 2;
131 my $comp =  IntComp->new(\@mem);
132
133 my @chars = (' ', '#', 'x', '=', 'o');
134 my ($p_x, $b_x, $b_dir);
135 my $score;
136 while (1) {
137         $b_dir = 1;
138         while (defined(my $rv = $comp->run)) {
139                 push @out, $rv;
140                 if (@out == 3) {
141                         if ($out[0] == -1 && $out[1] == 0) {
142                                 $score = $out[2];
143                                 say "Score: $score";
144                         } else {
145                                 $maxx = $out[0] if !defined $maxx || $maxx < $out[0];
146                                 $maxy = $out[1] if !defined $maxy || $maxy < $out[1];
147                                 $m{$out[0],$out[1]} = $out[2];
148                                 $b_x = $out[0] if $out[2] == 4;
149                                 $p_x = $out[0] if $out[2] == 3;
150                         }
151                         @out = ();
152                 }
153         }
154         last if !$comp->{want_input};
155         for my $y (0 .. $maxy) {
156                 for my $x (0 .. $maxx) {
157                         print $chars[ $m{$x,$y} // 0 ];
158                 }
159                 print "\n";
160         }
161         print "\n";
162         if ($p_x > $b_x) {
163                 $comp->input(-1);
164         } elsif ($p_x < $b_x) {
165                 $comp->input(1);
166         } else {
167                 $comp->input(0);
168         }
169 }
170
171 say "Final score: $score";
172