]> www.fi.muni.cz Git - aoc.git/commitdiff
First half of Year 2019
authorJan "Yenya" Kasprzak <kas@fi.muni.cz>
Thu, 24 Nov 2022 15:58:37 +0000 (16:58 +0100)
committerJan "Yenya" Kasprzak <kas@fi.muni.cz>
Thu, 24 Nov 2022 15:58:37 +0000 (16:58 +0100)
29 files changed:
2019/01.pl [new file with mode: 0755]
2019/02.pl [new file with mode: 0755]
2019/03.pl [new file with mode: 0755]
2019/04.pl [new file with mode: 0755]
2019/05.pl [new file with mode: 0755]
2019/06.pl [new file with mode: 0755]
2019/07.pl [new file with mode: 0755]
2019/08.pl [new file with mode: 0755]
2019/09.pl [new file with mode: 0755]
2019/10.pl [new file with mode: 0755]
2019/11.pl [new file with mode: 0755]
2019/12.pl [new file with mode: 0755]
2019/13.pl [new file with mode: 0755]
2019/14.pl [new file with mode: 0755]
2019/15.pl [new file with mode: 0755]
2019/16.pl [new file with mode: 0755]
2019/17.pl [new file with mode: 0755]
2019/18.pl [new file with mode: 0755]
2019/19.pl [new file with mode: 0755]
2019/20.pl [new file with mode: 0755]
2019/21.pl [new file with mode: 0755]
2019/22.pl [new file with mode: 0755]
2019/23.pl [new file with mode: 0755]
2019/24.pl [new file with mode: 0755]
2019/25.pl [new file with mode: 0755]
2019/26.pl [new file with mode: 0755]
2019/27.pl [new file with mode: 0755]
2019/28.pl [new file with mode: 0755]
2019/get.sh [new file with mode: 0755]

