Advertisement
musifter

AoC 2022, day 16 (perl pt 2)

Dec 17th, 2022 (edited)
1,891
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.19 KB | Source Code | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. use List::Util  qw(max);
  7.  
  8. my %valve;
  9. my %unstuck;
  10. my %dist;
  11. my %memo;
  12.  
  13. while (<>) {
  14.     my ($room, $flow, $lead) = m#^Valve (\w\w) has flow rate=(\d+);.*valves? (.*)#;
  15.     my @paths = ($lead =~ m#(\w\w)#g);
  16.  
  17.     $valve{$room} = {flow => $flow, paths => \@paths};
  18.     $unstuck{$room} = (1 << scalar keys %unstuck)  if ($flow > 0);
  19. }
  20.  
  21. # BFS to build symmetric table of distances between interesting points
  22. foreach my $i ('AA', keys %unstuck) {
  23.     my %visit;
  24.     my @queue = ([$i,0]);
  25.  
  26.     while (my $state = shift @queue) {
  27.         my ($room, $time) = @$state;
  28.  
  29.         next if ($visit{$room}++);
  30.  
  31.         if ($unstuck{$room}) {
  32.             $dist{$i}{$room} = $time;
  33.             $dist{$room}{$i} = $time;
  34.         }
  35.  
  36.         foreach my $tun ($valve{$room}{paths}->@*) {
  37.             push( @queue, [$tun, $time + 1] );
  38.         }
  39.     }
  40. }
  41.  
  42. # Recursive path finding on the new distance weighted directed graph
  43. sub recurse_path {
  44.     my ($room, $time, $left, $open, $total) = @_;
  45.     my $ret = 0;
  46.  
  47.     $total += $valve{$room}{flow} * (27 - $time);  # Add pressure released for valve
  48.  
  49.     $memo{$open} = $total  if (!exists $memo{$open} or $memo{$open} < $total);
  50.  
  51.     return ($total) if (!$left);                   # No more valves, wait
  52.  
  53.     my @moves = grep { $time + $dist{$room}{$_} + 1 < 26 }
  54.                 grep { $unstuck{$_} & $left } keys %unstuck;
  55.  
  56.     foreach my $tun (@moves) {
  57.         my $bit = $unstuck{$tun};
  58.         my $turns = $dist{$room}{$tun} + 1;        # Time to move + open valve
  59.  
  60.         $ret = max($ret, &recurse_path($tun, $time + $turns, ($left ^ $bit), ($open | $bit), $total));
  61.     }
  62.  
  63.     return ($ret);
  64. }
  65.  
  66. my $left_mask = (1 << scalar keys %unstuck) - 1;
  67. &recurse_path( 'AA', 1, $left_mask, 0, 0 );
  68.  
  69. my @paths = map { int } sort { $memo{$b} <=> $memo{$a} } keys %memo;
  70. my $part2 = 0;
  71.  
  72. PATH:
  73. for (my $i = 0; $i < $#paths; $i++) {
  74.     for (my $j = $i; $j <= $#paths; $j++) {
  75.         next if ($paths[$i] & $paths[$j]);
  76.         next PATH if ($memo{$paths[$i]} + $memo{$paths[$j]} < $part2);
  77.  
  78.         $part2 = max( $part2, $memo{$paths[$i]} + $memo{$paths[$j]} );
  79.     }
  80. }
  81.  
  82. print "Part 2: $part2\n";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement