--- /dev/null
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my $sum;
+$sum += int($_/3)-2 for <>;
+say $sum;
--- /dev/null
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my $sum;
+while (<>) {
+ while (1) {
+ $_ = int($_/3)-2;
+ last if $_ <= 0;
+ $sum += $_;
+ }
+}
+say $sum;
--- /dev/null
+#!/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];
--- /dev/null
+#!/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];
--- /dev/null
+#!/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;
+
--- /dev/null
+#!/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;
+
--- /dev/null
+#!/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;
+
--- /dev/null
+#!/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;
+
--- /dev/null
+#!/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 ]);
--- /dev/null
+#!/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 ]);
--- /dev/null
+#!/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;
+
+
+
+
+
--- /dev/null
+#!/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);
+
+
+
+
+
--- /dev/null
+#!/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;
+
--- /dev/null
+#!/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;
+
--- /dev/null
+#!/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];
--- /dev/null
+#!/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;
+}
--- /dev/null
+#!/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";
+
+
+
--- /dev/null
+#!/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";
+
+
+
--- /dev/null
+#!/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]};
--- /dev/null
+#!/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:
+ }
+}
+
--- /dev/null
+#!/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";
+
+
--- /dev/null
+#!/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";
+}
+
--- /dev/null
+#!/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;
+
+
+
--- /dev/null
+#!/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;
+
+
+
--- /dev/null
+#!/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;
+
--- /dev/null
+#!/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";
+
--- /dev/null
+#!/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};
--- /dev/null
+#!/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;
--- /dev/null
+#!/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