Advertisement
musifter

AoC day 16, part 2 (Perl)

Dec 16th, 2024 (edited)
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 1.97 KB | Source Code | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. use feature         qw(say);
  7.  
  8. use Array::Heap::PriorityQueue::Numeric;
  9.  
  10. my @Dirs = ([0,1], [1,0], [0,-1], [-1,0]);
  11. sub vec_sum ($$) { my ($v,$w) = @_; return [$v->[0] + $w->[0], $v->[1] + $w->[1]] }
  12.  
  13. my @Grid = map { chomp; [split(//)] } <>;
  14.  
  15. sub grid_at ($) { my $p = shift; return ($Grid[$p->[0]][$p->[1]]) }
  16. sub as_str ($)  { my $p = shift; return (join(',', @$p)) }
  17. sub print_grid  { say "\t", join( '', @$_ ) foreach (@Grid); }
  18.  
  19. my ($start, $end);
  20. foreach my $y (0 .. $#Grid) {
  21.     foreach my $x (0 .. $Grid[0]->$#*) {
  22.         $start = [$y,$x]  if ($Grid[$y][$x] eq 'S');
  23.         $end   = [$y,$x]  if ($Grid[$y][$x] eq 'E');
  24.     }
  25. }
  26.  
  27. my %paths;              # collects all path elements
  28. my $min = ~0;           # minium path seen
  29. my $time;
  30. my %visit;
  31.  
  32. my $queue = new Array::Heap::PriorityQueue::Numeric;
  33. $queue->add( [$start, 0, 0, [], 0], 0 );
  34.  
  35. QUEUE:
  36. while (my $state = $queue->get) {
  37.     my ($pos, $face, $turn, $path, $moves) = @$state;
  38.  
  39.     next QUEUE if ($moves > $min);
  40.  
  41.     if (grid_at($pos) eq 'E') {
  42.         say "Part 1: $moves     " if ($moves < $min);
  43.         $min = $moves;
  44.         %paths = (%paths, map {as_str($_) => 1} @$path);
  45.         next QUEUE;
  46.     }
  47.  
  48.     print ::stderr "[$time] ",$queue->size,"   \r" if (++$time % 10000 == 0);
  49.  
  50.     next QUEUE if (($visit{@$pos, $face} // ~0) < $moves);
  51.     $visit{@$pos, $face} = $moves;
  52.  
  53.     # Try straight if valid
  54.     my $step = &vec_sum( $pos, $Dirs[$face] );
  55.     if (grid_at($step) ne '#') {
  56.         $queue->add( [$step, $face, 0, [@$path, $step], $moves + 1], $moves + 1 );
  57.     }
  58.  
  59.     # Try turns, with an immediate step
  60.     # ASSUME: Never want to turn twice, only place this would matter is a U-turn at the start
  61.     if (!$turn) {
  62.         foreach my $t (1,-1) {
  63.             $queue->add( [$pos, ($face+$t) % 4, $t, $path, $moves + 1000], $moves + 1000 );
  64.         }
  65.     }
  66. }
  67.  
  68. # +1 for missing End
  69. say "Part 2: ", 1 + keys %paths, "     ";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement