musifter

AoC day 15 (Perl)

Dec 15th, 2021 (edited)
573
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 1.42 KB | None | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. use List::Priority;
  7.  
  8. $| = 1;
  9.  
  10. use List::AllUtils  qw(pairwise any);
  11.  
  12. my @dirs = ([-1,0], [1,0], [0,-1], [0,1]);
  13.  
  14. my @grid = map { chomp; [split //] } <>;
  15. my $max = scalar( @grid ) - 1;
  16.  
  17. # Ugly building of map for part 2
  18. # Build out horizontally
  19. foreach my $y (0 .. $max) {
  20.     push( @{$grid[$y]}, map {my $i = $_; map { ($_ + $i - 1) % 9 + 1 } @{$grid[$y]}} (1 .. 4) );
  21. }
  22.  
  23. # Build out vertically
  24. foreach my $i (1 .. 4) {
  25.     foreach my $y (0 .. $max) {
  26.         push( @grid, [map { ($_ + $i - 1) % 9 + 1 } @{$grid[$y]}] );
  27.     }
  28. }
  29.  
  30. # adjust max for new map
  31. $max = scalar( @grid ) - 1;
  32.  
  33.  
  34. # Same Dijkstra search as part 1
  35. my @visit = map { [(~0) x ($max + 1)] } (1 .. ($max + 1));
  36.  
  37. my $queue = new List::Priority;
  38. $queue->insert( 0, [0,0,0] );
  39.  
  40. my $time = 0;
  41.  
  42. queue:
  43. while (my $state = $queue->shift) {
  44.     my ($risk, $y, $x) = @$state;
  45.  
  46.     print ::stderr "Risk: $risk\r"  if ($time++ % 50000 == 0);
  47.  
  48.     if ($y == $x == $max) {
  49.         print "Part 2: $risk\n";
  50.         last queue;
  51.     }
  52.  
  53.     next queue  if ($visit[$y][$x] <= $risk);
  54.     $visit[$y][$x] = $risk;
  55.  
  56.     move:
  57.     foreach my $move (map { [pairwise {$a + $b} @{[$y,$x]}, @$_] } @dirs) {
  58.         next move if (any { $_ < 0 || $_ > $max } @$move);
  59.  
  60.         my $new_risk = $risk + $grid[$move->[0]][$move->[1]];
  61.         $queue->insert( $new_risk, [$new_risk, $move->[0], $move->[1]] );
  62.     }
  63. }
Add Comment
Please, Sign In to add comment