diff --git a/2019/01.pl b/2019/01.pl
new file mode 100755 (executable)
index 0000000..946d264
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my $sum;
+$sum += int($_/3)-2 for <>;
+say $sum;
diff --git a/2019/02.pl b/2019/02.pl
new file mode 100755 (executable)
index 0000000..90a125c
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my $sum;
+while (<>) {
+       while (1) {
+               $_ = int($_/3)-2;
+               last if $_ <= 0;        
+               $sum += $_;
+       } 
+}
+say $sum;
diff --git a/2019/03.pl b/2019/03.pl
new file mode 100755 (executable)
index 0000000..a73fcf4
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my @mem = split /,/, <>);
+$mem[1] = 12;
+$mem[2] = 2;
+my $pc = 0;
+while (1) {
+       if ($mem[$pc] == 1) {
+               $mem[ $mem[$pc+3] ] = $mem[ $mem[$pc+1] ] + $mem[ $mem[$pc+2] ];
+       } elsif ($mem[$pc] == 2) {
+               $mem[ $mem[$pc+3] ] = $mem[ $mem[$pc+1] ] * $mem[ $mem[$pc+2] ];
+       } elsif ($mem[$pc] == 99) {
+               last;
+       }
+       $pc += 4;
+}
+
+say $mem[0];
diff --git a/2019/04.pl b/2019/04.pl
new file mode 100755 (executable)
index 0000000..4e43c5d
--- /dev/null
@@ -0,0 +1,31 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my @mem = split /,/, <>);
+
+sub run {
+       my ($m1, $m2, @mem) = @_;
+       $mem[1] = $m1;
+       $mem[2] = $m2;
+       my $pc = 0;
+       while (1) {
+               if ($mem[$pc] == 1) {
+                       $mem[ $mem[$pc+3] ] = $mem[ $mem[$pc+1] ] + $mem[ $mem[$pc+2] ];
+               } elsif ($mem[$pc] == 2) {
+                       $mem[ $mem[$pc+3] ] = $mem[ $mem[$pc+1] ] * $mem[ $mem[$pc+2] ];
+               } elsif ($mem[$pc] == 99) {
+                       last;
+               }
+               $pc += 4;
+       }
+       return $mem[0];
+}
+
+for my $n (0..99) {
+       for my $v (0..99) {
+               say 100*$n + $v if run($n, $v, @mem) == 19690720;
+       }
+}
+
+say $mem[0];
diff --git a/2019/05.pl b/2019/05.pl
new file mode 100755 (executable)
index 0000000..72fb699
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+$; = ',';
+sub walk {
+       my ($desc) = @_;
+       my %rv;
+       my ($x, $y) = (0, 0);
+       for my $step (split /,/, $desc) {
+               my ($dir, $dist) = $step =~ /([A-Z])(\d+)/;
+               my ($dx, $dy);
+               ($dx, $dy) = (1,  0) if $dir eq 'R';
+               ($dx, $dy) = (0,  1) if $dir eq 'D';
+               ($dx, $dy) = (0, -1) if $dir eq 'U';
+               ($dx, $dy) = (-1, 0) if $dir eq 'L';
+               $rv{$x += $dx, $y += $dy} = 1 while $dist--;
+               say "$step -> $x, $y";
+       }
+       return \%rv;
+}
+
+my $p1 = walk(scalar <>);
+my $p2 = walk(scalar <>);
+
+my $dist;
+for my $pos (keys %$p1) {
+       next if !$p2->{$pos};
+       my ($x, $y) = split /,/, $pos;
+       my $d = abs($x)+abs($y);
+       $dist = $d if !$dist || $dist > $d;
+}
+
+say $dist;
+       
diff --git a/2019/06.pl b/2019/06.pl
new file mode 100755 (executable)
index 0000000..b67d12a
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+$; = ',';
+sub walk {
+       my ($desc) = @_;
+       my %rv;
+       my ($x, $y) = (0, 0);
+       my $l = 0;
+       for my $step (split /,/, $desc) {
+               my ($dir, $dist) = $step =~ /([A-Z])(\d+)/;
+               my ($dx, $dy);
+               ($dx, $dy) = (1,  0) if $dir eq 'R';
+               ($dx, $dy) = (0,  1) if $dir eq 'D';
+               ($dx, $dy) = (0, -1) if $dir eq 'U';
+               ($dx, $dy) = (-1, 0) if $dir eq 'L';
+               while ($dist--) {
+                       $x += $dx; $y += $dy; ++$l;
+                       $rv{$x, $y} //= $l;
+               }
+               say "$step -> $x, $y ($rv{$x,$y})";
+       }
+       return \%rv;
+}
+
+my $p1 = walk(scalar <>);
+my $p2 = walk(scalar <>);
+
+my $dist;
+for my $pos (keys %$p1) {
+       next if !$p2->{$pos};
+       next if $pos eq '0,0';
+       my $d = $p1->{$pos}+$p2->{$pos};
+       say "Intersection at $pos dist $d";
+       $dist = $d if !$dist || $dist > $d;
+}
+
+say $dist;
+       
diff --git a/2019/07.pl b/2019/07.pl
new file mode 100755 (executable)
index 0000000..7dce860
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my $count;
+NUM:
+for (347312..805915) {
+       next if !/(.)\1/;
+       my $prev = 0;
+       for my $d (split //) {
+               next NUM if $d < $prev;
+               $prev = $d;
+       }
+       $count++;
+}
+
+say $count;
+
diff --git a/2019/08.pl b/2019/08.pl
new file mode 100755 (executable)
index 0000000..948322f
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my $count;
+NUM:
+for (347312..805915) {
+       for my $d (0 .. 9) {
+               goto FOUND if /$d{2}/ && !/$d{3}/;
+       }
+       next;
+       FOUND:
+       my $prev = 0;
+       for my $d (split //) {
+               next NUM if $d < $prev;
+               $prev = $d;
+       }
+       $count++;
+}
+
+say $count;
+
diff --git a/2019/09.pl b/2019/09.pl
new file mode 100755 (executable)
index 0000000..84f958c
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my @mem = split /,/, <>);
+
+sub m2val {
+       my ($mref, $addr, $mode) = @_;
+       if ($mode == 0) {
+               return $mref->[ $mref->[$addr] ];
+       } elsif ($mode == 1) {
+               return $mref->[$addr];
+       }
+}
+       
+       
+       
+sub run {
+       my ($mref, $iref) = @_;
+       my @mem = @$mref;
+       my @inputs = @$iref;
+       my $pc = 0;
+       while (1) {
+               my $opcode = $mem[$pc];
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               if ($op == 1) {
+                       $mem[ $mem[$pc+3] ] = m2val(\@mem, $pc+1, $m1)
+                               + m2val(\@mem, $pc+2, $m2);
+                       $pc += 4;
+               } elsif ($op == 2) {
+                       $mem[ $mem[$pc+3] ] = m2val(\@mem, $pc+1, $m1)
+                               * m2val(\@mem, $pc+2, $m2);
+                       $pc += 4;
+               } elsif ($op == 3) {
+                       $mem[ $mem[$pc+1] ] = shift @inputs;
+                       $pc += 2;
+               } elsif ($op == 4) {
+                       say m2val(\@mem, $pc+1, $m1);
+                       $pc += 2;
+               } elsif ($op == 99) {
+                       last;
+               }
+       }
+}
+
+run(\@mem, [ 1 ]);
diff --git a/2019/10.pl b/2019/10.pl
new file mode 100755 (executable)
index 0000000..61b4cf8
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my @mem = split /,/, <>);
+
+sub m2val {
+       my ($mref, $addr, $mode) = @_;
+       if ($mode == 0) {
+               return $mref->[ $mref->[$addr] ];
+       } elsif ($mode == 1) {
+               return $mref->[$addr];
+       }
+}
+       
+       
+       
+sub run {
+       my ($mref, $iref) = @_;
+       my @mem = @$mref;
+       my @inputs = @$iref;
+       my $pc = 0;
+       while (1) {
+               my $opcode = $mem[$pc];
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               if ($op == 1) {
+                       $mem[ $mem[$pc+3] ] = m2val(\@mem, $pc+1, $m1)
+                               + m2val(\@mem, $pc+2, $m2);
+                       $pc += 4;
+               } elsif ($op == 2) {
+                       $mem[ $mem[$pc+3] ] = m2val(\@mem, $pc+1, $m1)
+                               * m2val(\@mem, $pc+2, $m2);
+                       $pc += 4;
+               } elsif ($op == 3) {
+                       $mem[ $mem[$pc+1] ] = shift @inputs;
+                       $pc += 2;
+               } elsif ($op == 4) {
+                       say m2val(\@mem, $pc+1, $m1);
+                       $pc += 2;
+               } elsif ($op == 5) {
+                       if (m2val(\@mem, $pc+1, $m1)) {
+                               $pc = m2val(\@mem, $pc+2, $m2);
+                       } else {
+                               $pc += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val(\@mem, $pc+1, $m1)) {
+                               $pc = m2val(\@mem, $pc+2, $m2);
+                       } else {
+                               $pc += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem[ $mem[$pc+3] ] =
+                               m2val(\@mem, $pc+1, $m1)
+                               < m2val(\@mem, $pc+2, $m2) ? 1 : 0;
+                       $pc += 4;
+               } elsif ($op == 8) {
+                       $mem[ $mem[$pc+3] ] =
+                               m2val(\@mem, $pc+1, $m1)
+                               == m2val(\@mem, $pc+2, $m2) ? 1 : 0;
+                       $pc += 4;
+               } elsif ($op == 99) {
+                       last;
+               }
+       }
+}
+
+run(\@mem, [ 5 ]);
diff --git a/2019/11.pl b/2019/11.pl
new file mode 100755 (executable)
index 0000000..fb05dc9
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use List::Util qw(sum);
+
+my %orb;
+while (<>) {
+       chomp;
+       my @b = split /\)/;
+       $orb{$b[0]}{$b[1]} = 1;
+}
+
+my %orbs;
+sub walk {
+       my ($b, $depth) = @_;
+       say "walking $b at $depth";
+       $orbs{$b} = $depth;
+       for my $x (keys %{ $orb{$b} }) {
+               walk($x, $depth+1);     
+       }
+}
+
+walk('COM', 0);
+say sum values %orbs;
+
+               
+               
+               
+
diff --git a/2019/12.pl b/2019/12.pl
new file mode 100755 (executable)
index 0000000..0a83ffd
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use List::Util qw(sum);
+
+my %orb;
+while (<>) {
+       chomp;
+       my @b = split /\)/;
+       $orb{$b[0]}{$b[1]} = 1;
+}
+
+sub walk {
+       my ($b, $depth) = @_;
+       my @rv;
+       $rv[0] = 0 if $b eq 'YOU';
+       $rv[1] = 0 if $b eq 'SAN';
+       say "walking $b at $depth, rv=", ($rv[0] // '_'), ',', ($rv[1] // '_');
+       for my $x (keys %{ $orb{$b} }) {
+               say "$b->$x";
+               my ($v1, $v2) = walk($x, $depth+1);     
+               say "$b<-$x, rv=", ($rv[0] // '_'), ',', ($rv[1] // '_');
+               $rv[0] //= $v1;
+               $rv[1] //= $v2;
+               if (defined $rv[0] && defined $rv[1]) {
+                       say "Back at $b: $rv[0],$rv[1]";
+                       say $rv[0]+$rv[1] - 2;
+                       exit 0;
+               }
+       }
+       $rv[0]++ if defined $rv[0];
+       $rv[1]++ if defined $rv[1];
+       say "returning from $b at $depth, rv=", ($rv[0] // '_'), ',', ($rv[1] // '_');
+       return @rv;
+}
+
+walk('COM', 0);
+
+               
+               
+               
+
diff --git a/2019/13.pl b/2019/13.pl
new file mode 100755 (executable)
index 0000000..9bdf64e
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my @mem = split /,/, <>);
+
+sub m2val {
+       my ($mref, $addr, $mode) = @_;
+       if ($mode == 0) {
+               return $mref->[ $mref->[$addr] ];
+       } elsif ($mode == 1) {
+               return $mref->[$addr];
+       }
+}
+
+sub run {
+       my ($mref, $iref) = @_;
+       my @mem = @$mref;
+       my @inputs = @$iref;
+       my $pc = 0;
+       my @out;
+       while (1) {
+               my $opcode = $mem[$pc];
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               if ($op == 1) {
+                       $mem[ $mem[$pc+3] ] = m2val(\@mem, $pc+1, $m1)
+                               + m2val(\@mem, $pc+2, $m2);
+                       $pc += 4;
+               } elsif ($op == 2) {
+                       $mem[ $mem[$pc+3] ] = m2val(\@mem, $pc+1, $m1)
+                               * m2val(\@mem, $pc+2, $m2);
+                       $pc += 4;
+               } elsif ($op == 3) {
+                       $mem[ $mem[$pc+1] ] = shift @inputs;
+                       $pc += 2;
+               } elsif ($op == 4) {
+                       push @out, m2val(\@mem, $pc+1, $m1);
+                       $pc += 2;
+               } elsif ($op == 5) {
+                       if (m2val(\@mem, $pc+1, $m1)) {
+                               $pc = m2val(\@mem, $pc+2, $m2);
+                       } else {
+                               $pc += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val(\@mem, $pc+1, $m1)) {
+                               $pc = m2val(\@mem, $pc+2, $m2);
+                       } else {
+                               $pc += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem[ $mem[$pc+3] ] =
+                               m2val(\@mem, $pc+1, $m1)
+                               < m2val(\@mem, $pc+2, $m2) ? 1 : 0;
+                       $pc += 4;
+               } elsif ($op == 8) {
+                       $mem[ $mem[$pc+3] ] =
+                               m2val(\@mem, $pc+1, $m1)
+                               == m2val(\@mem, $pc+2, $m2) ? 1 : 0;
+                       $pc += 4;
+               } elsif ($op == 99) {
+                       last;
+               }
+       }
+       return @out;
+}
+
+my $max = 0;
+sub permute {
+       my ($remaining, $input) = @_;
+       for my $i (0 .. $#$remaining) {
+               my @nr = @$remaining;
+               my @in = ($nr[$i], @$input);
+               say "running with ", join(',', @in);
+               splice(@nr, $i, 1);
+               my @rv = run(\@mem, \@in);
+               if (@nr) {
+                       permute(\@nr, \@rv);
+               } else {
+                       say @rv;
+                       $max = $rv[0] if $max < $rv[0];
+               }
+       }
+}
+
+permute([ 0 .. 4 ], [0]);
+
+say $max;
+
diff --git a/2019/14.pl b/2019/14.pl
new file mode 100755 (executable)
index 0000000..8e8388d
--- /dev/null
@@ -0,0 +1,160 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+package IntComp;
+
+sub new {
+       my ($class, $mem, $inputs) = @_;
+       my $self = {
+               mem => [ @$mem ],
+               pc  => 0,
+               want_input => undef,
+       };
+       $self->{inputs} = [ @$inputs ]
+               if defined $inputs;
+       bless $self, $class;
+}
+
+sub m2val {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ];
+       } elsif ($mode == 1) {
+               return $self->{mem}->[$self->{pc} + $off];
+       }
+}
+
+sub input {
+       my ($self, @input) = @_;
+       push @{ $self->{inputs} }, @input;
+}
+
+sub run {
+       my ($self, @input) = @_;
+       my $mem = $self->{mem};
+
+       push @{ $self->{inputs} }, @input;
+       if (defined $self->{want_input}) {
+               $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
+               $self->{want_input} = undef;
+       }
+
+       while (1) {
+               my $opcode = $mem->[$self->{pc}];
+               say "pc=", $self->{pc}, " opcode=$opcode";
+               say "mem=", join(',', @{ $self->{mem} });
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               if ($op == 1) {
+                       $mem->[ $mem->[$self->{pc}+3] ]
+                               = m2val($self, 1, $m1)
+                               + m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 2) {
+                       $mem->[ $mem->[$self->{pc}+3] ]
+                               = m2val($self, 1, $m1)
+                               * m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 3) {
+                       if (@{ $self->{inputs} }) {
+                               $mem->[ $mem->[$self->{pc} + 1] ]
+                                       = shift @{ $self->{inputs} };
+                               $self->{pc} += 2;
+                       } else {
+                               $self->{want_input} = $self->{pc} + 1;
+                               $self->{pc} += 2;
+                               return undef;
+                       }
+               } elsif ($op == 4) {
+                       my $val = m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+                       return $val;
+               } elsif ($op == 5) {
+                       if (m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem->[ $mem->[$self->{pc}+3] ] =
+                               m2val($self, 1, $m1)
+                               < m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 8) {
+                       $mem->[ $mem->[$self->{pc}+3] ] =
+                               m2val($self, 1, $m1)
+                               == m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 99) {
+                       return undef;
+               }
+       }
+}
+
+package main;
+
+chomp (my @mem = split /,/, <>);
+
+my $max;
+sub run_all {
+       my @perm = @_;
+       my @interps;
+
+       for my $p (@perm) {
+               push @interps, IntComp->new(\@mem, [ $p ]);
+       }
+
+       my $last_rv;
+       my $rv = 0;
+       ROUND:
+       while (1) {
+               say "Starting from 0";
+               for my $int (@interps) {
+                       if (defined $rv) {
+                               $int->input($rv);
+                       }
+                       $rv = $int->run;
+                       say "Interp returned ", $rv // '_';
+                       next ROUND if !defined $rv && $int->{want_input};
+               }
+               if (defined $rv) {
+                       say "Loop returned $rv";
+                       $last_rv = $rv;
+                       next ROUND;
+               }
+               last if !defined $rv;
+       }
+       return $last_rv;
+}
+
+my $max = 0;
+sub permute {
+       my ($rem, $used) = @_;
+       for my $i (0 .. $#$rem) {
+               my @nr = @$rem;
+               my @in = ($nr[$i], @$used);
+               splice(@nr, $i, 1);
+               
+               if (@nr) {
+                       permute(\@nr, \@in);
+               } else {
+                       say "Running with perm ", join(',', @in);
+                       my $rv = run_all(@in);
+                       say $rv;
+                       $max = $rv if $max < $rv;
+               }
+       }
+}
+
+permute([ 5 .. 9 ], []);
+
+say $max;
+
diff --git a/2019/15.pl b/2019/15.pl
new file mode 100755 (executable)
index 0000000..38a4607
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my $data = <>);
+
+my @min;
+my $count = 25*6;
+for my $l ($data =~ /.{$count}/g) {
+       say $l;
+       my @x;
+       $x[0] = () = $l =~ /0/g;
+       $x[1] = () = $l =~ /1/g;
+       $x[2] = () = $l =~ /2/g;
+       @min = @x
+               if !defined $min[0] || $min[0] > $x[0];
+}
+
+say $min[1] * $min[2];
diff --git a/2019/16.pl b/2019/16.pl
new file mode 100755 (executable)
index 0000000..79a272d
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my $data = <>);
+
+my @min;
+my $count = 25*6;
+my @p;
+for my $l ($data =~ /.{$count}/g) {
+       my @px = split //, $l;
+       my @p1;
+       for (@px) {
+               my $p0 = shift @p;
+               push @p1, !defined $p0 || $p0 == 2 ? $_ : $p0;
+       }
+       @p = @p1;
+       say "---";
+}
+
+my $i = 0;
+for (@p) {
+       print $_ ? '#' : ' ';
+       print "\n" if ++$i % 25 == 0;
+}
diff --git a/2019/17.pl b/2019/17.pl
new file mode 100755 (executable)
index 0000000..2fb88f6
--- /dev/null
@@ -0,0 +1,128 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+package IntComp;
+use bigint;
+
+sub new {
+       my ($class, $mem, $inputs) = @_;
+       my $self = {
+               mem => [ @$mem ],
+               pc  => 0,
+               want_input => undef,
+               base => 0,
+       };
+       $self->{inputs} = [ @$inputs ]
+               if defined $inputs;
+       bless $self, $class;
+}
+
+sub m2val {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ] // 0;
+       } elsif ($mode == 1) {
+               return $self->{mem}->[$self->{pc} + $off] // 0;
+       } elsif ($mode == 2) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off ] + $self->{base} ] // 0;
+       }
+}
+
+sub m2pos {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[$self->{pc} + $off];
+       } elsif ($mode == 2) {
+               return $self->{mem}->[$self->{pc} + $off] + $self->{base};
+       }
+}
+
+sub input {
+       my ($self, @input) = @_;
+       push @{ $self->{inputs} }, @input;
+}
+
+sub run {
+       my ($self, @input) = @_;
+       my $mem = $self->{mem};
+
+       push @{ $self->{inputs} }, @input;
+       if (defined $self->{want_input}) {
+               $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
+               $self->{want_input} = undef;
+       }
+
+       while (1) {
+               my $opcode = $mem->[$self->{pc}];
+               # say "pc=", $self->{pc}, " opcode=$opcode";
+               # say "mem=", join(',', map { $_ // '_' } @{ $self->{mem} });
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               my $m3 = int($opcode / 10000) % 10;
+               if ($op == 1) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               + m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 2) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               * m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 3) {
+                       if (@{ $self->{inputs} }) {
+                               $mem->[ m2pos($self, 1, $m1) ]
+                                       = shift @{ $self->{inputs} };
+                               $self->{pc} += 2;
+                       } else {
+                               $self->{want_input} = m2pos($self, 1, $m1);
+                               $self->{pc} += 2;
+                               return undef;
+                       }
+               } elsif ($op == 4) {
+                       my $val = m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+                       return $val;
+               } elsif ($op == 5) {
+                       if (m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               < m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 8) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               == m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 9) {
+                       $self->{base} += m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+               } elsif ($op == 99) {
+                       return undef;
+               }
+       }
+}
+
+package main;
+
+chomp (my @mem = split /,/, <>);
+
+my $comp =  IntComp->new(\@mem, [1]);
+print $_,'_' while defined ($_ = $comp->run);
+print "\n";
+
+
+
diff --git a/2019/18.pl b/2019/18.pl
new file mode 100755 (executable)
index 0000000..7e1c0ca
--- /dev/null
@@ -0,0 +1,128 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+package IntComp;
+use bigint;
+
+sub new {
+       my ($class, $mem, $inputs) = @_;
+       my $self = {
+               mem => [ @$mem ],
+               pc  => 0,
+               want_input => undef,
+               base => 0,
+       };
+       $self->{inputs} = [ @$inputs ]
+               if defined $inputs;
+       bless $self, $class;
+}
+
+sub m2val {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ] // 0;
+       } elsif ($mode == 1) {
+               return $self->{mem}->[$self->{pc} + $off] // 0;
+       } elsif ($mode == 2) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off ] + $self->{base} ] // 0;
+       }
+}
+
+sub m2pos {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[$self->{pc} + $off];
+       } elsif ($mode == 2) {
+               return $self->{mem}->[$self->{pc} + $off] + $self->{base};
+       }
+}
+
+sub input {
+       my ($self, @input) = @_;
+       push @{ $self->{inputs} }, @input;
+}
+
+sub run {
+       my ($self, @input) = @_;
+       my $mem = $self->{mem};
+
+       push @{ $self->{inputs} }, @input;
+       if (defined $self->{want_input}) {
+               $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
+               $self->{want_input} = undef;
+       }
+
+       while (1) {
+               my $opcode = $mem->[$self->{pc}];
+               # say "pc=", $self->{pc}, " opcode=$opcode";
+               # say "mem=", join(',', map { $_ // '_' } @{ $self->{mem} });
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               my $m3 = int($opcode / 10000) % 10;
+               if ($op == 1) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               + m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 2) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               * m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 3) {
+                       if (@{ $self->{inputs} }) {
+                               $mem->[ m2pos($self, 1, $m1) ]
+                                       = shift @{ $self->{inputs} };
+                               $self->{pc} += 2;
+                       } else {
+                               $self->{want_input} = m2pos($self, 1, $m1);
+                               $self->{pc} += 2;
+                               return undef;
+                       }
+               } elsif ($op == 4) {
+                       my $val = m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+                       return $val;
+               } elsif ($op == 5) {
+                       if (m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               < m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 8) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               == m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 9) {
+                       $self->{base} += m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+               } elsif ($op == 99) {
+                       return undef;
+               }
+       }
+}
+
+package main;
+
+chomp (my @mem = split /,/, <>);
+
+my $comp =  IntComp->new(\@mem, [2]);
+print $_,'_' while defined ($_ = $comp->run);
+print "\n";
+
+
+
diff --git a/2019/19.pl b/2019/19.pl
new file mode 100755 (executable)
index 0000000..8755717
--- /dev/null
@@ -0,0 +1,73 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %m;
+$; = ',';
+my $y = 0;
+my ($maxx, $maxy);
+while (<>) {
+       chomp;
+       my $x = 0;
+       $maxx = length;
+       for my $c (split //) {
+               $m{$x,$y}++ if $c eq '#';
+               $x++;
+       }
+       $y++;
+}
+$maxy = $y;
+
+my %gcd;
+sub gcd {
+       my ($n1, $n2) = @_;
+       return $gcd{$n1,$n2} //=
+               $n1 == $n2 ? $n1
+               : $n1 > $n2 ? gcd($n2, $n1-$n2)
+               : gcd($n1, $n2-$n1);
+}
+
+my %dir;
+sub dir1 {
+       my ($x, $y) = @_;
+       return (0, 1) if $x == 0 && $y > 0;
+       return (0,-1) if $x == 0 && $y < 0;
+       return (1, 0) if $y == 0 && $x > 0;
+       return (-1,0) if $y == 0 && $x < 0;
+       my $g = gcd(abs($x), abs($y));
+       return ($x/$g, $y/$g);
+}
+
+sub dir {
+       my ($x, $y) = @_;
+       $dir{$x,$y} //= [ dir1($x,$y) ];
+       return @{ $dir{$x,$y} };
+}
+
+my %sum;
+for (keys %m) {
+       my ($x,$y) = split /,/;
+       ASTEROID:
+       for (keys %m) {
+               my ($ax, $ay) = split /,/;
+               next if $ax == $x && $ay == $y;
+               say "testing $ax,$ay from $x,$y";
+               my ($dx, $dy) = dir($ax-$x, $ay-$y);
+               # next if $tried_dir{$dx,$dy}++;
+               say "dx,dy=$dx,$dy";
+               my ($x0, $y0) = ($x+$dx, $y+$dy);
+               while ($x0 != $ax || $y0 != $ay) {
+                       say "x0,y0=$x0,$y0";
+                       if ($m{$x0,$y0}) {
+                               say "$ax,$ay cannot be seen from $x,$y because of $x0,$y0";
+                               next ASTEROID;
+                       }
+                       $x0 += $dx; $y0 += $dy;
+               }
+               say "$ax,$ay CAN be seen from $x,$y";
+               $sum{$x,$y}++;
+       }
+}
+
+my @s = sort { $sum{$b} <=> $sum{$a} } keys %sum;
+say $s[0], '=', $sum{$s[0]};
diff --git a/2019/20.pl b/2019/20.pl
new file mode 100755 (executable)
index 0000000..d34db6f
--- /dev/null
@@ -0,0 +1,124 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %m;
+$; = ',';
+my $y = 0;
+my ($maxx, $maxy);
+while (<>) {
+       chomp;
+       my $x = 0;
+       $maxx = length;
+       for my $c (split //) {
+               $m{$x,$y}++ if $c eq '#';
+               $x++;
+       }
+       $y++;
+}
+$maxy = $y;
+
+my %gcd;
+sub gcd {
+       my ($n1, $n2) = @_;
+       return $gcd{$n1,$n2} //=
+               $n1 == $n2 ? $n1
+               : $n1 > $n2 ? gcd($n2, $n1-$n2)
+               : gcd($n1, $n2-$n1);
+}
+
+my %dir;
+sub dir1 {
+       my ($x, $y) = @_;
+       return (0, 1) if $x == 0 && $y > 0;
+       return (0,-1) if $x == 0 && $y < 0;
+       return (1, 0) if $y == 0 && $x > 0;
+       return (-1,0) if $y == 0 && $x < 0;
+       my $g = gcd(abs($x), abs($y));
+       return ($x/$g, $y/$g);
+}
+
+sub dir {
+       my ($x, $y) = @_;
+       $dir{$x,$y} //= [ dir1($x,$y) ];
+       return @{ $dir{$x,$y} };
+}
+
+my $max_sum;
+my $max_pos;
+my @max_dirs;
+for (keys %m) {
+       my ($x,$y) = split /,/;
+       my $sum;
+       my @dirs;
+       ASTEROID:
+       for (keys %m) {
+               my ($ax, $ay) = split /,/;
+               next if $ax == $x && $ay == $y;
+               # say "testing $ax,$ay from $x,$y";
+               my ($dx, $dy) = dir($ax-$x, $ay-$y);
+               # next if $tried_dir{$dx,$dy}++;
+               # say "dx,dy=$dx,$dy";
+               my ($x0, $y0) = ($x+$dx, $y+$dy);
+               while ($x0 != $ax || $y0 != $ay) {
+                       # say "x0,y0=$x0,$y0";
+                       if ($m{$x0,$y0}) {
+                               # say "$ax,$ay cannot be seen from $x,$y because of $x0,$y0";
+                               next ASTEROID;
+                       }
+                       $x0 += $dx; $y0 += $dy;
+               }
+               # say "$ax,$ay CAN be seen from $x,$y";
+               push @dirs, [$dx, $dy];
+               $sum++;
+       }
+       if (!defined $max_sum || $max_sum < $sum) {
+               $max_sum = $sum;
+               $max_pos = "$x,$y";
+               @max_dirs = @dirs;
+       }
+}
+
+say $max_pos, '=', $max_sum;
+
+my $x;
+($x, $y) = split /,/, $max_pos;
+my @dirs = (
+       (grep { $_->[0] == 0 && $_->[1] < 0 } @max_dirs),
+       (sort { $b->[0]/$b->[1] <=> $a->[0]/$a->[1] }
+               grep { $_->[0] > 0 && $_->[1] < 0 } @max_dirs),
+       (grep { $_->[0] > 0 && $_->[1] == 0 } @max_dirs),
+       (sort { $b->[0]/$b->[1] <=> $a->[0]/$a->[1] }
+               grep { $_->[0] > 0 && $_->[1] > 0 } @max_dirs),
+       (grep { $_->[0] == 0 && $_->[1] > 0 } @max_dirs),
+       (sort { $b->[0]/$b->[1] <=> $a->[0]/$a->[1] }
+               grep { $_->[0] < 0 && $_->[1] > 0 } @max_dirs),
+       (grep { $_->[0] < 0 && $_->[1] == 0 } @max_dirs),
+       (sort { $b->[0]/$b->[1] <=> $a->[0]/$a->[1] }
+               grep { $_->[0] < 0 && $_->[1] < 0 } @max_dirs),
+);
+
+
+my %seen;
+my $count;
+my %skip_dir;
+while (1) {
+       for my $dir (@dirs) {
+               my ($dx,$dy) = @$dir;
+               next if $skip_dir{$dx,$dy};
+               #say "dir $dx,$dy";
+               my ($x0, $y0) = ($x + $dx, $y + $dy);
+               while ($x0 >= 0 && $y0 >= 0 && $x0 < $maxx && $y0 < $maxy) {
+                       if (!$seen{$x0,$y0} && $m{$x0,$y0}) {
+                               $seen{$x0,$y0} = 1;
+                               say ++$count, " at $x0,$y0 dir $dx,$dy (", 100*$x0+$y0, ")";
+                               exit 0 if $count == 200;
+                               goto OUT;
+                       }
+                       $x0 += $dx; $y0 += $dy;
+               }
+               $skip_dir{$dx,$dy}=1;
+       OUT:
+       }
+}
+
diff --git a/2019/21.pl b/2019/21.pl
new file mode 100755 (executable)
index 0000000..f4842d3
--- /dev/null
@@ -0,0 +1,159 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+package IntComp;
+use bigint;
+
+sub new {
+       my ($class, $mem, $inputs) = @_;
+       my $self = {
+               mem => [ @$mem ],
+               pc  => 0,
+               want_input => undef,
+               base => 0,
+       };
+       $self->{inputs} = [ @$inputs ]
+               if defined $inputs;
+       bless $self, $class;
+}
+
+sub m2val {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ] // 0;
+       } elsif ($mode == 1) {
+               return $self->{mem}->[$self->{pc} + $off] // 0;
+       } elsif ($mode == 2) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off ] + $self->{base} ] // 0;
+       }
+}
+
+sub m2pos {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[$self->{pc} + $off];
+       } elsif ($mode == 2) {
+               return $self->{mem}->[$self->{pc} + $off] + $self->{base};
+       }
+}
+
+sub input {
+       my ($self, @input) = @_;
+       push @{ $self->{inputs} }, @input;
+}
+
+sub run {
+       my ($self, @input) = @_;
+       my $mem = $self->{mem};
+
+       push @{ $self->{inputs} }, @input;
+       if (defined $self->{want_input}) {
+               $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
+               $self->{want_input} = undef;
+       }
+
+       while (1) {
+               my $opcode = $mem->[$self->{pc}];
+               # say "pc=", $self->{pc}, " opcode=$opcode";
+               # say "mem=", join(',', map { $_ // '_' } @{ $self->{mem} });
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               my $m3 = int($opcode / 10000) % 10;
+               if ($op == 1) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               + m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 2) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               * m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 3) {
+                       if (@{ $self->{inputs} }) {
+                               $mem->[ m2pos($self, 1, $m1) ]
+                                       = shift @{ $self->{inputs} };
+                               $self->{pc} += 2;
+                       } else {
+                               $self->{want_input} = m2pos($self, 1, $m1);
+                               $self->{pc} += 2;
+                               return undef;
+                       }
+               } elsif ($op == 4) {
+                       my $val = m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+                       return $val;
+               } elsif ($op == 5) {
+                       if (m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               < m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 8) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               == m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 9) {
+                       $self->{base} += m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+               } elsif ($op == 99) {
+                       return undef;
+               }
+       }
+}
+
+package main;
+
+chomp (my @mem = split /,/, <>);
+
+$; = ',';
+my @dirs = ([0, -1], [1, 0], [0, 1], [-1, 0]);
+my ($x, $y, $dir) = (0, 0, 0);
+my %board;
+my $comp =  IntComp->new(\@mem, [ 0 ]);
+
+while (1) {
+       my $rv;
+       while (1) {
+               $rv = $comp->run;
+               last if !$comp->{want_input};
+               $comp->input($board{$x,$y} ? 1 : 0);
+       }
+       last if !defined $rv;
+       $board{$x,$y} = $rv;
+       say "Painted $x,$y = $rv";
+       while (1) {
+               $rv = $comp->run;
+               last if !$comp->{want_input};
+               $comp->input($board{$x,$y} ? 1 : 0);
+       }
+       last if !defined $rv;
+       if ($rv) {
+               $dir++;
+               $dir = 0 if $dir > 3;
+       } else {
+               $dir--;
+               $dir = 3 if $dir < 0;
+       }
+       $x += $dirs[$dir]->[0];
+       $y += $dirs[$dir]->[1];
+       say "rotated ", $rv ? 'right' : 'left', " and moved to $x, $y";
+}
+
+say "painted ", scalar keys %board, " fields";
+
+
diff --git a/2019/22.pl b/2019/22.pl
new file mode 100755 (executable)
index 0000000..581ac56
--- /dev/null
@@ -0,0 +1,169 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+package IntComp;
+use bigint;
+
+sub new {
+       my ($class, $mem, $inputs) = @_;
+       my $self = {
+               mem => [ @$mem ],
+               pc  => 0,
+               want_input => undef,
+               base => 0,
+       };
+       $self->{inputs} = [ @$inputs ]
+               if defined $inputs;
+       bless $self, $class;
+}
+
+sub m2val {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ] // 0;
+       } elsif ($mode == 1) {
+               return $self->{mem}->[$self->{pc} + $off] // 0;
+       } elsif ($mode == 2) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off ] + $self->{base} ] // 0;
+       }
+}
+
+sub m2pos {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[$self->{pc} + $off];
+       } elsif ($mode == 2) {
+               return $self->{mem}->[$self->{pc} + $off] + $self->{base};
+       }
+}
+
+sub input {
+       my ($self, @input) = @_;
+       push @{ $self->{inputs} }, @input;
+}
+
+sub run {
+       my ($self, @input) = @_;
+       my $mem = $self->{mem};
+
+       push @{ $self->{inputs} }, @input;
+       if (defined $self->{want_input}) {
+               $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
+               $self->{want_input} = undef;
+       }
+
+       while (1) {
+               my $opcode = $mem->[$self->{pc}];
+               # say "pc=", $self->{pc}, " opcode=$opcode";
+               # say "mem=", join(',', map { $_ // '_' } @{ $self->{mem} });
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               my $m3 = int($opcode / 10000) % 10;
+               if ($op == 1) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               + m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 2) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               * m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 3) {
+                       if (@{ $self->{inputs} }) {
+                               $mem->[ m2pos($self, 1, $m1) ]
+                                       = shift @{ $self->{inputs} };
+                               $self->{pc} += 2;
+                       } else {
+                               $self->{want_input} = m2pos($self, 1, $m1);
+                               $self->{pc} += 2;
+                               return undef;
+                       }
+               } elsif ($op == 4) {
+                       my $val = m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+                       return $val;
+               } elsif ($op == 5) {
+                       if (m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               < m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 8) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               == m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 9) {
+                       $self->{base} += m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+               } elsif ($op == 99) {
+                       return undef;
+               }
+       }
+}
+
+package main;
+
+chomp (my @mem = split /,/, <>);
+
+$; = ',';
+my @dirs = ([0, -1], [1, 0], [0, 1], [-1, 0]);
+my ($x, $y, $dir) = (0, 0, 0);
+my %board = ("0,0" => 1);
+my $comp =  IntComp->new(\@mem, [ 1 ]);
+
+my ($minx, $maxx, $miny, $maxy);
+while (1) {
+       my $rv;
+       while (1) {
+               $rv = $comp->run;
+               last if !$comp->{want_input};
+               $comp->input($board{$x,$y} ? 1 : 0);
+       }
+       last if !defined $rv;
+       $board{$x,$y} = $rv;
+       say "Painted $x,$y = $rv";
+       while (1) {
+               $rv = $comp->run;
+               last if !$comp->{want_input};
+               $comp->input($board{$x,$y} ? 1 : 0);
+       }
+       last if !defined $rv;
+       if ($rv) {
+               $dir++;
+               $dir = 0 if $dir > 3;
+       } else {
+               $dir--;
+               $dir = 3 if $dir < 0;
+       }
+       $x += $dirs[$dir]->[0];
+       $y += $dirs[$dir]->[1];
+       $minx = $x if !defined $minx || $minx > $x;
+       $miny = $y if !defined $miny || $miny > $y;
+       $maxx = $x if !defined $maxx || $maxx < $x;
+       $maxy = $y if !defined $maxy || $maxy < $y;
+       say "rotated ", $rv ? 'right' : 'left', " and moved to $x, $y";
+}
+
+say "x=$minx..$maxx, y=$miny..$maxy";
+for $y ($miny .. $maxy) {
+       for $x ($minx .. $maxx) {
+               print $board{$x,$y} ? '#' : ' ';
+       }
+       print "\n";
+}
+
diff --git a/2019/23.pl b/2019/23.pl
new file mode 100755 (executable)
index 0000000..64d1d68
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use Data::Dumper;
+
+my (@m, @v);
+while (<>) {
+       my @row = /-?\d+/g;
+       push @m, [ @row ];
+       push @v, [ 0, 0, 0];
+}
+
+for (1 .. 1000) {
+       for my $m1 (0 .. $#m) {
+       for my $m2 (0 .. $#m) {
+               next if $m1 == $m2;
+               for my $c (0 .. 2) {
+                       $v[$m1][$c]++ if $m[$m1][$c] < $m[$m2][$c];
+                       $v[$m1][$c]-- if $m[$m1][$c] > $m[$m2][$c];
+               }
+       } }
+       for my $m1 (0 .. $#m) {
+               for my $c (0 .. 2) {
+                       $m[$m1][$c] += $v[$m1][$c];
+               }
+       }
+       print Dumper \@m, \@v;
+}
+
+my $sum;
+for my $m1 (0 .. $#m) {
+       my ($pot, $kin);
+       for my $c (0 .. 2) {
+               $pot += abs($m[$m1][$c]);
+               $kin += abs($v[$m1][$c]);
+       }
+       $sum += $pot*$kin;
+}
+
+say $sum;
+               
+
+
diff --git a/2019/24.pl b/2019/24.pl
new file mode 100755 (executable)
index 0000000..326e8c3
--- /dev/null
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use Data::Dumper;
+
+my (@m, @v);
+while (<>) {
+       my @row = /-?\d+/g;
+       push @m, [ @row ];
+       push @v, [ 0, 0, 0];
+}
+
+my @states;
+my $rep = 0;
+my @reps;
+my $i = 0;
+while (1) {
+       for my $m1 (0 .. $#m) {
+       for my $m2 (0 .. $#m) {
+               next if $m1 == $m2;
+               for my $c (0 .. 2) {
+                       $v[$m1][$c]++ if $m[$m1][$c] < $m[$m2][$c];
+                       $v[$m1][$c]-- if $m[$m1][$c] > $m[$m2][$c];
+               }
+       } }
+       for my $m1 (0 .. $#m) {
+               for my $c (0 .. 2) {
+                       $m[$m1][$c] += $v[$m1][$c];
+               }
+       }
+       for my $c (0 .. 2) {
+               next if $reps[$c];
+               my $state = join(',', (map { $_->[$c] } @m), (map { $_->[$c] } @v));
+               next unless $states[$c]->{$state}++;
+               $reps[$c] = $i;
+               $rep++;
+       }
+       last if $rep > 2;
+       $i++;
+}
+
+sub gcd {
+       my ($n1, $n2) = @_;
+       while ($n1 != $n2) {
+               ($n1, $n2) = ($n2, $n1) if $n1 < $n2;
+               $n1 -= $n2;
+       }
+       return $n1;
+}
+
+say "reps: ", join(',', @reps);
+my $m = $reps[0]*$reps[1]/gcd($reps[0], $reps[1]);
+$m = $m*$reps[2]/gcd($m, $reps[2]);
+say $m;
+
+my $sum;
+for my $m1 (0 .. $#m) {
+       my ($pot, $kin);
+       for my $c (0 .. 2) {
+               $pot += abs($m[$m1][$c]);
+               $kin += abs($v[$m1][$c]);
+       }
+       $sum += $pot*$kin;
+}
+
+say $sum;
+               
+
+
diff --git a/2019/25.pl b/2019/25.pl
new file mode 100755 (executable)
index 0000000..05d69cf
--- /dev/null
@@ -0,0 +1,139 @@
+#!/usr/bin/perl -w
+#!/usr/bin/perl -w
+
+use v5.16;
+
+package IntComp;
+use bigint;
+
+sub new {
+       my ($class, $mem, $inputs) = @_;
+       my $self = {
+               mem => [ @$mem ],
+               pc  => 0,
+               want_input => undef,
+               base => 0,
+       };
+       $self->{inputs} = [ @$inputs ]
+               if defined $inputs;
+       bless $self, $class;
+}
+
+sub m2val {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ] // 0;
+       } elsif ($mode == 1) {
+               return $self->{mem}->[$self->{pc} + $off] // 0;
+       } elsif ($mode == 2) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off ] + $self->{base} ] // 0;
+       }
+}
+
+sub m2pos {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[$self->{pc} + $off];
+       } elsif ($mode == 2) {
+               return $self->{mem}->[$self->{pc} + $off] + $self->{base};
+       }
+}
+
+sub input {
+       my ($self, @input) = @_;
+       push @{ $self->{inputs} }, @input;
+}
+
+sub run {
+       my ($self, @input) = @_;
+       my $mem = $self->{mem};
+
+       push @{ $self->{inputs} }, @input;
+       if (defined $self->{want_input}) {
+               $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
+               $self->{want_input} = undef;
+       }
+
+       while (1) {
+               my $opcode = $mem->[$self->{pc}];
+               # say "pc=", $self->{pc}, " opcode=$opcode";
+               # say "mem=", join(',', map { $_ // '_' } @{ $self->{mem} });
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               my $m3 = int($opcode / 10000) % 10;
+               if ($op == 1) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               + m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 2) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               * m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 3) {
+                       if (@{ $self->{inputs} }) {
+                               $mem->[ m2pos($self, 1, $m1) ]
+                                       = shift @{ $self->{inputs} };
+                               $self->{pc} += 2;
+                       } else {
+                               $self->{want_input} = m2pos($self, 1, $m1);
+                               $self->{pc} += 2;
+                               return undef;
+                       }
+               } elsif ($op == 4) {
+                       my $val = m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+                       return $val;
+               } elsif ($op == 5) {
+                       if (m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               < m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 8) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               == m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 9) {
+                       $self->{base} += m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+               } elsif ($op == 99) {
+                       return undef;
+               }
+       }
+}
+
+package main;
+
+chomp (my @mem = split /,/, <>);
+
+$; = ',';
+
+my %m;
+my @out;
+
+my $comp =  IntComp->new(\@mem);
+while (defined(my $rv = $comp->run)) {
+       push @out, $rv;
+       if (@out == 3) {
+               $m{$out[0],$out[1]} = $out[2];
+               @out = ();
+       }
+}
+
+say scalar grep { $_ == 2 } values %m;
+
diff --git a/2019/26.pl b/2019/26.pl
new file mode 100755 (executable)
index 0000000..836eb9f
--- /dev/null
@@ -0,0 +1,172 @@
+#!/usr/bin/perl -w
+#!/usr/bin/perl -w
+
+use v5.16;
+
+package IntComp;
+use bigint;
+
+sub new {
+       my ($class, $mem, $inputs) = @_;
+       my $self = {
+               mem => [ @$mem ],
+               pc  => 0,
+               want_input => undef,
+               base => 0,
+       };
+       $self->{inputs} = [ @$inputs ]
+               if defined $inputs;
+       bless $self, $class;
+}
+
+sub m2val {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off] ] // 0;
+       } elsif ($mode == 1) {
+               return $self->{mem}->[$self->{pc} + $off] // 0;
+       } elsif ($mode == 2) {
+               return $self->{mem}->[ $self->{mem}->[$self->{pc} + $off ] + $self->{base} ] // 0;
+       }
+}
+
+sub m2pos {
+       my ($self, $off, $mode) = @_;
+       if ($mode == 0) {
+               return $self->{mem}->[$self->{pc} + $off];
+       } elsif ($mode == 2) {
+               return $self->{mem}->[$self->{pc} + $off] + $self->{base};
+       }
+}
+
+sub input {
+       my ($self, @input) = @_;
+       push @{ $self->{inputs} }, @input;
+}
+
+sub run {
+       my ($self, @input) = @_;
+       my $mem = $self->{mem};
+
+       push @{ $self->{inputs} }, @input;
+       if (defined $self->{want_input}) {
+               $mem->[$self->{want_input}] = shift @{ $self->{inputs} };
+               $self->{want_input} = undef;
+       }
+
+       while (1) {
+               my $opcode = $mem->[$self->{pc}];
+               # say "pc=", $self->{pc}, " opcode=$opcode";
+               # say "mem=", join(',', map { $_ // '_' } @{ $self->{mem} });
+               my $op = int($opcode % 100);
+               my $m1 = int($opcode / 100) % 10;
+               my $m2 = int($opcode / 1000) % 10;
+               my $m3 = int($opcode / 10000) % 10;
+               if ($op == 1) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               + m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 2) {
+                       $mem->[ m2pos($self, 3, $m3) ]
+                               = m2val($self, 1, $m1)
+                               * m2val($self, 2, $m2);
+                       $self->{pc} += 4;
+               } elsif ($op == 3) {
+                       if (@{ $self->{inputs} }) {
+                               $mem->[ m2pos($self, 1, $m1) ]
+                                       = shift @{ $self->{inputs} };
+                               $self->{pc} += 2;
+                       } else {
+                               $self->{want_input} = m2pos($self, 1, $m1);
+                               $self->{pc} += 2;
+                               return undef;
+                       }
+               } elsif ($op == 4) {
+                       my $val = m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+                       return $val;
+               } elsif ($op == 5) {
+                       if (m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 6) {
+                       if (!m2val($self, 1, $m1)) {
+                               $self->{pc} = m2val($self, 2, $m2);
+                       } else {
+                               $self->{pc} += 3;
+                       }
+               } elsif ($op == 7) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               < m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 8) {
+                       $mem->[ m2pos($self, 3, $m3) ] =
+                               m2val($self, 1, $m1)
+                               == m2val($self, 2, $m2) ? 1 : 0;
+                       $self->{pc} += 4;
+               } elsif ($op == 9) {
+                       $self->{base} += m2val($self, 1, $m1);
+                       $self->{pc} += 2;
+               } elsif ($op == 99) {
+                       return undef;
+               }
+       }
+}
+
+package main;
+
+chomp (my @mem = split /,/, <>);
+
+$; = ',';
+
+my %m;
+my @out;
+my ($maxx, $maxy);
+
+$mem[0] = 2;
+my $comp =  IntComp->new(\@mem);
+
+my @chars = (' ', '#', 'x', '=', 'o');
+my ($p_x, $b_x, $b_dir);
+my $score;
+while (1) {
+       $b_dir = 1;
+       while (defined(my $rv = $comp->run)) {
+               push @out, $rv;
+               if (@out == 3) {
+                       if ($out[0] == -1 && $out[1] == 0) {
+                               $score = $out[2];
+                               say "Score: $score";
+                       } else {
+                               $maxx = $out[0] if !defined $maxx || $maxx < $out[0];
+                               $maxy = $out[1] if !defined $maxy || $maxy < $out[1];
+                               $m{$out[0],$out[1]} = $out[2];
+                               $b_x = $out[0] if $out[2] == 4;
+                               $p_x = $out[0] if $out[2] == 3;
+                       }
+                       @out = ();
+               }
+       }
+       last if !$comp->{want_input};
+       for my $y (0 .. $maxy) {
+               for my $x (0 .. $maxx) {
+                       print $chars[ $m{$x,$y} // 0 ];
+               }
+               print "\n";
+       }
+       print "\n";
+       if ($p_x > $b_x) {
+               $comp->input(-1);
+       } elsif ($p_x < $b_x) {
+               $comp->input(1);
+       } else {
+               $comp->input(0);
+       }
+}
+
+say "Final score: $score";
+
diff --git a/2019/27.pl b/2019/27.pl
new file mode 100755 (executable)
index 0000000..6c4764c
--- /dev/null
@@ -0,0 +1,51 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use Data::Dumper;
+use List::Util qw(any);
+
+my %rules;
+while (<>) {
+       chomp;
+       my ($srcs, $dstcount, $dst) = /(.*) => (\d+) (\w+)/;
+       my %srcs = reverse $srcs =~ /(\d+) (\w+)/g;
+       $rules{$dst} = {
+               count => $dstcount,
+               srcs  => \%srcs,
+       };
+}
+
+my (%want, %have);
+$want{FUEL} = 1;
+
+use List::Util qw(first);
+
+my $expanded;
+while (my $w = first { $_ ne 'ORE' && $want{$_} } keys %want) {
+       $expanded = 1;
+       my $r = $rules{$w};
+       my $rcount = int (($want{$w}+$r->{count}-1)/$r->{count});
+       say "want $want{$w} of $w, rule has $r->{count}, need $rcount rules";
+       if ($rcount * $r->{count} > $want{$w}) {
+               $have{$w} = $rcount * $r->{count} - $want{$w};
+       }
+       delete $want{$w};
+       for my $src (keys %{ $r->{srcs} }) {
+               my $need = $r->{srcs}->{$src} * $rcount;
+               if ($have{$src}) {
+                       if ($need >= $have{$src}) {
+                               $need -= $have{$src};
+                               delete $have{$src};
+                       } else {
+                               $have{$src} -= $need;
+                               next;
+                       }
+               }
+               $want{$src} += $need;
+       }
+       say "want: ", join(', ', map { "$want{$_} of $_" } keys %want);
+       say "have: ", join(', ', map { "$have{$_} of $_" } keys %have);
+       say "";
+}
+
+say $want{ORE};
diff --git a/2019/28.pl b/2019/28.pl
new file mode 100755 (executable)
index 0000000..c13b528
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use Data::Dumper;
+use List::Util qw(any);
+
+my %rules;
+while (<>) {
+       chomp;
+       my ($srcs, $dstcount, $dst) = /(.*) => (\d+) (\w+)/;
+       my %srcs = reverse $srcs =~ /(\d+) (\w+)/g;
+       $rules{$dst} = {
+               count => $dstcount,
+               srcs  => \%srcs,
+       };
+}
+
+use List::Util qw(first);
+
+sub fuel_from_ore {
+       my $fuel = shift;
+
+       my (%want, %have);
+       $want{FUEL} = $fuel;
+       while (my $w = first { $_ ne 'ORE' && $want{$_} } keys %want) {
+               my $r = $rules{$w};
+               my $rcount = int (($want{$w}+$r->{count}-1)/$r->{count});
+               # say "want $want{$w} of $w, rule has $r->{count}, need $rcount rules";
+               if ($rcount * $r->{count} > $want{$w}) {
+                       $have{$w} = $rcount * $r->{count} - $want{$w};
+               }
+               delete $want{$w};
+               for my $src (keys %{ $r->{srcs} }) {
+                       my $need = $r->{srcs}->{$src} * $rcount;
+                       if ($have{$src}) {
+                               if ($need >= $have{$src}) {
+                                       $need -= $have{$src};
+                                       delete $have{$src};
+                               } else {
+                                       $have{$src} -= $need;
+                                       next;
+                               }
+                       }
+                       $want{$src} += $need;
+               }
+               # say "want: ", join(', ', map { "$want{$_} of $_" } keys %want);
+               # say "have: ", join(', ', map { "$have{$_} of $_" } keys %have);
+               # say "";
+       }
+       return $want{ORE};
+}
+
+my $low = fuel_from_ore(1);
+say $low;
+my $high = $low;
+
+my $max_ore = 1_000_000_000_000;
+$high *= 2 while fuel_from_ore($high) <= $max_ore;
+
+my $now;
+do {
+       $now = int(($high + $low) / 2);
+       if (fuel_from_ore($now) <= $max_ore) {
+               $low = $now;
+       } else {
+               $high = $now;
+       }
+} while ($low + 1 < $high);
+
+say $low;
diff --git a/2019/get.sh b/2019/get.sh
new file mode 100755 (executable)
index 0000000..68b3188
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+DAY=`date +%e|sed 's/ //g'`
+test -n "$1" && DAY="$1"
+FILE="$((2*DAY - 1))in.txt"
+COOKIE=`cat cookie`
+
+START="6:00:02"
+MAXWAIT=300
+STARTSEC=`date -d "$START" "+%s"`
+NOW=`date "+%s"`
+WAITSEC=`expr $STARTSEC - $NOW`
+
+if [ $WAITSEC -gt 0 -a $WAITSEC -lt $MAXWAIT ]
+then
+       echo "Waiting for $WAITSEC seconds till $START for getting $FILE ..."
+       sleep $WAITSEC
+fi
+
+URL="https://adventofcode.com/2019/day/$DAY/input"
+echo
+echo "Downloading $URL to $FILE"
+curl -s -b "$COOKIE" "$URL" --output "$FILE"
+echo ========================================================================
+cat "$FILE"
+echo ========================================================================
+echo "lines words chars"
+wc "$FILE"
+echo