Advertisement
musifter

AoC 2024, day 20, Perl version of Smalltalk sol'n

Dec 20th, 2024
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 1.85 KB | Source Code | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. use feature         qw(say);
  7.  
  8. $| = 1;
  9.  
  10. # Read grid:
  11. my @Grid = map { [split(//)] } <>;
  12.  
  13. sub grid_at ($) { my $p = shift; return ($Grid[$p->[0]][$p->[1]]) }
  14.  
  15. # Vector stuff:
  16. my @Dirs = ([0,1], [1,0], [0,-1], [-1,0]);
  17. sub vec_sum ($$) { my ($v,$w) = @_; return [$v->[0] + $w->[0], $v->[1] + $w->[1]] }
  18. sub vec_eq ($$)  { my ($v,$w) = @_; return (($v->[0] == $w->[0]) and ($v->[1] == $w->[1])) }
  19. sub dist ($$)    { my ($v,$w) = @_; return (abs($v->[0] - $w->[0]) + abs($v->[1] - $w->[1])) }
  20.  
  21. # Find start and end:
  22. my ($start, $end);
  23. foreach my $y (0 .. $#Grid) {
  24.     foreach my $x (0 .. $Grid[0]->$#*) {
  25.         $start = [$y,$x]  if ($Grid[$y][$x] eq 'S');
  26.         $end   = [$y,$x]  if ($Grid[$y][$x] eq 'E');
  27.     }
  28. }
  29.  
  30. # Get path of race course
  31. my @path = ($start);
  32. my $pos = $start;
  33. my $back = -1;
  34.  
  35. while (!&vec_eq( $pos, $end )) {
  36.     DIR:
  37.     for (my $d = 0; $d < @Dirs; $d++) {
  38.         my $move = &vec_sum( $pos, $Dirs[$d] );
  39.         if (grid_at($move) ne '#' and $back != $d) {
  40.             $back = ($d + 2) % 4;
  41.             $pos  = $move;
  42.             push( @path, $move );
  43.             last DIR;
  44.         }
  45.     }
  46. }
  47.  
  48. # Done with grid, now using just the path:
  49. my $part1 = 0;
  50. my $part2 = 0;
  51. my $targ  = 100;
  52.  
  53. # Compare points that are far enough apart on the path to potentially gain target.
  54. foreach (my $i = 0; $i <= $#path - ($targ + 2); $i++) {
  55.     print ::stderr "[$i/$#path] $part2\r"  if ($i % 250 == 0);
  56.  
  57.     foreach (my $j = $i + ($targ + 2); $j <= $#path; $j++) {
  58.         my $dist = &dist( $path[$i], $path[$j] );
  59.  
  60.         # Check allowed distance, and if we didn't lose too much time.
  61.         if (($dist <= 20) and ($j - $i - $dist >= $targ)) {
  62.             $part2++;
  63.             $part1++  if ($dist == 2);
  64.         }
  65.     }
  66. }
  67.  
  68. say "\nPart 1: $part1";
  69. say "Part 2: $part2";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement