musifter

AoC 2025 day 9 (Perl)

Dec 9th, 2025 (edited)
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.84 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::AllUtils  qw(max min minmax);
  8.  
  9. $| = 1;
  10.  
  11. my @input = map { chomp; [map {int} split /,/] } <>;
  12.  
  13. my %horz;
  14. my %vert;
  15. my @lines;
  16.  
  17. for (my $i = -1; $i < $#input; $i++) {
  18.     my @x = minmax ($input[$i][0], $input[$i+1][0]);
  19.     my @y = minmax ($input[$i][1], $input[$i+1][1]);
  20.  
  21.     push( @lines, [[$x[0],$y[0]], [$x[1],$y[1]]] );
  22.  
  23.     # ASSERT: Assuming only 1 interval in a given row or col (so no list needed)
  24.     # ASSERT: None of these are adjacent and parallel, forming a 0-width channel
  25.     if ($input[$i][1] == $input[$i+1][1]) {
  26.         $horz{$input[$i][1]}->@* = @x;
  27.     } else {
  28.         $vert{$input[$i][0]}->@* = @y;
  29.     }
  30. }
  31.  
  32. my @vertKeys = sort {$a<=>$b} keys %vert;
  33.  
  34. sub inside {
  35.     my @pt = @_;
  36.     my $cross = 0;
  37.  
  38.     return (1) if (exists $horz{$pt[1]} and ($horz{$pt[1]}[0] <= $pt[0] <= $horz{$pt[1]}[1]));
  39.     return (1) if (exists $vert{$pt[0]} and ($vert{$pt[0]}[0] <= $pt[1] <= $vert{$pt[0]}[1]));
  40.  
  41.     foreach my $x (@vertKeys) {
  42.         last if ($x > $pt[0]);
  43.  
  44.         if ($vert{$x}[0] < $pt[1] < $vert{$x}[1]) {
  45.             # cross middle
  46.             $cross++;
  47.  
  48.         } elsif ($vert{$x}[0] == $pt[1]) {
  49.             # hit top
  50.             my @hline = $horz{$pt[1]}->@*;
  51.             my $other = ($hline[0] != $pt[0]) ? $hline[0] : $hline[1];
  52.             $cross-- if ($vert{$other}[0] == $pt[1]);
  53.  
  54.         } elsif ($vert{$x}[1] == $pt[1]) {
  55.             # hit bottom
  56.             my @hline = $horz{$pt[1]}->@*;
  57.             my $other = ($hline[0] != $pt[0]) ? $hline[0] : $hline[1];
  58.             $cross-- if ($vert{$other}[1] == $pt[1]);
  59.         }
  60.     }
  61.  
  62.     return ($cross % 2);
  63. }
  64.  
  65. my $part1 = 0;
  66. my $part2 = 0;
  67. for (my $i = 0; $i < @input; $i++) {
  68.     BOX:
  69.     for (my $j = -1; $j < $i; $j++) {
  70.         my $area = (abs($input[$i][0] - $input[$j][0]) + 1)
  71.                  * (abs($input[$i][1] - $input[$j][1]) + 1);
  72.  
  73.         $part1 = max ($area, $part1);
  74.  
  75.         next if ($area < $part2);
  76.         next if (!&inside($input[$i][0], $input[$j][1]) or !&inside($input[$j][0], $input[$i][1]));
  77.  
  78.         my @x = minmax ($input[$i][0], $input[$j][0]);
  79.         my @y = minmax ($input[$i][1], $input[$j][1]);
  80.         my @rect = ([$x[0]+1, $y[0]+1], [$x[1]-1, $y[1]-1]);
  81.  
  82.         next if ($rect[1][0] < $rect[0][0] or $rect[1][1] < $rect[0][1]);
  83.  
  84.         foreach my $line (@lines) {
  85.             my @inter = ([max ($rect[0][0], $line->[0][0]), max ($rect[0][1], $line->[0][1])],
  86.                          [min ($rect[1][0], $line->[1][0]), min ($rect[1][1], $line->[1][1])]);
  87.  
  88.             next BOX if ($inter[0][0] <= $inter[1][0] and $inter[0][1] <= $inter[1][1]);
  89.         }
  90.  
  91.         if ($area > $part2) {
  92.             say "[$i]\t$area";
  93.             $part2 = $area;
  94.         }
  95.     }
  96. }
  97.  
  98. say "Part 1: $part1";
  99. say "Part 2: $part2";
Advertisement
Add Comment
Please, Sign In to add comment