]> www.fi.muni.cz Git - aoc.git/blob - 2019/22.pl
Day 25: examining the input
[aoc.git] / 2019 / 22.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 $; = ',';
124 my @dirs = ([0, -1], [1, 0], [0, 1], [-1, 0]);
125 my ($x, $y, $dir) = (0, 0, 0);
126 my %board = ("0,0" => 1);
127 my $comp =  IntComp->new(\@mem, [ 1 ]);
128
129 my ($minx, $maxx, $miny, $maxy);
130 while (1) {
131         my $rv;
132         while (1) {
133                 $rv = $comp->run;
134                 last if !$comp->{want_input};
135                 $comp->input($board{$x,$y} ? 1 : 0);
136         }
137         last if !defined $rv;
138         $board{$x,$y} = $rv;
139         say "Painted $x,$y = $rv";
140         while (1) {
141                 $rv = $comp->run;
142                 last if !$comp->{want_input};
143                 $comp->input($board{$x,$y} ? 1 : 0);
144         }
145         last if !defined $rv;
146         if ($rv) {
147                 $dir++;
148                 $dir = 0 if $dir > 3;
149         } else {
150                 $dir--;
151                 $dir = 3 if $dir < 0;
152         }
153         $x += $dirs[$dir]->[0];
154         $y += $dirs[$dir]->[1];
155         $minx = $x if !defined $minx || $minx > $x;
156         $miny = $y if !defined $miny || $miny > $y;
157         $maxx = $x if !defined $maxx || $maxx < $x;
158         $maxy = $y if !defined $maxy || $maxy < $y;
159         say "rotated ", $rv ? 'right' : 'left', " and moved to $x, $y";
160 }
161
162 say "x=$minx..$maxx, y=$miny..$maxy";
163 for $y ($miny .. $maxy) {
164         for $x ($minx .. $maxx) {
165                 print $board{$x,$y} ? '#' : ' ';
166         }
167         print "\n";
168 }
169