Advertisement
musifter

AoC 2023 day 10 (Perl)

Dec 10th, 2023 (edited)
945
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.79 KB | Source Code | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use v5.26;
  4. use warnings;
  5.  
  6. use List::AllUtils  qw(first firstidx);
  7. use Math::Vector::Real;
  8.  
  9. # Set up unit vector basis and directions
  10. my ($vy,$vx) = Math::Vector::Real->canonical_base(2);
  11. my %Dirs = (S => $vy, E => $vx, N => -$vy, W => -$vx);
  12. my %Back = (S => 'N', E => 'W', N => 'S', W => 'E');
  13.  
  14. # Hash of pipes to directions of travel with a list of adjacent RHS dirs
  15. my %Pipe = (
  16.     '|' => {S => [ $vx], N => [-$vx]},
  17.     '-' => {W => [ $vy], E => [-$vy]},
  18.  
  19.     'L' => {N => [-$vx,  $vy ], E => []},
  20.     'J' => {W => [ $vx,  $vy ], N => []},
  21.     'F' => {E => [-$vx, -$vy ], S => []},
  22.     '7' => {S => [ $vx, -$vy ], W => []},
  23. );
  24.  
  25. # Hash from ends to type of piece
  26. my %Piece = ('NS' => '|', 'EW' => '-', 'EN' => 'L', 'NW' => 'J', 'ES' => 'F', 'SW' => '7');
  27.  
  28. # Read in grid, adding sentinels to right and bottom
  29. my @Grid = map { chomp; [split(//), '.', '~'] } <>;
  30. push( @Grid, [(('.') x $Grid[0]->$#*), '~'] );
  31. push( @Grid, [('~') x $Grid[0]->@*] );
  32.  
  33. # Helper to handle ugly access between Vector package in arrays
  34. sub grid_at ($) { my $p = shift; return ($Grid[$p->[0]][$p->[1]]) }
  35.  
  36. my %path;           # pipe path (don't need order, so hash)
  37.  
  38. # Find starting location
  39. my $pos;
  40. foreach my $y (0 .. @Grid - 1) {
  41.     my $x = firstidx { $_ eq 'S' } $Grid[$y]->@*;
  42.     if ($x != -1) {
  43.         $pos = V($y,$x);
  44.         $path{$pos}++;
  45.         last;
  46.     }
  47. }
  48.  
  49. # Figure out starting tile
  50. my @ends;
  51. for my $d (keys %Dirs) {
  52.     my $move = $pos + $Dirs{$d};
  53.     push( @ends, $d ) if (exists $Pipe{ grid_at($move) }{ $Back{$d} });
  54. }
  55.  
  56. my $steps = 0;
  57. my $tile = $Piece{join('', sort @ends)};    # get starting tile from its ends
  58. my $come_from = $ends[0];                   # take the first direction and go!
  59. my @rhs;                                    # track squares on RHS of our path
  60.  
  61. # Walk the path, keeping track of RHS and where we've been
  62. while ($tile ne 'S') {
  63.     push( @rhs, map { $pos + $_ } $Pipe{$tile}{$come_from}->@* );
  64.  
  65.     my $move = first { $_ ne $come_from } keys $Pipe{$tile}->%*;
  66.  
  67.     $pos += $Dirs{$move};
  68.     $path{$pos}++;
  69.     $come_from = $Back{$move};
  70.     $steps++;
  71.  
  72.     $tile = grid_at( $pos );
  73. }
  74.  
  75. say "Part 1: ", $steps / 2;
  76.  
  77. # Clear pipes not in cycle
  78. my $count = 0;
  79. foreach my $y (0 .. @Grid - 2) {
  80.     foreach my $x (0 .. $Grid[0]->$#* - 1) {
  81.         if (!exists $path{"{$y, $x}"}) {
  82.             $Grid[$y][$x] = '.';
  83.             $count++;
  84.         }
  85.     }
  86. }
  87.  
  88. # Floodfill from the RHS of the path
  89. my $rhs_count = 0;
  90. foreach my $pt (@rhs) {
  91.     next if (grid_at($pt) ne '.');
  92.  
  93.     $Grid[$pt->[0]][$pt->[1]] = '*';
  94.     $rhs_count++;
  95.     push( @rhs, map { $pt + $_ } values %Dirs );
  96. }
  97.  
  98. # If RHS flowed into sentinels, then the inside is the LHS of path.
  99. say "Part 2: ", ($Grid[0][-2] eq '*') ? $count - $rhs_count : $rhs_count;
  100.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement