Advertisement
musifter

AoC 2024, day 15, part 2 (Perl)

Dec 15th, 2024 (edited)
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 3.49 KB | Source Code | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. use feature         qw(say);
  7. use List::Util      qw(any all);
  8.  
  9. use Math::Vector::Real;
  10.  
  11. my ($vy,$vx) = Math::Vector::Real->canonical_base(2);
  12. my %Dirs = ('v' => $vy, '>' => $vx, '^' => -$vy, '<' => -$vx);
  13.  
  14. $/ = '';
  15. my ($in_map, $in_moves) = map {[split /\n/]} <>;
  16.  
  17. my @moves = map {  split //  } @$in_moves;
  18. my @Grid  = map { [map {($_ eq 'O') ? ('[',']') : ($_,$_)} split //] } @$in_map;
  19. my $robot;
  20.  
  21. sub grid_at ($) { my $p = shift; return ($Grid[$p->[0]][$p->[1]]) }
  22.  
  23. SEARCH:
  24. foreach my $y (0 .. $#Grid) {
  25.     foreach my $x (0 .. $Grid[0]->$#*) {
  26.         if ($Grid[$y][$x] eq '@') {
  27.             $robot = V($y, $x);
  28.             $Grid[$y][$x]   = '.';
  29.             $Grid[$y][$x+1] = '.';
  30.             last SEARCH;
  31.         }
  32.     }
  33. }
  34.  
  35. # Recursive sub to test if boxes can be vertically pushed (and collect them in boxes)
  36. # And leaf hitting a wall stops everything... everything needs to be clear at the ends.
  37. sub test_vert_push {
  38.     my ($pos, $dir, $boxes) = @_;
  39.  
  40.     push( @$boxes, $pos );
  41.  
  42.     # Get both squares ahead of box push
  43.     my @ahead = map {grid_at($pos + $_)} ($dir, $dir + $vx);
  44.     if (all {$_ eq '.'} @ahead) {
  45.         return (1);
  46.     } elsif (any {$_ eq '#'} @ahead) {
  47.         return (0);
  48.     }
  49.  
  50.     # Got more multipushing to do
  51.     my $ret = 1;
  52.     if (join('', @ahead) eq '[]') {
  53.         $ret *= &test_vert_push( $pos + $dir, $dir, $boxes );   # one box straight ahead
  54.     } else {
  55.         # A box to the left or right ahead, maybe both:
  56.         $ret *= &test_vert_push( $pos + $dir - $vx, $dir, $boxes ) if ($ahead[0] eq ']');
  57.         $ret *= &test_vert_push( $pos + $dir + $vx, $dir, $boxes ) if ($ahead[1] eq '[');
  58.     }
  59.  
  60.     return ($ret);
  61. }
  62.  
  63. MOVE:
  64. foreach my $d (@moves) {
  65.     my $move = $robot + $Dirs{$d};
  66.     my $targ = grid_at($move);
  67.  
  68.     if ($targ eq '.' or $targ eq '#') {
  69.         $robot = $move  if ($targ eq '.');      # move
  70.         next MOVE;
  71.     }
  72.  
  73.     # Pushing a box
  74.     if ($d eq '<' or $d eq '>') {   # horizontal push
  75.         my $end = $move;
  76.  
  77.         # Check for space at end of multipush
  78.         $end += $Dirs{$d}  while (grid_at($end) eq '[' or grid_at($end) eq ']');
  79.  
  80.         next MOVE if (grid_at($end) eq '#');    # bump
  81.  
  82.         # Box halves toggle left<->right in horizontal push
  83.         for (my $p = $move; $p != $end; $p += $Dirs{$d}) {
  84.             $Grid[ $p->[0] ][ $p->[1] ] = (grid_at($p) eq '[' ? ']' : '[');
  85.         }
  86.  
  87.         # Set the ends, move the robot
  88.         $Grid[  $end->[0] ][  $end->[1] ] = grid_at($move);
  89.         $Grid[ $move->[0] ][ $move->[1] ] = '.';
  90.         $robot = $move;
  91.  
  92.     } else {                        # vertical push
  93.         my @boxes;
  94.         my $test = &test_vert_push( $move - $vx * (grid_at($move) eq ']'), $Dirs{$d}, \@boxes );
  95.  
  96.         if ($test) {
  97.             # clear old box locations
  98.             foreach my $box (@boxes) {
  99.                 $Grid[ $box->[0] ][ $box->[1]   ] = '.';
  100.                 $Grid[ $box->[0] ][ $box->[1]+1 ] = '.';
  101.             }
  102.  
  103.             # set new box locations
  104.             foreach my $box (@boxes) {
  105.                 my $p = $box + $Dirs{$d};
  106.                 $Grid[ $p->[0] ][ $p->[1]   ] = '[';
  107.                 $Grid[ $p->[0] ][ $p->[1]+1 ] = ']';
  108.             }
  109.  
  110.             $robot = $move;
  111.         }
  112.     }
  113. }
  114.  
  115. my $part2 = 0;
  116. foreach my $y (0 .. $#Grid) {
  117.     foreach my $x (0 .. $Grid[0]->$#*) {
  118.         $part2 += (100 * $y + $x)  if ($Grid[$y][$x] eq '[');
  119.     }
  120. }
  121.  
  122. say "Part 2: $part2";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement