]> www.fi.muni.cz Git - aoc.git/commitdiff
2019 day 18 - slow and ugly bruteforce
authorJan "Yenya" Kasprzak <kas@fi.muni.cz>
Mon, 13 Nov 2023 09:14:39 +0000 (10:14 +0100)
committerJan "Yenya" Kasprzak <kas@fi.muni.cz>
Mon, 13 Nov 2023 09:14:39 +0000 (10:14 +0100)
2019/35.pl [new file with mode: 0755]
2019/36.pl [new file with mode: 0755]

diff --git a/2019/35.pl b/2019/35.pl
new file mode 100755 (executable)
index 0000000..07758eb
--- /dev/null
@@ -0,0 +1,88 @@
+#!/usr/bin/perl -w
+
+use v5.36;
+use Data::Dumper;
+use Array::Heap;
+use feature 'multidimensional';
+
+my @map = map { chomp; [ split // ] } <>;
+
+my %pos_of;
+for my $y (0 .. $#map) {
+       for my $x (0 .. $#{ $map[0]}) {
+               my $c = $map[$y][$x];
+               next if $c !~ /[a-z@]/;
+               $pos_of{$c} = [ $x, $y ];
+       }
+}
+
+my $nkeys = keys %pos_of;
+say "nkeys = $nkeys";
+
+$; = ';';
+
+my $best;
+
+my $min_dist = 1_000_000;
+
+my %min_cost;
+my @q0;
+sub walk {
+       my ($cost, @opened) = @_;
+
+       my %opened = map { $_ => 1 } @opened;
+
+       my $key = $opened[0] . join('', sort @opened);
+
+       if (defined $min_cost{$key} && $min_cost{$key} <= $cost) {
+               return;
+       }
+
+       $min_cost{$key} = $cost;
+
+       say "walk $min_dist $cost - $key ", length $key;
+       if ($nkeys + 1 == length $key) {
+               say "Found!";
+               exit 1;
+       }
+
+       my $p = $pos_of{$opened[0]};
+       my @q = [ @$p, $cost ];
+
+       my %seen;
+       $seen{$p->[0],$p->[1]} = 1;
+
+       my %dist;
+
+       while (my $pos = shift @q) {
+               my ($x, $y, $steps) = @$pos;
+
+               my $v = $map[$y][$x];
+               next if $v eq '#';
+               if ($v =~ /[a-z]/ && !$opened{$v}) {
+                       $dist{$v} //= $steps;
+                       # say "opened=". scalar @opened;
+                       $min_dist = $steps if $min_dist > $steps
+                               && @opened == keys %pos_of;
+                       push_heap @q0, [ $steps, $v, @opened ];
+               }
+               if ($v =~ /[A-Z]/) {
+                       next if !$opened{lc($v)};
+               }
+       
+               for my ($dx, $dy) (1, 0, 0, 1, -1, 0, 0, -1) {
+                       my ($nx, $ny) = ($x + $dx, $y + $dy);
+                       next if $seen{$nx,$ny}++;
+                       push @q, [ $nx, $ny, $steps+1 ]
+                               if $steps + 1 < $min_dist;
+               }
+       }
+}
+
+push_heap @q0, [0, '@'];
+while (@q0) {
+       my $elem = pop_heap @q0;
+       walk(@$elem);
+}
+
+say $min_dist;
diff --git a/2019/36.pl b/2019/36.pl
new file mode 100755 (executable)
index 0000000..f56553c
--- /dev/null
@@ -0,0 +1,96 @@
+#!/usr/bin/perl -w
+
+use v5.36;
+use Data::Dumper;
+use Array::Heap;
+use feature 'multidimensional';
+
+my @map = map { chomp; [ split // ] } <>;
+
+my %pos_of;
+for my $y (0 .. $#map) {
+       for my $x (0 .. $#{ $map[0]}) {
+               my $c = $map[$y][$x];
+               next if $c !~ /[a-z1-4]/;
+               $pos_of{$c} = [ $x, $y ];
+       }
+}
+
+my $nkeys = keys %pos_of;
+say "nkeys = $nkeys";
+
+$; = ';';
+
+my $best;
+
+my $min_dist = 1_000_000;
+
+my %min_cost;
+my $max_opened;
+my $max_cost;
+my @q0;
+sub walk {
+       my ($cost0, $cost, @opened) = @_;
+
+       my @robots = splice(@opened, 0, 4);
+       my %opened = map { $_ => 1 } @opened;
+
+       my $key = join('', $robots[0], sort(@robots[1..3]), '|', sort @opened);
+
+       if (defined $min_cost{$key} && $min_cost{$key} <= $cost) {
+               return;
+       }
+
+       $min_cost{$key} = $cost;
+
+       $max_opened = @opened if (!defined $max_opened || @opened > $max_opened);
+       if (!defined $max_cost || $max_cost < $cost) {
+               $max_cost = $cost;
+               say "walk $cost - $key ", length $key, ' ', $max_opened;
+       }
+       if ($nkeys == @opened) {
+               say "Found!";
+               exit 1;
+       }
+               
+
+       my $p = $pos_of{$robots[0]};
+       my @q = [ @$p, $cost ];
+
+       my %seen;
+       $seen{$p->[0],$p->[1]} = 1;
+
+       my %dist;
+
+       while (my $pos = shift @q) {
+               my ($x, $y, $steps) = @$pos;
+
+               my $v = $map[$y][$x];
+               next if $v eq '#';
+               if ($v =~ /[a-z]/ && !$opened{$v}) {
+                       $dist{$v} //= $steps;
+                       my $cost = $steps + $nkeys - @opened;
+                       # say "opened=". scalar @opened;
+                       push_heap @q0, [ $cost, $steps, $v, @robots[1..3], $v, @opened ];
+                       push_heap @q0, [ $cost, $steps, $robots[1], $v, @robots[2..3], $v, @opened ];
+                       push_heap @q0, [ $cost, $steps, $robots[2], $v, @robots[1,3], $v, @opened ];
+                       push_heap @q0, [ $cost, $steps, $robots[3], $v, @robots[1..2], $v, @opened ];
+               }
+               if ($v =~ /[A-Z]/) {
+                       next if !$opened{lc($v)};
+               }
+       
+               for my ($dx, $dy) (1, 0, 0, 1, -1, 0, 0, -1) {
+                       my ($nx, $ny) = ($x + $dx, $y + $dy);
+                       next if $seen{$nx,$ny}++;
+                       push @q, [ $nx, $ny, $steps+1 ];
+               }
+       }
+}
+
+push_heap @q0, [0, 0, 1, 2, 3, 4, 1, 2, 3, 4];
+while (@q0) {
+       my $elem = pop_heap @q0;
+       walk(@$elem);
+}
+