]> www.fi.muni.cz Git - aoc.git/commitdiff
Merge branch 'aoc2021'
authorJan "Yenya" Kasprzak <kas@fi.muni.cz>
Mon, 3 Jan 2022 18:03:20 +0000 (19:03 +0100)
committerJan "Yenya" Kasprzak <kas@fi.muni.cz>
Mon, 3 Jan 2022 18:03:20 +0000 (19:03 +0100)
50 files changed:
.gitignore [new file with mode: 0644]
2021/01.pl [new file with mode: 0755]
2021/02.pl [new file with mode: 0755]
2021/03.pl [new file with mode: 0755]
2021/04.pl [new file with mode: 0755]
2021/05.pl [new file with mode: 0755]
2021/06.pl [new file with mode: 0755]
2021/07.pl [new file with mode: 0755]
2021/08.pl [new file with mode: 0755]
2021/09.pl [new file with mode: 0755]
2021/10.pl [new file with mode: 0755]
2021/11.pl [new file with mode: 0755]
2021/12.pl [new file with mode: 0755]
2021/13.pl [new file with mode: 0755]
2021/14.pl [new file with mode: 0755]
2021/15.pl [new file with mode: 0755]
2021/16.pl [new file with mode: 0755]
2021/17.pl [new file with mode: 0755]
2021/18.pl [new file with mode: 0755]
2021/19.pl [new file with mode: 0755]
2021/20.pl [new file with mode: 0755]
2021/21.pl [new file with mode: 0755]
2021/22.pl [new file with mode: 0755]
2021/23.pl [new file with mode: 0755]
2021/24.pl [new file with mode: 0755]
2021/25.pl [new file with mode: 0755]
2021/26.pl [new file with mode: 0755]
2021/27.pl [new file with mode: 0755]
2021/28.pl [new file with mode: 0755]
2021/29.pl [new file with mode: 0755]
2021/30.pl [new file with mode: 0755]
2021/31.pl [new file with mode: 0755]
2021/32.pl [new file with mode: 0755]
2021/34.pl [new file with mode: 0755]
2021/35.pl [new file with mode: 0755]
2021/36.pl [new file with mode: 0755]
2021/37.pl [new file with mode: 0755]
2021/38.pl [new file with mode: 0755]
2021/39.pl [new file with mode: 0755]
2021/41.pl [new file with mode: 0755]
2021/42.pl [new file with mode: 0755]
2021/43.pl [new file with mode: 0755]
2021/44.pl [new file with mode: 0755]
2021/45.pl [new file with mode: 0755]
2021/46.pl [new file with mode: 0755]
2021/47.pl [new file with mode: 0755]
2021/48.pl [new file with mode: 0755]
2021/49.pl [new file with mode: 0755]
2021/get.sh [new file with mode: 0755]
2021/leaderboard [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..36a44fd
--- /dev/null
@@ -0,0 +1,6 @@
+.*.swp
+*in.txt
+*test.txt
+cache-*.json
+cookie
+id.txt
diff --git a/2021/01.pl b/2021/01.pl
new file mode 100755 (executable)
index 0000000..f1912b2
--- /dev/null
@@ -0,0 +1,14 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+my $prev;
+my $inc;
+while (<>) {
+       chomp;
+       $inc++ if $prev && $_ > $prev;
+       $prev = $_;
+}
+
+print $inc, "\n";
+
diff --git a/2021/02.pl b/2021/02.pl
new file mode 100755 (executable)
index 0000000..b9fbfb5
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+chomp (my @a = <>);
+my $prev;
+my $inc;
+
+for my $i (0 .. $#a-2) {
+       my $sum = $a[$i]+$a[$i+1]+$a[$i+2];
+       $inc++ if $prev && $sum > $prev;
+       $prev = $sum;
+}
+
+print "$inc\n";
diff --git a/2021/03.pl b/2021/03.pl
new file mode 100755 (executable)
index 0000000..47683ee
--- /dev/null
@@ -0,0 +1,13 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my ($x, $z) = (0, 0);
+while (<>) {
+       my ($dir, $num) = split /\s+/;
+       $x+=$num if $dir eq 'forward';
+       $z+=$num if $dir eq 'down';
+       $z-=$num if $dir eq 'up';
+}
+say $x*$z;
+
diff --git a/2021/04.pl b/2021/04.pl
new file mode 100755 (executable)
index 0000000..78106cf
--- /dev/null
@@ -0,0 +1,16 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my ($x, $z, $aim) = (0, 0, 0);
+while (<>) {
+       my ($dir, $num) = split /\s+/;
+       if ($dir eq 'forward') {
+               $x += $num;
+               $z += $aim*$num;
+       }
+       $aim+=$num if $dir eq 'down';
+       $aim-=$num if $dir eq 'up';
+}
+say $x*$z;
+
diff --git a/2021/05.pl b/2021/05.pl
new file mode 100755 (executable)
index 0000000..7fd647b
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my ($c, @s);
+
+while (<>) {
+       $c++;
+       chomp;
+       my $i = 0;
+       for my $b (split//) {
+               $s[$i++] += $b;
+       }
+}
+
+my ($e, $g);
+for my $b (@s) {
+       $e .= ($b > $c/2) ? '1' : '0';
+       $g .= ($b > $c/2) ? '0' : '1';
+}
+
+say oct("0b$e")*oct("0b$g");
+
diff --git a/2021/06.pl b/2021/06.pl
new file mode 100755 (executable)
index 0000000..ed4aed2
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my ($c, @s);
+
+chomp (my @nums = <>);
+$c = @nums;
+
+my @n = @nums;
+my $pos = 0;
+while (@n > 1) {
+       my $ones = grep { substr ($_, $pos, 1) eq '1' } @n;
+       if ($ones >= @n/2) {
+               @n = grep { substr ($_, $pos, 1) eq '1' } @n;
+       } else { 
+               @n = grep { substr ($_, $pos, 1) eq '0' } @n;
+       }
+       $pos++;
+}
+my $ox = oct "0b".$n[0];
+
+@n = @nums;
+$pos = 0;
+while (@n > 1) {
+       my $ones = grep { substr ($_, $pos, 1) eq '0' } @n;
+       if ($ones > @n/2) {
+               @n = grep { substr ($_, $pos, 1) eq '1' } @n;
+       } else { 
+               @n = grep { substr ($_, $pos, 1) eq '0' } @n;
+       }
+       $pos++;
+}
+my $co = oct "0b".$n[0];
+
+say $ox * $co;
+
diff --git a/2021/07.pl b/2021/07.pl
new file mode 100755 (executable)
index 0000000..d41536a
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+$/ = "\n\n";
+
+my @drawn = split/[,\s]/, <>;
+my @boards = <>;
+
+for my $d (@drawn) {
+       for my $board (@boards) {
+               $board =~ s/\b$d\b/' ' x length $d/e;
+               if ($board =~ / {14}/
+                       || $board =~ /\s{3}(?:.{12}\s{3}){4}/xms) {
+                       $board =~ s/(?<=\d)\s+(?=\d)/+/gxms;
+                       say eval "$d*($board)";
+                       exit;
+               }
+       }
+}
+
diff --git a/2021/08.pl b/2021/08.pl
new file mode 100755 (executable)
index 0000000..2315874
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+$/ = "\n\n";
+
+my @drawn = split/[,\s]/, <>;
+my @boards = <>;
+my $remaining = @boards;
+
+for my $d (@drawn) {
+       for my $board (@boards) {
+               $board =~ s/\b$d\b/' ' x length $d/e;
+               if ($board =~ / {14}/
+                       || $board =~ /\s{3}(?:.{12}\s{3}){4}/xms) {
+                       if (--$remaining) {
+                               $board = 'x';
+                               next;
+                       }
+                       $board =~ s/(?<=\d)\s+(?=\d)/+/gxms;
+                       say eval "$d*($board)";
+                       exit;
+               }
+       }
+}
+
diff --git a/2021/09.pl b/2021/09.pl
new file mode 100755 (executable)
index 0000000..11d9003
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my $p;
+my $count;
+while (<>) {
+       my ($x1, $y1, $x2, $y2) = /(\d+),(\d+) -> (\d+),(\d+)/;
+       next if $x1 != $x2 && $y1 != $y2;
+       if ($x1 != $x2) {
+               if ($x1 > $x2) {
+                       ($x1, $x2) = ($x2, $x1);
+               }
+               for my $x ($x1 .. $x2) {
+                       $count++ if ++$p->{$x}->{$y1} == 2;
+               }
+       } else {
+               if ($y1 > $y2) {
+                       ($y1, $y2) = ($y2, $y1);
+               }
+               for my $y ($y1 .. $y2) {
+                       $count++ if ++$p->{$x1}->{$y} == 2;
+               }
+       }
+}
+
+say $count;
+
diff --git a/2021/10.pl b/2021/10.pl
new file mode 100755 (executable)
index 0000000..908bfd6
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my $p;
+my $count;
+while (<>) {
+       my ($x1, $y1, $x2, $y2) = /(\d+),(\d+) -> (\d+),(\d+)/;
+       # say "   $x1, $y1 -> $x2, $y2";
+       my $xi = $x2 > $x1 ? 1 : $x2 == $x1 ? 0 : -1;
+       my $yi = $y2 > $y1 ? 1 : $y2 == $y1 ? 0 : -1;
+       # say "   $xi, $yi";
+       
+       my ($x, $y) = ($x1, $y1);
+       do {
+               # say "$x, $y";
+               $count++ if ++$p->{$x}->{$y} == 2;
+               $x += $xi; $y += $yi;
+       } while ($x != $x2+$xi || $y != $y2+$yi);
+}
+
+say $count;
+
diff --git a/2021/11.pl b/2021/11.pl
new file mode 100755 (executable)
index 0000000..18e31c7
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @timers;
+
+for (split /,/, <>) {
+       $timers[$_]++;
+}
+
+my $days = 80;
+
+while ($days--) {
+       my $zero = shift @timers;
+       $timers[6]+=$zero;
+       $timers[8]+=$zero;
+}
+
+my $sum = 0;
+$sum += $_ for @timers;
+
+say $sum;
+
+       
+
diff --git a/2021/12.pl b/2021/12.pl
new file mode 100755 (executable)
index 0000000..990aac6
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @timers;
+
+for (split /,/, <>) {
+       $timers[$_]++;
+}
+
+my $days = 256;
+
+while ($days--) {
+       my $zero = shift @timers;
+       $timers[6]+=$zero;
+       $timers[8]+=$zero;
+}
+
+my $sum = 0;
+$sum += $_ for @timers;
+
+say $sum;
+
+       
+
diff --git a/2021/13.pl b/2021/13.pl
new file mode 100755 (executable)
index 0000000..79740a3
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @c = split /[,\s]/, <>;
+
+my $max;
+($max = !$max || $max < $_ ? $_ : $max) for @c;
+
+my $min_f;
+for my $pos (0 .. $max) {
+       my $f = 0;
+       $f += abs($_ - $pos) for @c;
+       $min_f = $f if !$min_f || $min_f > $f;
+       # say "$pos $f $min_f";
+}
+
+say $min_f;
diff --git a/2021/14.pl b/2021/14.pl
new file mode 100755 (executable)
index 0000000..3822e47
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @c = split /[,\s]/, <>;
+
+my $max;
+($max = !$max || $max < $_ ? $_ : $max) for @c;
+
+my $min_f;
+for my $pos (0 .. $max) {
+       my $f = 0;
+       for my $c1 (@c) {
+               my $dist = abs($c1 - $pos);
+               $f += $dist * ($dist+1) /2;
+       }
+       $min_f = $f if !$min_f || $min_f > $f;
+       # say "$pos $f $min_f";
+}
+
+say $min_f;
diff --git a/2021/15.pl b/2021/15.pl
new file mode 100755 (executable)
index 0000000..19d53b8
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %l = map { $_ => 1 } qw(2 3 4 7);
+my $sum;
+while (<>) {
+       chomp;
+       s/.*\| //;
+       $sum += grep { $l{length()} } split /\s+/;
+}
+
+say $sum;
+
+
+
+
+
diff --git a/2021/16.pl b/2021/16.pl
new file mode 100755 (executable)
index 0000000..86d8dfb
--- /dev/null
@@ -0,0 +1,67 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %digits = (
+       abcefg  => 0,
+       cf      => 1,
+       acdeg   => 2,
+       acdfg   => 3,
+       bcdf    => 4,
+       abdfg   => 5,
+       abdefg  => 6,
+       acf     => 7,
+       abcdefg => 8,
+       abcdfg  => 9,
+);
+
+my @perms;
+
+sub do_perms {
+       my ($t, @vals) = @_;
+       if (@vals == 1) {
+               push @perms, $t.$vals[0];
+       } else {
+               for my $i (0 .. $#vals) {
+                       my @v1 = @vals;
+                       my $u = splice @v1, $i, 1;
+                       do_perms("$t$u", @v1);
+               }
+       }
+}
+
+do_perms('', qw(a b c d e f g));
+
+sub permute {
+       my ($val, $perm) = @_;
+       eval "\$val =~ y/abcdefg/$perm/";
+       join('', sort split //, $val);
+}
+
+my $sum = 0;
+ROW:
+while (<>) {
+       chomp;
+       my ($inv, $outv) = split /\s+\|\s+/;
+       my (@in) = sort { length $a <=> length $b } split /\s+/, $inv;
+       # say "$inv => ", join(' ', @in);
+       my (@out) = split /\s+/, $outv;
+
+       PERM: for my $perm (@perms) {
+               for my $i (@in) {
+                       my $ni = permute($i, $perm);
+                       next PERM if !defined $digits{$ni};
+               }
+               my $rv;
+               for my $o (@out) {
+                       my $no = permute($o, $perm);
+                       $rv .= $digits{$no};
+               }
+               $sum += $rv;
+               next ROW;
+       }
+}
+
+say $sum;
+                       
+               
diff --git a/2021/17.pl b/2021/17.pl
new file mode 100755 (executable)
index 0000000..e4d2707
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @m = map { chomp; [ split // ]; } <>; 
+my $maxy = $#m;
+my $maxx = $#{$m[0]};
+say "$maxx x $maxy";
+
+my $sum;
+for my $y (0 .. $maxy) {
+       for my $x (0 .. $maxx) {
+               my $val = $m[$y][$x];
+               next if $y > 0     && $m[$y-1][$x] <= $val;
+               next if $y < $maxy && $m[$y+1][$x] <= $val;
+               next if $x > 0     && $m[$y][$x-1] <= $val;
+               next if $x < $maxx && $m[$y][$x+1] <= $val;
+               say "found at $x $y";
+               $sum += $val + 1;
+       }
+}
+
+say $sum;
+
diff --git a/2021/18.pl b/2021/18.pl
new file mode 100755 (executable)
index 0000000..f328873
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @m = map { chomp; [ split // ]; } <>; 
+my $maxy = $#m;
+my $maxx = $#{$m[0]};
+
+my @basins;
+my $max_id = 0;
+my @prev_row;
+for my $row (@m) {
+       my $prev_l = undef;
+       for my $i (0 .. $#$row) {
+               my $b_id;
+               if ($row->[$i] == 9) {
+                       $b_id = undef;
+               } elsif (!$prev_l && !$prev_row[$i]) {
+                       $b_id = ++$max_id;
+               } elsif (!$prev_l) {
+                       $b_id = $prev_row[$i];
+               } elsif (!$prev_row[$i] || $prev_l == $prev_row[$i]) {
+                       $b_id = $prev_l;
+               } else { # merge
+                       $b_id = $prev_row[$i];
+                       $basins[$b_id] += $basins[$prev_l];
+                       $basins[$prev_l] = undef;
+                       for my $j (0 .. $#$row) {
+                               next if !$row->[$j] || $row->[$j] != $prev_l;
+                               $row->[$j] = $b_id;
+                       }
+                       for my $j (0 .. $#$row) {
+                               next if !$prev_row[$j] || $prev_row[$j] != $prev_l;
+                               $prev_row[$j] = $b_id;
+                       }
+               }
+               $prev_l = $b_id;
+               $row->[$i] = $b_id;
+               $basins[$b_id]++ if defined $b_id;
+       }
+       @prev_row = @$row;
+}
+
+@basins = sort { $b <=> $a } grep { defined $_ } @basins;
+
+say $basins[0]*$basins[1]*$basins[2];
+
+
+
diff --git a/2021/19.pl b/2021/19.pl
new file mode 100755 (executable)
index 0000000..419030b
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %score_of = (
+       ')' => 3,
+       ']' => 57,
+       '}' => 1197,
+       '>' => 25137,
+);
+
+my $sum;
+while (<>) {
+       chomp;
+       1 while s/\(\)|\[\]|\{\}|\<\>//;
+       s/^[\(\[\{\<]*//;
+       next if !length;
+       $sum += $score_of{substr($_, 0,1)};
+}
+
+say $sum;
+
diff --git a/2021/20.pl b/2021/20.pl
new file mode 100755 (executable)
index 0000000..30f517f
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %score_of = (
+       '(' => 1,
+       '[' => 2,
+       '{' => 3,
+       '<' => 4,
+);
+
+my @sums;
+while (<>) {
+       chomp;
+       my $sum = 0;
+       1 while s/\(\)|\[\]|\{\}|\<\>//;
+        next if /[\)\]\}\>]/;
+       next if !length;
+       for my $c (reverse split //) {
+               $sum *= 5;
+               $sum += $score_of{$c};
+       }
+       push @sums, $sum;
+}
+
+@sums = sort { $a <=> $b } @sums;
+say $sums[@sums/2];
+
diff --git a/2021/21.pl b/2021/21.pl
new file mode 100755 (executable)
index 0000000..8bbba21
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @m = map { chomp; [ split // ] } <>;
+
+my $sum;
+for (1 .. 100) {
+       my %f;
+       my @q;
+       for my $x (0 .. 9) {
+       for my $y (0 .. 9) {
+               next if $f{$x,$y};
+               next if ++$m[$y][$x] < 10;
+               $f{$x,$y} = 1;
+               push @q, [$x,$y];
+               say "flashed:$x,$y";
+       } }
+       while (@q) {
+               my $p = shift @q;
+               my ($x2, $y2) = @$p;
+
+               for my $dx (-1 .. 1) {
+               for my $dy (-1 .. 1) {
+                       next if $dx == 0 && $dy == 0;
+                       next if $x2+$dx < 0 || $x2+$dx > 9;
+                       next if $y2+$dy < 0 || $y2+$dy > 9;
+                       next if $f{$x2+$dx,$y2+$dy};
+                       say $x2+$dx, ',', $y2+$dy, ' >',$m[$y2+$dy][$x2+$dx];
+                       next if ++$m[$y2+$dy][$x2+$dx] < 10;
+                       $f{$x2+$dx,$y2+$dy} = 1;
+                       push @q, [$x2+$dx, $y2+$dy];
+                       say "flashed ", $x2+$dx,',',$y2+$dy;
+               } }
+       }
+       for my $p (keys %f) {
+               my ($x, $y) = split /$;/, $p;
+               $m[$y][$x] = 0;
+       }
+       say "Step $_ flashes ", scalar keys %f;
+       say join("\n", map { join('', @$_) } @m);
+       say;
+       # last if $_ > 1;
+       $sum += keys %f;
+}
+
+say $sum;
+
diff --git a/2021/22.pl b/2021/22.pl
new file mode 100755 (executable)
index 0000000..9915675
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @m = map { chomp; [ split // ] } <>;
+
+my $step = 0;
+while (++$step) {
+       my (%f, @q);
+       for my $x (0 .. 9) {
+       for my $y (0 .. 9) {
+               next if ++$m[$y][$x] < 10;
+               $f{$x,$y} = 1;
+               push @q, [$x, $y];
+       } }
+       while (my $p = shift @q) {
+               my ($x, $y) = @$p;
+
+               for my $dx (-1 .. 1) {
+               for my $dy (-1 .. 1) {
+                       my ($x2, $y2) = ($x+$dx, $y+$dy);
+                       next if $x2 < 0 || $x2 > 9;
+                       next if $y2 < 0 || $y2 > 9;
+                       next if $f{$x2,$y2};
+                       next if ++$m[$y2][$x2] < 10;
+                       $f{$x2,$y2} = 1;
+                       push @q, [$x2, $y2];
+               } }
+       }
+       for my $p (keys %f) {
+               my ($x, $y) = split /$;/, $p;
+               $m[$y][$x] = 0;
+       }
+       say "Step $step flashes ", scalar keys %f;
+       say join("\n", map { join('', @$_) } @m);
+       say '';
+       last if keys %f == 100;
+}
+
+say $step;
+
diff --git a/2021/23.pl b/2021/23.pl
new file mode 100755 (executable)
index 0000000..1cb99a6
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %g;
+while (<>) {
+       chomp;
+       my ($n1, $n2) = split /-/;
+       $g{$n1}->{$n2} = 1;
+       $g{$n2}->{$n1} = 1;
+}
+
+my @paths;
+my %subpaths;
+
+sub walk {
+       my (@path) = @_;
+       my $here = $path[-1];
+       my %visited = map { $_ => 1 } grep { /[a-z]/ } @path;
+
+       for my $node (keys %{ $g{$here} }) {
+               next if $visited{$node};
+               if ($node eq 'end') {
+                       push @paths, [ @path, $node ];
+                       say join('-', @{ $paths[-1] });
+               } else {
+                       my $p = join('-', @path, $node);
+                       next if $subpaths{$p}++;
+                       walk(@path, $node);
+               }
+       }
+}
+
+walk('start');
+
+say scalar @paths;
+               
+
diff --git a/2021/24.pl b/2021/24.pl
new file mode 100755 (executable)
index 0000000..de622d8
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %g;
+while (<>) {
+       chomp;
+       my ($n1, $n2) = split /-/;
+       $g{$n1}->{$n2} = 1;
+       $g{$n2}->{$n1} = 1;
+}
+
+my @paths;
+my %subpaths;
+
+sub walk {
+       my (@path) = @_;
+       my $here = $path[-1];
+       my %visited;
+       $visited{$_}++ for grep { /[a-z]/ } @path;
+       my $two = grep { $_ == 2 } values %visited;
+
+       for my $node (keys %{ $g{$here} }) {
+               next if $visited{$node}
+                       && ($two || $node eq 'start' || $node eq 'end');
+               my $p = join('-', @path, $node);
+               next if $subpaths{$p}++;
+               if ($node eq 'end') {
+                       push @paths, [ @path, $node ];
+                       say join('-', @path, $node);
+               } else {
+                       walk(@path, $node);
+               }
+       }
+}
+
+walk('start');
+
+say scalar @paths;
+               
+
diff --git a/2021/25.pl b/2021/25.pl
new file mode 100755 (executable)
index 0000000..ceeb16f
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %dots;
+
+while (<>) {
+       chomp;
+       my ($x, $y) = split /,/;
+       last if !defined $y;
+       $dots{$x}{$y}++;
+}
+
+my ($maxx, $maxy);
+while (<>) {
+       chomp;
+       my ($axis, $val) = /fold along (.)=(\d+)/;
+
+       for my $x (keys %dots) {
+       for my $y (keys %{$dots{$x}}) {
+               if ($axis eq 'x' && $x > $val) {
+                       $dots{2*$val - $x}{$y}++;
+                       delete $dots{$x}{$y};
+               } elsif ($axis eq 'y' && $y > $val) {
+                       $dots{$x}{2*$val - $y}++;
+                       delete $dots{$x}{$y};
+               }
+       } }
+       last;
+}
+
+my $sum;
+for my $x (keys %dots) {
+       $sum += keys %{$dots{$x}};
+}
+
+say $sum;
+
diff --git a/2021/26.pl b/2021/26.pl
new file mode 100755 (executable)
index 0000000..adfba38
--- /dev/null
@@ -0,0 +1,37 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my %dots;
+$; = ',';
+while (<>) {
+       chomp;
+       last if !length;
+       $dots{$_}++;
+}
+
+my %max;
+while (<>) {
+       chomp;
+       my ($axis, $val) = /fold along (.)=(\d+)/;
+       $max{$axis} = $val;
+
+       for (keys %dots) {
+               my ($x, $y) = split /,/;
+               if ($axis eq 'x' && $x > $val) {
+                       $dots{2*$val - $x,$y}++;
+                       delete $dots{$x,$y};
+               } elsif ($axis eq 'y' && $y > $val) {
+                       $dots{$x,2*$val - $y}++;
+                       delete $dots{$x,$y};
+               }
+       }
+}
+
+for my $y (0 .. $max{y}) {
+       for my $x (0 .. $max{x}) {
+               print $dots{$x,$y} ? '#' : ' ';
+       }
+       print "\n";
+}
+
diff --git a/2021/27.pl b/2021/27.pl
new file mode 100755 (executable)
index 0000000..d07c3ae
--- /dev/null
@@ -0,0 +1,36 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my $tmpl = <>);
+scalar <>;
+
+my %r;
+while (<>) {
+       chomp;
+       my ($s1, $s2, $d) = /([A-Z])/g;
+       $r{"$s1$s2"} = "$s1$d$s2";
+}
+
+for (1 .. 10) {
+       my $i = 0;
+       while ($i < length $tmpl) {
+               my $s = substr($tmpl, $i, 2);
+               if ($r{$s}) {
+                       substr($tmpl, $i, 2) = $r{$s};
+                       $i+=2;
+                       next;
+               }
+               $i++;
+       }
+}
+
+my %count;
+for ('A' .. 'Z') {
+       $count{$_} = () = $tmpl =~ /$_/g;
+}
+
+my @count = sort { $a <=> $b } grep { $_ > 0 } values %count;
+
+say $count[-1] - $count[0];
+
diff --git a/2021/28.pl b/2021/28.pl
new file mode 100755 (executable)
index 0000000..d07c23c
--- /dev/null
@@ -0,0 +1,35 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my $tmpl = <>);
+scalar <>;
+
+my %rules;
+while (<>) {
+       chomp;
+       my ($s1, $s2, $d) = /[A-Z]/g;
+       $rules{"$s1$s2"} = [ "$s1$d", "$d$s2", $d ];
+}
+
+my (%pairs, %count);
+for my $i (0 .. length($tmpl) - 2) {
+       $pairs{substr($tmpl, $i, 2)}++;
+       $count{substr($tmpl, $i, 1)}++;
+}
+$count{substr($tmpl, -1, 1)}++;
+
+for (1 .. 40) {
+       my %newp;
+       for my $pair (grep { $rules{$_} } keys %pairs) {
+               my $rule = $rules{$pair};
+                $newp{ $rule->[0] } += $pairs{$pair};
+                $newp{ $rule->[1] } += $pairs{$pair};
+               $count{ $rule->[2] } += $pairs{$pair};
+       }
+       %pairs = %newp;
+}
+
+my @count = sort { $a <=> $b } values %count;
+say $count[-1] - $count[0];
+
diff --git a/2021/29.pl b/2021/29.pl
new file mode 100755 (executable)
index 0000000..d4a2441
--- /dev/null
@@ -0,0 +1,34 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use Data::Dumper;
+
+$; = ',';
+my @m;
+my ($maxx, $maxy) = (0, 0);
+while (<>) {
+       chomp;
+       push @m, [ split // ];
+       $maxx = length;
+       $maxy++;
+}
+
+my %cost = ("0,0" => 0);
+my @todo = ([0, 0]);
+
+while (my $p = shift @todo) {
+       my ($sx, $sy) = @$p;
+       for my $d ([ 0, 1], [0, -1], [1, 0], [-1, 0]) {
+               my $dx = $sx + $d->[0];
+               my $dy = $sy + $d->[1];
+               next if $dx < 0 || $dx >= $maxx || $dy < 0 || $dy >= $maxy;
+               if (!defined $cost{$dx,$dy}
+                       || $cost{$dx,$dy} > $cost{$sx,$sy} + $m[$dy][$dx]) {
+                       $cost{$dx,$dy} = $cost{$sx,$sy} + $m[$dy][$dx];
+                       push @todo, [$dx,$dy];
+               }
+       }
+}
+
+say $cost{$maxx-1,$maxy-1};
+
diff --git a/2021/30.pl b/2021/30.pl
new file mode 100755 (executable)
index 0000000..8cee293
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use Data::Dumper;
+
+$; = ',';
+my @m1;
+my ($maxx, $maxy) = (0, 0);
+while (<>) {
+       chomp;
+       push @m1, [ split(//) ];
+       $maxx = length;
+}
+$maxy = @m1;
+
+my @m;
+$maxx *= 5;
+$maxy *= 5;
+
+for my $x (0 .. $maxx-1) {
+for my $y (0 .. $maxy-1) {
+       my $add = int($x*5/$maxx)+int($y*5/$maxy);
+       my $x1 = $x % ($maxx/5);
+       my $y1 = $y % ($maxy/5);
+       $m[$y][$x] = $m1[$y1][$x1] + $add;
+       $m[$y][$x] -= 9 if $m[$y][$x] > 9;
+} }
+
+my %cost = ("0,0" => 0);
+my @todo = ([0, 0]);
+
+while (my $p = shift @todo) {
+       my ($sx, $sy) = @$p;
+       for my $d ([ 0, 1], [0, -1], [1, 0], [-1, 0]) {
+               my $dx = $sx + $d->[0];
+               my $dy = $sy + $d->[1];
+               next if $dx < 0 || $dx >= $maxx || $dy < 0 || $dy >= $maxy;
+               if (!defined $cost{$dx,$dy}
+                       || $cost{$dx,$dy} > $cost{$sx,$sy} + $m[$dy][$dx]) {
+                       $cost{$dx,$dy} = $cost{$sx,$sy} + $m[$dy][$dx];
+                       push @todo, [$dx,$dy];
+               }
+       }
+}
+
+say $cost{$maxx-1,$maxy-1};
diff --git a/2021/31.pl b/2021/31.pl
new file mode 100755 (executable)
index 0000000..9f8f753
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp(my $packet = <>);
+$packet =~ s/./sprintf("%04b", hex $&)/ge if $packet =~ /[2-9A-F]/;
+
+sub get_b (\$$) {
+       my ($ppack, $bits) = @_;
+       my $rv;
+       $$ppack =~ s/.{$bits}/$rv=eval"0b$&";''/e;
+       return $rv;
+}
+
+my $ver_sum;
+my $result;
+sub parse {
+       my $pp = shift;
+
+       my $l = length $pp;
+       my $ver = get_b($pp, 3);
+       $ver_sum += $ver;
+       my $typ = get_b($pp, 3);
+       if ($typ == 4) {
+               my $num = 0;
+               while (get_b($pp, 1)) {
+                       $num *= 16;
+                       $num += get_b($pp, 4);
+               }
+               $num *= 16;
+               $num += get_b($pp, 4);
+               $result .= "$num,";
+       } else {
+               $result .= "op($typ,";
+               my $li = get_b($pp, 1);
+               if ($li) {
+                       my $subp = get_b($pp, 11);
+                       for (1 .. $subp) {
+                               my $l1 = parse($pp);
+                               $pp =~ s/.{$l1}//;
+                       }
+               } else {
+                       my $subl = get_b($pp, 15);
+                       my $s = substr($pp, 0, $subl);
+                       $pp =~ s/.{$subl}//;
+                       while ($subl) {
+                               my $l1 = parse($s);
+                               $s =~ s/.{$l1}//;
+                               $subl -= $l1;
+                       }
+               }
+               $result .= ")";
+       }
+       return $l - length($pp);
+}
+
+parse($packet);
+say $result;
+say $ver_sum;
+
diff --git a/2021/32.pl b/2021/32.pl
new file mode 100755 (executable)
index 0000000..390c25d
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp(my $data = <>);
+# Accept also a binary string instead of hexadecimal one:
+$data =~ s/./sprintf("%04b", hex $&)/ge if $data =~ /[2-9A-F]/;
+
+sub chop_bits {
+       my ($bits) = @_;
+       my $rv;
+       $data =~ s/.{$bits}/$rv = eval "0b$&"; ''/e;
+       # say "chop_bits($bits) = $rv";
+       return $rv;
+}
+
+my $ver_sum;
+my $result;
+
+sub parse {
+       $ver_sum += chop_bits(3);
+       my $type = chop_bits(3);
+
+       if ($type == 4) {
+               my $num = 0;
+               my $more;
+               do {
+                       $more = chop_bits(1);
+                       $num *= 16;
+                       $num += chop_bits(4);
+               } while ($more);
+               $result .= "$num,";
+       } else {
+               $result .= "op$type(";
+               if (chop_bits(1)) {
+                       my $subparts = chop_bits(11);
+                       parse() for 1 .. $subparts;
+               } else {
+                       my $sublen = chop_bits(15);
+                       my $len = length $data;
+                       parse() while $len - length($data) < $sublen;
+               }
+               $result .= "),";
+       }
+}
+
+use List::Util qw(sum product min max);
+
+sub op0 { sum @_; }
+sub op1 { product @_; }
+sub op2 { min @_; }
+sub op3 { max @_; }
+sub op5 { $_[0] >  $_[1] ? 1 : 0 }
+sub op6 { $_[0] <  $_[1] ? 1 : 0 }
+sub op7 { $_[0] == $_[1] ? 1 : 0 }
+
+parse();
+
+say "versions = $ver_sum";
+say $result, ' = ', eval $result;
+
diff --git a/2021/34.pl b/2021/34.pl
new file mode 100755 (executable)
index 0000000..640916c
--- /dev/null
@@ -0,0 +1,26 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my ($xmin, $xmax) = (281, 311); my ($ymin, $ymax) = (-74, -54);
+# my ($xmin, $xmax) = (20, 30); my ($ymin, $ymax) = (-10, -5);
+
+my $count;
+for my $dx (1 .. $xmax) {
+for my $dy ($ymin..-$ymin) {
+       my ($dx0, $dy0) = ($dx, $dy);
+       my ($x, $y) = (0, 0);
+       while ($x <= $xmax && $y >= $ymin) {
+               if ($x >= $xmin && $x <= $xmax && $y >= $ymin && $y <= $ymax) {
+                       $count++;
+                       # say $dx,',', $dy;
+                       last;
+               }
+               $x += $dx0; $y += $dy0;
+               if ($dx0 > 0) { $dx0-- };
+               $dy0--;
+       }
+} }
+
+say $count;
+       
diff --git a/2021/35.pl b/2021/35.pl
new file mode 100755 (executable)
index 0000000..53e1e3e
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+chomp (my $res = <>);
+while (<>) {
+       chomp;
+       say "\nadd:   $res\nto:    $_";
+       $res = "[$res,$_]";
+       ACTION:
+       while (1) {
+               say "have:  $res";
+               # explode
+               my $depth = 0;
+               for my $i (0 .. length($res)-1) {
+                       $depth++ if substr($res, $i, 1) eq '[';
+                       $depth-- if substr($res, $i, 1) eq ']';
+                       
+                       if ($depth >= 5) {
+                               pos($res) = $i;
+                               next if $res !~ /\G\[(\d+),(\d+)\]/;
+                               say "explode at $i";
+                               pos($res) = $i;
+                               $res =~ s/\G\[(\d+),(\d+)\]/X/;
+                               say "X:     $res";
+                               my $l = $1;
+                               my $r = $2;
+                               $res =~ s/(\d+)([^\d]*X)/($1+$l).$2/e;
+                               $res =~ s/(X[^\d]*)(\d+)/"$1".($2+$r)/e;
+                               $res =~ s/X/0/;
+                               say "after: $res";
+                               next ACTION;
+                       }
+               }
+               # split
+               if ($res =~ s|\d{2,}|'['.int($&/2).','.int(($&+1)/2).']'|e) {
+                       say "split: $res";
+                       next ACTION;
+               }
+               last;
+       }
+}
+
+1 while $res =~ s/\[(\d+),(\d+)\]/3*$1+2*$2/e;
+say $res;
+
diff --git a/2021/36.pl b/2021/36.pl
new file mode 100755 (executable)
index 0000000..3047f40
--- /dev/null
@@ -0,0 +1,47 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+sub add {
+       $_ = "[$_[0],$_[1]]";
+       my $modified;
+       do {
+               $modified = undef;
+               my ($i, $depth) = (0, 0);
+               while ($i < length) {
+                       $depth-- if substr($_, $i, 1) eq ']';
+                       $depth++ if substr($_, $i, 1) eq '[';
+                       
+                       if ($depth >= 5) {
+                               pos = $i;
+                               next unless s/\G\[(\d+),(\d+)\]/X/;
+                               my ($l, $r) = ($1, $2);
+                               s/(\d+)([^\d]*X)/($1+$l).$2/e;
+                               s/(X[^\d]*)(\d+)/$1.($2+$r)/e;
+                               s/X/0/;
+                               $modified++; $depth--;
+                       }
+                       $i++;
+               }
+               $modified++ if s|\d{2,}|'['.int($&/2).','.int(($&+1)/2).']'|e;
+       } while ($modified);
+       return $_;
+}
+
+sub magnitude { $_ = shift; 1 while s/\[(\d+),(\d+)\]/3*$1+2*$2/e; $_ }
+
+use List::Util qw(reduce);
+
+chomp (my @nums = <>);
+
+say magnitude( reduce { add($a, $b) } @nums );
+
+my $max = 0;
+for my $i (0 .. $#nums) {
+for my $j (0 .. $#nums) {
+       next if $i == $j;
+       my $r = magnitude( add($nums[$i], $nums[$j]) );
+       $max = $r if ($max < $r);
+} }
+
+say $max;
diff --git a/2021/37.pl b/2021/37.pl
new file mode 100755 (executable)
index 0000000..8770cb7
--- /dev/null
@@ -0,0 +1,118 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+$; = ',';
+my %scans;
+my $scanner;
+my $first_scanner;
+while (<>) {
+       chomp;
+       if (/--- (scanner \d+) ---/) {
+               $scanner = $1;
+               $first_scanner //= $1;
+       } elsif (/^$/) {
+               next;
+       } else {
+               $scans{$scanner}->{$_} = 1;
+       }
+}
+
+my @perms = (
+       [ 0, 1, 2],
+       [ 0, 2, 1],
+       [ 1, 0, 2],
+       [ 1, 2, 0],
+       [ 2, 0, 1],
+       [ 2, 1, 0],
+);
+
+my @rotations;
+my %r_seen;
+for (0 .. 7) {
+       for my $p (@perms) {
+               my @r = @$p;
+               $r[3] = $_ & 0x01 ? -1 : 1;
+               $r[4] = $_ & 0x02 ? -1 : 1;
+               $r[5] = $_ & 0x04 ? -1 : 1;
+               push @rotations, \@r;
+       }
+}
+               
+use Data::Dumper;
+say "rotations: ", scalar @rotations;
+
+sub transform {
+       my ($coords, $trans) = @_;
+       my @res;
+       for (0 .. $#$coords) {
+               $res[$_] = $coords->[$trans->[$_]];
+               $res[$_] *= -1 if $trans->[$_+@$coords] < 0;
+       }
+       return @res;
+}
+
+sub is_aligned {
+       my ($s1, $s2) = @_;
+       my $coords1 = $scans{$s1};
+       my $coords2 = $scans{$s2};
+
+       say "comparing $s1 and $s2";
+       for my $from_t (keys %$coords1) {
+               my @from = split /,/, $from_t;
+               for my $rot (@rotations) {
+                       my @from_rotated = transform(\@from, $rot);
+                       # say "rotated ", join(',', @from), ' to ', join(',', @from_rotated);
+                       for my $to_t (keys %$coords2) {
+                               my @off = split /,/, $to_t;
+                               $off[$_] -= $from_rotated[$_] for 0..$#off;
+                               # say "trying offset ", join(',', @off);
+                               my $count = 0;
+                               for my $c1_t (keys %$coords1) {
+                                       my @c1 = split /,/, $c1_t;
+                                       @c1 = transform(\@c1, $rot);
+                                       $c1[$_] += $off[$_] for 0..$#off;
+                                       # say "searching for ", join(',',@c1);
+                                       $count++ if $coords2->{join(',', @c1)};
+                               }
+                               if ($count >= 12) {
+                                       say "found $count matches ", join(',', @$rot);
+                                       return (\@off, $rot);
+                               }
+                       }
+               }
+       }
+}
+
+my %aligned_scanners = ($first_scanner => [ [ 0, 0, 0], [ 0, 1, 2, 1, 1, 1 ] ]);
+my %beacons = ( %{ $scans{$first_scanner} } );
+my %tested;
+while (scalar keys %aligned_scanners < scalar keys %scans) {
+       say scalar keys %beacons, ' beacons found:';
+       for my $s1 (grep { $aligned_scanners{$_} } keys %scans) {
+               for my $s2 (grep { !$aligned_scanners{$_} } keys %scans) {
+                       next if $tested{$s1,$s2} || $tested{$s2,$s1};
+                       my ($off, $rot) = is_aligned($s2, $s1);
+                       $tested{$s1,$s2} = $tested{$s2,$s1} = 1;
+                       next if !defined $rot;
+                       my %nscans;
+                       for my $c2_t (keys %{ $scans{$s2}}) {
+                               my @c2 = split /,/, $c2_t;
+                               @c2 = transform(\@c2, $rot);
+                               $c2[$_] += $off->[$_] for 0 .. $#c2;
+                               my $key = join(',', @c2);
+                               $beacons{$key}++;
+                               $nscans{$key}++;
+                       }
+                       $scans{$s2} = \%nscans;
+                       $aligned_scanners{$s2} = 1;
+                       say "$s1 and $s2 aligned: ", join(',', @$off, @$rot), " beacons: ", scalar keys %beacons;
+               }
+       }
+}
+
+say '=========';
+for my $b (sort keys %beacons) {
+       say $b;
+}
+say "total beacons: ", scalar keys %beacons;
diff --git a/2021/38.pl b/2021/38.pl
new file mode 100755 (executable)
index 0000000..b604ecc
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+$; = ',';
+
+sub transform {
+       my ($coords, $trans) = @_;
+       my @res;
+       for (0 .. $#$coords) {
+               $res[$_] = $coords->[$trans->[$_]];
+               $res[$_] *= -1 if $trans->[$_+@$coords] < 0;
+       }
+       return @res;
+}
+
+my %aligned_scanners = ('scanner 0' => [ 0, 0, 0 ]);
+
+# parsing the debugging output of the first part ...
+while (<>) {
+       my ($s1, $s2, $rest) = /(.*) and (.*) aligned: (.*) beacons:/;
+       next if !$rest;
+
+       my @r = split /,/, $rest;
+       my @off = @r[0..2];
+       my @rot = @r[3..8];
+
+       # @off = transform(\@off, \@rot);
+       say "$s1 to $s2";
+       # $off[$_] += $aligned_scanners{$s1}->[$_] for 0..2;
+       say "$s2 at ", join(',', @off);
+       $aligned_scanners{$s2} = [ @off ];
+}
+
+my $max_dist = 0;
+for my $s1 (keys %aligned_scanners) {
+for my $s2 (keys %aligned_scanners) {
+       my $dist;
+       $dist += abs($aligned_scanners{$s1}->[$_] - $aligned_scanners{$s2}->[$_]) for 0 .. 2;
+       $max_dist = $dist if $dist > $max_dist;
+       say "$s1 to $s2 = $dist";
+} }
+
+say $max_dist;
+
diff --git a/2021/39.pl b/2021/39.pl
new file mode 100755 (executable)
index 0000000..e4d6c01
--- /dev/null
@@ -0,0 +1,76 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @m = split //, <>;
+scalar <>;
+
+$; = ',';
+my @image = map { chomp; [ split // ] } <>;
+
+my $odd = 1;
+sub enhance {
+       my $img = shift;
+       my $ymax = @$img;
+       my $xmax = @{ $img->[0] };
+
+       say "odd=$odd, m0=$m[0]";
+
+       my @rv;
+       for my $y (0 .. $ymax+3) {
+               for my $x (0 .. $xmax+3) {
+                       my $idx = 0;
+                       for my $dy (-2 .. 0) {
+                               my $y2 = $y+$dy;
+                               for my $dx (-2 .. 0) {
+                                       my $x2 = $x+$dx;
+                                       # say "$x,$y + $dx,$dy = $x2, $y2";
+                                       $idx <<= 1;
+                                       if ($y2 >= 0 && $y2 < $ymax
+                                               && $x2 >= 0 && $x2 < $xmax) {
+                                                       $idx++ if $img->[$y2][$x2] eq '#';
+                                       } else {
+                                               $idx++ if !$odd && ($m[0] eq '#');
+                                       }
+                               }
+                       }
+                       # say "$x,$y => $idx => $m[$idx]";
+                       $rv[$y][$x] = $m[$idx];
+               }
+       }
+
+       $odd = !$odd;
+
+       return @rv;
+}
+
+sub imgdump {
+       my $img = shift;
+       my $ymax = @$img;
+       my $xmax = @{ $img->[0] };
+
+       my $sum;
+
+       say "$xmax x $ymax";
+       for my $y (0 .. $ymax-1) {
+               for my $x (0 .. $xmax-1) {
+                       print $img->[$y][$x];
+                       $sum++ if $img->[$y][$x] eq '#';
+               }
+               print "\n";
+       }
+       say "sum=$sum";
+}
+
+for (1 .. 50) {
+       imgdump(\@image);
+       @image = enhance(\@image);
+}
+imgdump(\@image);
+my $sum = 0;
+for my $row (@image) {
+       for my $pixel (@$row) {
+               $sum++ if $pixel eq '#';
+       }
+}
+say "pixels = $sum"; 
diff --git a/2021/41.pl b/2021/41.pl
new file mode 100755 (executable)
index 0000000..ac2e4e0
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my (@p) = @ARGV;
+my @s = (0, 0);
+my $d = 1;
+my $dc = 0;
+
+sub roll() {
+       $dc++;
+       my $rv = $d++;
+       $d = 1 if $d > 100;
+       return $rv;
+}
+
+while (1) {
+       for (0 .. 1) {
+               $p[$_] += roll()+roll()+roll();
+               $p[$_] -= 10 while $p[$_] > 10;
+               $s[$_] += $p[$_];
+               # say "$dc: $d, $_, $p[$_]";
+               if ($s[$_] >= 1000) {   
+                       say $s[1-$_]*$dc;
+                       exit 0;
+               }
+       }
+}
diff --git a/2021/42.pl b/2021/42.pl
new file mode 100755 (executable)
index 0000000..c8af64b
--- /dev/null
@@ -0,0 +1,54 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use bigint;
+
+my %state_count = (
+       3 => 1,
+       4 => 3,
+       5 => 6,
+       6 => 7,
+       7 => 6,
+       8 => 3,
+       9 => 1,
+);
+       
+use Array::Heap;
+my @queue = [ 0, 0, $ARGV[0], $ARGV[1], 0, 0 ];
+
+my %states = ( join(',', @{ $queue[0] }) => 1 );
+
+my @wins = (0, 0);
+
+while (my $q = pop_heap @queue) {
+       my $count = $states{join(',', @$q)};
+       for my $dice (3 .. 9) {
+               my $player = $q->[1];
+               my $pos    = $q->[2+$player];
+               my $score  = $q->[4+$player];
+               $pos += $dice;
+               $pos -= 10 while $pos > 10;
+               $score += $pos;
+               my $ncount = $count * $state_count{$dice};
+               if ($score >= 21) {
+                       $wins[$player] += $ncount;
+                       next;
+               }
+
+               my @nq = @$q;
+               $nq[0] += $pos;
+               $nq[1] = 1-$player;
+               $nq[2+$player] = $pos;
+               $nq[4+$player] = $score;
+               my $key = join(',', @nq);
+               if ($states{$key}) {
+                       $states{$key} += $ncount;
+               } else {
+                       $states{$key} = $ncount;
+                       push_heap @queue, \@nq;
+               }
+       }
+}
+
+say $wins[0], ' vs ', $wins[1], " winner is ",
+       $wins[0] > $wins[1] ? 'first' : 'second';
diff --git a/2021/43.pl b/2021/43.pl
new file mode 100755 (executable)
index 0000000..c7c2cc1
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+$; = ',';
+my %cubes;
+while (<>) {
+       my $state = /^on / ? 1 : 0;
+       my ($xmin, $xmax, $ymin, $ymax, $zmin, $zmax) = /-?\d+/g;
+       ($xmin, $xmax) = ($xmax, $xmin) if $xmax < $xmin;
+       ($ymin, $ymax) = ($ymax, $ymin) if $ymax < $ymin;
+       ($zmin, $zmax) = ($zmax, $zmin) if $zmax < $zmin;
+       say "cuboid ", join(',', $state, $xmin, $xmax, $ymin, $ymax, $zmin, $zmax);
+       next if ($xmax < -50 || $ymax < -50 || $zmax < -50);
+       next if ($xmin > 50 || $ymin > 50 || $zmin > 50);
+       $xmin = -50 if ($xmin < -50);
+       $ymin = -50 if ($ymin < -50);
+       $zmin = -50 if ($zmin < -50);
+       $xmax = 50 if $xmax > 50;
+       $ymax = 50 if $zmax > 50;
+       $zmax = 50 if $zmax > 50;
+       for my $x ($xmin .. $xmax) {
+       for my $y ($ymin .. $ymax) {
+       for my $z ($zmin .. $zmax) {
+               $cubes{$x,$y,$z} = $state;
+               say "$x,$y,$z => $state";
+       } } }
+}
+
+my $count;
+for my $x (-50 .. 50) {
+for my $y (-50 .. 50) {
+for my $z (-50 .. 50) {
+       $count++ if $cubes{$x,$y,$z};
+} } }
+
+say $count;
+
diff --git a/2021/44.pl b/2021/44.pl
new file mode 100755 (executable)
index 0000000..c98c77f
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+$; = ',';
+my @cuboids;
+while (<>) {
+       my $state = /^on / ? 1 : 0;
+       my ($xmin, $xmax, $ymin, $ymax, $zmin, $zmax) = /-?\d+/g;
+       ($xmin, $xmax) = ($xmax, $xmin) if $xmax < $xmin;
+       ($ymin, $ymax) = ($ymax, $ymin) if $ymax < $ymin;
+       ($zmin, $zmax) = ($zmax, $zmin) if $zmax < $zmin;
+       push @cuboids, [$xmin, $xmax, $ymin, $ymax, $zmin, $zmax, $state];
+}
+
+sub overlaps_int {
+       my ($min1, $max1, $min2, $max2) = @_;
+       return ($min1 >= $min2 && $min1 <= $max2)
+               || ($max1 >= $min2 && $max1 <= $max2)
+               || ($min1 <= $min2 && $max1 >= $max2)
+               || ($min1 >= $min2 && $max1 <= $max2);
+}
+
+sub overlaps_axis {
+       my ($c1, $c2, $axis) = @_;
+       $axis *=2;
+       return overlaps_int($c1->[$axis], $c1->[$axis+1], $c2->[$axis], $c2->[$axis+1]);
+}
+
+my @on_cuboids;
+for my $c1 (@cuboids) {
+       my @on_new;
+       CUBOID:
+       while (@on_cuboids) {
+               my $c2 = shift @on_cuboids;
+               for (0 .. 2) { # does $c1 overlap $c2?
+                       if (!overlaps_axis($c1, $c2, $_)) {
+                               push @on_new, $c2;
+                               next CUBOID;
+                       }
+               }
+               for (0 .. 2) {
+                       my ($min, $max) = (2*$_, 2*$_+1);
+                       if ($c1->[$min] > $c2->[$min] && $c1->[$min] <= $c2->[$max]) {
+                               my @c = @$c2;
+                               $c[$max] = $c1->[$min]-1;
+                               push @on_cuboids, [ @c ];
+                               @c = @$c2;
+                               $c[$min] = $c1->[$min];
+                               push @on_cuboids, [ @c ];
+                               next CUBOID;
+                       }
+                       if ($c1->[$max] >= $c2->[$min] && $c1->[$max] < $c2->[$max]) {
+                               my @c = @$c2;
+                               $c[$max] = $c1->[$max];
+                               push @on_cuboids, [ @c ];
+                               @c = @$c2;
+                               $c[$min] = $c1->[$max]+1;
+                               push @on_cuboids, [ @c ];
+                               next CUBOID;
+                       }
+                       if ($c1->[$min] > $c2->[$min]
+                               || $c1->[$max] < $c2->[$max]) {
+                               push @on_new, $c2;
+                               next CUBOID;
+                       }
+               }
+       }
+       push @on_new, $c1 if $c1->[6];
+       @on_cuboids = @on_new;
+}
+
+my $count;
+for my $c1 (@on_cuboids) {
+       $count += ($c1->[1] - $c1->[0] + 1)
+               * ($c1->[3] - $c1->[2] + 1)
+               * ($c1->[5] - $c1->[4] + 1);
+}
+
+say $count;
diff --git a/2021/45.pl b/2021/45.pl
new file mode 100755 (executable)
index 0000000..b5ff0b9
--- /dev/null
@@ -0,0 +1,208 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+#  ab c d e fg
+#    h j l n
+#    i k m o
+
+my %g = (
+       'h' => {
+               'a' => [ 3, 'b' ],
+               'b' => [ 2, '' ],
+               'c' => [ 2, '' ],
+               'd' => [ 4, 'c' ],
+               'e' => [ 6, 'cd' ],
+               'f' => [ 8, 'cde' ],
+               'g' => [ 9, 'cdef' ],
+       },
+       'i' => {
+               'a' => [ 4, 'bh' ],
+               'b' => [ 3, 'h' ],
+               'c' => [ 3, 'h' ],
+               'd' => [ 5, 'ch' ],
+               'e' => [ 7, 'cdh' ],
+               'f' => [ 9, 'cdeh' ],
+               'g' => [ 10, 'cdefh' ],
+       },
+       'j' => {
+               'a' => [ 5, 'bc' ],
+               'b' => [ 4, 'c' ],
+               'c' => [ 2, '' ],
+               'd' => [ 2, '' ],
+               'e' => [ 4, 'd' ],
+               'f' => [ 6, 'de' ],
+               'g' => [ 7, 'def' ],
+       },
+       'k' => {
+               'a' => [ 6, 'bcj' ],
+               'b' => [ 5, 'cj' ],
+               'c' => [ 3, 'j' ],
+               'd' => [ 3, 'j' ],
+               'e' => [ 5, 'dj' ],
+               'f' => [ 7, 'dej' ],
+               'g' => [ 8, 'defj' ],
+       },
+       'l' => {
+               'a' => [ 7, 'bcd' ],
+               'b' => [ 6, 'cd' ],
+               'c' => [ 4, 'd' ],
+               'd' => [ 2, '' ],
+               'e' => [ 2, '' ],
+               'f' => [ 4, 'e' ],
+               'g' => [ 6, 'ef' ],
+       },
+       'm' => {
+               'a' => [ 8, 'bcdl' ],
+               'b' => [ 7, 'cdl' ],
+               'c' => [ 5, 'dl' ],
+               'd' => [ 3, 'l' ],
+               'e' => [ 3, 'l' ],
+               'f' => [ 5, 'el' ],
+               'g' => [ 7, 'efl' ],
+       },
+       'n' => {
+               'a' => [ 9, 'bcde' ],
+               'b' => [ 8, 'cde' ],
+               'c' => [ 6, 'de' ],
+               'd' => [ 4, 'e' ],
+               'e' => [ 2, '' ],
+               'f' => [ 2, '' ],
+               'g' => [ 3, 'f' ],
+       },
+       'o' => {
+               'a' => [ 10, 'bcden' ],
+               'b' => [ 9, 'cden' ],
+               'c' => [ 7, 'den' ],
+               'd' => [ 5, 'en' ],
+               'e' => [ 3, 'n' ],
+               'f' => [ 3, 'n' ],
+               'g' => [ 4, 'fn' ],
+       },
+);
+
+for my $node (keys %g) {
+       for my $n2 (keys %{ $g{$node} }) {
+               $g{$n2}->{$node} = $g{$node}->{$n2};
+       }
+}
+
+my %home = (
+       h => 'A',
+       i => 'A',
+       j => 'B',
+       k => 'B',
+       l => 'C',
+       m => 'C',
+       n => 'D',
+       o => 'D',
+);
+
+my %otherhome = (
+       h => 'i',
+       j => 'k',
+       l => 'm',
+       n => 'o',
+);
+%otherhome = (%otherhome, reverse %otherhome);
+
+my %cost_of = (
+       A => 1,
+       B => 10,
+       C => 100,
+       D => 1000,
+);
+
+my @type = qw( A A B B C C D D );
+
+sub can_move {
+       my ($pos, $who, $dst) = @_;
+       my $i = 0;
+       my %rpos = map { $_ => $i++ } @$pos;
+       my $src = $pos->[$who];
+       my $mytype = $type[$who];
+       return 0 if defined $rpos{$dst}; # occupied
+       return 0 if !$home{$src} && !$home{$dst}; # cant move in a hallway
+       if ($home{$dst}) {
+               return 0 if $home{$dst} ne $mytype; # not own home
+               my $other = $otherhome{$dst};
+               return 0 if defined $rpos{$other} && $type[$rpos{$other}] ne $mytype;
+               return 0 if $other gt $dst && !defined $rpos{$other};
+       }
+
+       # path exists?
+       my $c = $g{$src}->{$dst};
+       return 0 if !$c;
+
+       # path occupied?
+       for my $in (split //, $c->[1]) {
+               return 0 if $rpos{$in};
+       }
+
+       # say "can_move $who$type[$who]=>$dst ", join(',', keys %rpos);
+       return $c->[0];
+}
+
+my %pos_seen;
+my $min_cost = 100_000;
+sub walk {
+       my ($pos, $moved, $cost, $moves) = @_;
+       my $key = join(' ', @$pos, $cost);
+       return if $pos_seen{$key}++;
+       my $athome = 0;
+       # say "walk ", join(' ', @$pos), " cost $cost";
+       for my $i (0 .. $#$pos) {
+               my @dsts; 
+               if (!$moved->{$i}) {
+                       @dsts = 'a' .. 'g';
+               } elsif ($moved->{$i} == 1) {
+                       @dsts = grep { $home{$_} eq $type[$i] } keys %home;
+               } else {
+                       $athome++;
+               }
+               for my $dst (@dsts) {
+                       my $acost = can_move($pos, $i, $dst);
+                       next if !$acost;
+                       $acost *= $cost_of{$type[$i]};
+                       next if $cost + $acost >= $min_cost;
+
+                       my @npos = @$pos;
+                       $npos[$i] = $dst;
+
+                       my %nmoved = %$moved;
+                       $nmoved{$i}++;
+
+                       my @nmoves = @$moves;
+                       push @nmoves, "$i$type[$i]=>$dst $acost";
+                       
+                       walk(\@npos, \%nmoved, $cost + $acost, \@nmoves);
+               }
+       }
+       if ($athome == 8) {
+               if (!$min_cost || $cost < $min_cost) {
+                       $min_cost = $cost;
+                       say "athome = $athome cost $cost $min_cost: ",
+                               join(', ', @$moves);
+               }
+       }
+}
+
+
+walk( [qw( h k i l j o m n )], {}, 0, [ ]);
+# walk( [qw( i o h l j m k n )], { 0 => 2, 5 => 2 }, 0, [ ]);
+
+#############
+#...........#
+###B#C#B#D###
+  #A#D#C#A#
+  #########
+
+
+
+                       
+                       
+               
+                       
+               
+
+
diff --git a/2021/46.pl b/2021/46.pl
new file mode 100755 (executable)
index 0000000..4cacd82
--- /dev/null
@@ -0,0 +1,264 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+#  ab c d e fg
+#    h l p t
+#    i m q u
+#    j n r v
+#    k o s w
+
+my %g = (
+       'h' => {
+               'a' => [ 3, 'b' ],
+               'b' => [ 2, '' ],
+               'c' => [ 2, '' ],
+               'd' => [ 4, 'c' ],
+               'e' => [ 6, 'cd' ],
+               'f' => [ 8, 'cde' ],
+               'g' => [ 9, 'cdef' ],
+       },
+       'l' => {
+               'a' => [ 5, 'bc' ],
+               'b' => [ 4, 'c' ],
+               'c' => [ 2, '' ],
+               'd' => [ 2, '' ],
+               'e' => [ 4, 'd' ],
+               'f' => [ 6, 'de' ],
+               'g' => [ 7, 'def' ],
+       },
+       'p' => {
+               'a' => [ 7, 'bcd' ],
+               'b' => [ 6, 'cd' ],
+               'c' => [ 4, 'd' ],
+               'd' => [ 2, '' ],
+               'e' => [ 2, '' ],
+               'f' => [ 4, 'e' ],
+               'g' => [ 6, 'ef' ],
+       },
+       't' => {
+               'a' => [ 9, 'bcde' ],
+               'b' => [ 8, 'cde' ],
+               'c' => [ 6, 'de' ],
+               'd' => [ 4, 'e' ],
+               'e' => [ 2, '' ],
+               'f' => [ 2, '' ],
+               'g' => [ 3, 'f' ],
+       },
+);
+
+for my $n1 (keys %g) {
+       my $prevnodes = $n1;
+       for my $i (1..3) {
+               my $n2 = chr(ord($n1)+$i);
+               for my $n3 (keys %{ $g{$n1} }) {
+                       my $c = $g{$n1}->{$n3};
+                       $g{$n2}->{$n3} = [ $c->[0] + $i, $c->[1].$prevnodes ];
+               }
+               $prevnodes .= $n2;
+       }
+}
+
+# symmetric
+for my $node (keys %g) {
+       for my $n2 (keys %{ $g{$node} }) {
+               $g{$n2}->{$node} = $g{$node}->{$n2};
+       }
+}
+
+my %home = (
+       h => 'A',
+       l => 'B',
+       p => 'C',
+       t => 'D',
+);
+
+my %lowerhome;
+for my $n1 (keys %home) {
+       for (1..3) {
+               my $n2 = chr(ord($n1)+$_);
+               $home{$n2} = $home{$n1};
+       }
+}
+
+my %home_of = (
+       A => [ 'h' .. 'k' ],
+       B => [ 'l' .. 'o' ],
+       C => [ 'p' .. 's' ],
+       D => [ 't' .. 'w' ],
+);
+
+my %cost_of = (
+       A => 1,
+       B => 10,
+       C => 100,
+       D => 1000,
+);
+
+my @type = qw( A A A A B B B B C C C C D D D D );
+
+sub can_move {
+       my ($pos, $who, $dst) = @_;
+       my $i = 0;
+       my %rpos = map { $_ => $i++ } @$pos;
+       my $src = $pos->[$who];
+       my $mytype = $type[$who];
+       return 0 if defined $rpos{$dst}; # occupied
+       return 0 if !$home{$src} && !$home{$dst}; # cant move in a hallway
+
+       # path exists?
+       my $c = $g{$src}->{$dst};
+       return 0 if !$c;
+
+       # path occupied?
+       for my $in (split //, $c->[1]) {
+               return 0 if defined $rpos{$in};
+       }
+
+       # say "can_move $who$type[$who]=>$dst ", join(',', keys %rpos);
+       return $c->[0];
+}
+
+sub gen_pos {
+       my ($pos) = @_;
+       my $text = <<'EOF';
+#############
+#ab.c.d.e.fg#
+###h#l#p#t###
+  #i#m#q#u#
+  #j#n#r#v#
+  #k#o#s#w#
+  #########
+EOF
+       for my $i (0 .. $#$pos) {
+               $text =~ s/$pos->[$i]/$type[$i]/gxms;
+       }
+       $text =~ s/[a-z]/./gxms;
+       return join('', @$pos) . "\n" .$text;
+}
+
+sub print_pos { say gen_pos(shift) }
+
+my %pos_seen;
+my $min_cost = 100_000;
+sub walk {
+       my ($pos, $moved, $can_move, $free_home, $cost, $moves) = @_;
+
+       my $key = join(' ', @$pos, $cost);
+       return if $pos_seen{$key}++;
+
+       my $finished = grep { $moved->{$_} && $moved->{$_} == 2 } 0 .. $#$pos;
+       my $stepped =  grep { $moved->{$_} && $moved->{$_} == 1 } 0 .. $#$pos;
+       # say "stepped $stepped, finished: $finished";
+       if ($finished == @$pos) {
+               if (!$min_cost || $cost < $min_cost) {
+                       $min_cost = $cost;
+                       say "cost $cost $min_cost: ", @$moves;
+               }
+       }
+
+       my $x = 0;
+       my %rpos = map { $_ => $x++ } @$pos;
+
+if (0) {
+       say "walk ", join(' ', @$pos), " cost $cost, can_move = ",
+               join(',', keys %$can_move),
+               " free_home = ", join(',', keys %$free_home);
+       print_pos($pos);
+}
+
+       for my $i (grep { !$moved->{$_} } keys %$can_move) {
+               my @dsts;
+
+               my %nmoved = %$moved;
+               my %ncan_move = %$can_move;
+               my %nfree_home = %$free_home;
+
+               my $mypos = $pos->[$i];
+               my $mytype = $type[$i];
+
+               $nmoved{$i}++;
+
+               delete $ncan_move{$i};
+               my $under = chr(ord($mypos)+1);
+               if (defined $home{$under} && $home{$mypos} eq $home{$under}
+                       && !$moved->{$rpos{$under}}) { 
+                       $ncan_move{$rpos{$under}} = 1;
+               } else {
+                       $nfree_home{$home{$mypos}} = $mypos;
+               }
+               for my $dst (grep { !defined $rpos{$_} } 'a' .. 'g') {
+                       my $acost = can_move($pos, $i, $dst);
+                       next if !$acost;
+                       $acost *= $cost_of{$type[$i]};
+                       next if $cost + $acost >= $min_cost;
+
+                       my @npos = @$pos;
+                       $npos[$i] = $dst;
+
+                       my @nmoves = @$moves;
+                       push @nmoves, "$i$type[$i]$pos->[$i]=>$dst $acost\n" . gen_pos($pos) . "\n";
+                       
+                       # print_pos($pos);
+                       # say $nmoves[-1];
+                       walk(\@npos, \%nmoved, \%ncan_move, \%nfree_home, $cost + $acost, \@nmoves);
+               }
+       }
+
+       for my $i (grep { $moved->{$_} && $moved->{$_} == 1 } keys %$moved) {
+               my $mypos = $pos->[$i];
+               my $mytype = $type[$i];
+               next if !$free_home->{$mytype};
+               my $dst = $free_home->{$mytype};
+
+               my $acost = can_move($pos, $i, $dst);
+               next if !$acost;
+               $acost *= $cost_of{$type[$i]};
+               next if $cost + $acost >= $min_cost;
+
+               my %nmoved = %$moved;
+               my %ncan_move = %$can_move;
+               my %nfree_home = %$free_home;
+
+               $nmoved{$i}++;
+
+               delete $nfree_home{$mytype};
+               my $above = chr(ord($dst)-1);
+               if ($home{$above} && $home{$above} eq $mytype) {
+                       $nfree_home{$mytype} = $above;
+               }
+
+               delete $ncan_move{$i};
+               
+               my @npos = @$pos;
+               $npos[$i] = $dst;
+
+               my @nmoves = @$moves;
+               push @nmoves, "$i$type[$i]$pos->[$i]=>$dst $acost\n" . gen_pos($pos) . "\n";
+               # say "xxx ", $nmoves[-1];
+               # print_pos($pos);
+               walk(\@npos, \%nmoved, \%ncan_move, \%nfree_home, $cost + $acost, \@nmoves);
+       }
+
+       # say "return";
+}
+
+my $prod = 1;
+#          A A A A B B B B C C C C D D D D
+walk( [qw( h o r u k n p q l m v w i j s t )],
+       {},
+       { map { $_ => 1 } qw(0 8 6 15) },
+       {},
+       0, [ ]) if $prod;
+walk( [qw( k r u w h n p q l m s v i j o t )],
+       { 0 => 2, 10 => 2 },
+       { map { $_ => 1 } qw(4 8 6 15) },
+       { },
+       0, [ ]) if !$prod;
+
+say $min_cost;
+#############
+#...........#
+###B#C#B#D###
+  #A#D#C#A#
+  #########
diff --git a/2021/47.pl b/2021/47.pl
new file mode 100755 (executable)
index 0000000..84034ae
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @ins = map { chomp; [ split /\s+/ ] } <STDIN>;
+
+my %regs = (
+       x => 0,
+       y => 0,
+       z => 0,
+       w => 0,
+);
+
+# my @inp = split //, 13579246899999;
+# my @inp = (-10, 3);
+
+my %cache;
+
+sub calculate {
+       my ($ip, %regs) = @_;
+
+       my $key = join(',', $ip, $regs{w}, $regs{x}, $regs{y}, $regs{z});
+       return if $cache{$key}++;
+
+       say "calculate $ip $regs{q}"
+               if length($regs{q}) < 5;
+       while ($ip < @ins) {
+               my ($ins, $r1, $r2) = @{ $ins[$ip] };
+               my $v2 = (defined $r2 && $r2 =~ /[w-z]/) ? $regs{$r2} : $r2;
+               if ($ins eq 'inp') {
+                       if (!length($regs{q})) {
+                               $regs{q} = $regs{$r1} = shift @ARGV;
+                               say "calculate for $regs{q}";
+                       } else {
+                               for my $val (reverse '1' .. '9') {
+                                       $regs{$r1} = $val;
+                                       calculate($ip+1, %regs, q => $regs{q} . $val);
+                               }
+                       }
+               } elsif ($ins eq 'add') {
+                       $regs{$r1} += $v2;
+               } elsif ($ins eq 'mul') {
+                       $regs{$r1} *= $v2;
+               } elsif ($ins eq 'div') {
+                       $regs{$r1} /= $v2;
+                       $regs{$r1} = $regs{$r1} > 0 ? int($regs{$r1}) : -int(-$regs{$r1});
+               } elsif ($ins eq 'mod') {
+                       $regs{$r1} %= $v2;
+               } elsif ($ins eq 'eql') {
+                       $regs{$r1} = $regs{$r1} == $v2 ? 1 : 0;
+               }
+
+               # say join(' ', $ip, @{ $ins[$ip] }), "\n\tw=$regs{w} x=$regs{x} y=$regs{y} z=$regs{z}";
+               $ip++;
+       }
+       if ($regs{z} == 0) {
+               say "accepted $regs{q}";
+sleep 100_000;
+               exit 0;
+       }
+}
+
+calculate (0, %regs);
+
diff --git a/2021/48.pl b/2021/48.pl
new file mode 100755 (executable)
index 0000000..6aa9060
--- /dev/null
@@ -0,0 +1,66 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @ins = map { chomp; [ split /\s+/ ] } <STDIN>;
+
+my %regs = (
+       x => 0,
+       y => 0,
+       z => 0,
+       w => 0,
+       q => '',
+);
+
+# my @inp = split //, 13579246899999;
+# my @inp = (-10, 3);
+
+my %cache;
+
+sub calculate {
+       my ($ip, %regs) = @_;
+
+       my $key = join(',', $ip, $regs{w}, $regs{x}, $regs{y}, $regs{z});
+       return if $cache{$key}++;
+
+       say "calculate $ip $regs{q}"
+               if length($regs{q}) < 5;
+       while ($ip < @ins) {
+               my ($ins, $r1, $r2) = @{ $ins[$ip] };
+               my $v2 = (defined $r2 && $r2 =~ /[w-z]/) ? $regs{$r2} : $r2;
+               if ($ins eq 'inp') {
+                       my $v = shift @ARGV;
+                       if (defined $v) {
+                               $regs{q} .= $regs{$r1} = $v;
+                               say "calculate for $regs{q}";
+                       } else {
+                               for my $val ('1' .. '9') {
+                                       $regs{$r1} = $val;
+                                       calculate($ip+1, %regs, q => $regs{q} . $val);
+                               }
+                       }
+               } elsif ($ins eq 'add') {
+                       $regs{$r1} += $v2;
+               } elsif ($ins eq 'mul') {
+                       $regs{$r1} *= $v2;
+               } elsif ($ins eq 'div') {
+                       $regs{$r1} /= $v2;
+                       $regs{$r1} = $regs{$r1} > 0 ? int($regs{$r1}) : -int(-$regs{$r1});
+               } elsif ($ins eq 'mod') {
+                       $regs{$r1} %= $v2;
+               } elsif ($ins eq 'eql') {
+                       $regs{$r1} = $regs{$r1} == $v2 ? 1 : 0;
+               }
+
+               # say join(' ', $ip, @{ $ins[$ip] }), "\n\tw=$regs{w} x=$regs{x} y=$regs{y} z=$regs{z}";
+               $ip++;
+       }
+       if ($regs{z} == 0) {
+               say "accepted $regs{q}";
+sleep 100_000;
+               exit 0;
+       }
+}
+
+calculate (0, %regs);
+
diff --git a/2021/49.pl b/2021/49.pl
new file mode 100755 (executable)
index 0000000..831140f
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+
+my @m = map { chomp; [ split // ] } <>;
+
+my $xmax = @{ $m[0] };
+my $ymax = @m;
+
+sub print_map {
+       my $m = shift;
+       for my $row (@m) {
+               say join('', @$row);
+       }
+       say "";
+}
+
+my $step;
+my $moved;
+do {
+       $moved = 0;
+       my @m1;
+       for my $y (0 .. $ymax-1) {
+               for my $x (0 .. $xmax-1) {
+                       if ($m[$y][$x] eq '>') {
+                               my $nx = $x+1;
+                               $nx = 0 if $nx >= $xmax;
+                               if ($m[$y][$nx] eq '.') {
+                                       $m1[$y][$nx] = '>';
+                                       $m1[$y][$x] = '.';
+                                       $moved++;
+                               } else {
+                                       $m1[$y][$x] = $m[$y][$x];
+                               }
+                       } else {
+                               if (!defined $m1[$y][$x]) {
+                                       $m1[$y][$x] = $m[$y][$x];
+                               }
+                       }
+               }
+       }
+       @m = @m1;
+       @m1 = ();
+
+       for my $y (0 .. $ymax-1) {
+               for my $x (0 .. $xmax-1) {
+                       if ($m[$y][$x] eq 'v') {
+                               my $ny = $y+1;
+                               $ny = 0 if $ny >= $ymax;
+                               if ($m[$ny][$x] eq '.') {
+                                       $m1[$ny][$x] = 'v';
+                                       $m1[$y][$x] = '.';
+                                       $moved++;
+                               } else {
+                                       $m1[$y][$x] = $m[$y][$x];
+                               }
+                       } else {
+                               if (!defined $m1[$y][$x]) {
+                                       $m1[$y][$x] = $m[$y][$x];
+                               }
+                       }
+               }
+       }
+       @m = @m1;
+       $step++;
+       print_map(\@m);
+} while ($moved);
+
+say "$step steps";
+
diff --git a/2021/get.sh b/2021/get.sh
new file mode 100755 (executable)
index 0000000..f888a90
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+DAY=`date +%e|sed 's/ //g'`
+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/2021/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
diff --git a/2021/leaderboard b/2021/leaderboard
new file mode 100755 (executable)
index 0000000..42874cd
--- /dev/null
@@ -0,0 +1,67 @@
+#!/usr/bin/perl -w
+
+use v5.16;
+use Mojo::UserAgent -signatures;
+use Mojo::JSON qw(from_json);
+use Mojo::File qw(curfile);
+use Mojo::Util qw(getopt dumper);
+use POSIX;
+
+my $board_id = 652041;
+my $my_name = 'Yenya';
+my $day = (localtime(time))[3];
+my $mode = 'r';
+my $force;
+getopt
+       'n|name=s'      => \$my_name,
+       'd|day=i'       => \$day,
+       '1|first-task'  => sub { $mode = '1' },
+       '2|second-task' => sub { $mode = '2' },
+       'r|relative'    => sub { $mode = 'r' },
+       'b|board=i'     => \$board_id,
+       'f|force'       => \$force
+or die "Usage: $0 [-n username] [-1|-2|-r] [-b board_id]\n";
+my $cache_filename = "cache-$board_id.json";
+my $cached = curfile->sibling($cache_filename);
+
+if ($force || !$cached->stat || time - $cached->stat->mtime > 900) {
+       warn "Downloading $cache_filename\n";
+       chomp(my $cookie = curfile->sibling('cookie')->slurp);
+       my $res = Mojo::UserAgent->new->get(
+               "https://adventofcode.com/2021/leaderboard/private/view/$board_id.json",
+               { Cookie => $cookie }
+       )->result;
+
+       $cached->spurt($res->body);
+}
+
+my $json = from_json $cached->slurp;
+
+
+my %times;
+my $my_time;
+for my $name (keys %{ $json->{members} }) {
+        my $member = $json->{members}->{$name};
+       my $level = $member->{completion_day_level}->{$day}
+               or next;
+       my $time;
+       if ($mode eq 'r') {
+               next if !$level->{2};
+               $time = $level->{2}->{get_star_ts} - $level->{1}->{get_star_ts};
+       } elsif ($mode eq '1') {
+               next if !$level->{1};
+               $time = $level->{1}->{get_star_ts};
+       } elsif ($mode eq '2') {
+               next if !$level->{2};
+               $time = $level->{2}->{get_star_ts};
+       }
+       my $id_or_name = $member->{name} // 'Anonymous user #' . $member->{id};
+       $times{ $id_or_name } = $time;
+       $my_time = $time
+               if $id_or_name eq $my_name;
+}
+
+for my $name (sort { $times{$a} <=> $times{$b} } keys %times) {
+       $my_time //= $times{$name};
+       printf("%6d %6d %s\n", $times{$name}, $times{$name} - $my_time, $name);
+}