Advertisement
musifter

AoC 2022, day 17 (perl pt 2)

Dec 17th, 2022 (edited)
1,712
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 2.56 KB | Source Code | 0 0
  1. #!/usr/bin/perl
  2.  
  3. use strict;
  4. use warnings;
  5.  
  6. use List::Util  qw(max all reduce);
  7.  
  8. my $Num_rocks = 1_000_000_000_000;
  9.  
  10. my %Grid;
  11. my %Dirs = ('>' => [0,1], '<' => [0,-1]);
  12.  
  13. my @Blocks = ([[ 0,0], [ 0,1], [ 0,2], [ 0,3]],             # —
  14.               [[-2,1], [-1,0], [-1,1], [-1,2], [0,1]],      # ✚
  15.               [[-2,0], [-2,1], [-2,2], [-1,2], [0,2]],      # ⅃
  16.               [[-3,0], [-2,0], [-1,0], [ 0,0]],             # |
  17.               [[-1,0], [-1,1], [ 0,0], [ 0,1]]);            # ⬜
  18.  
  19. my $Num_blocks = scalar @Blocks;
  20.  
  21. my @Input = map { chomp; split // } <>;
  22. my $Input_len = scalar @Input;
  23. my $Inptr = -1;
  24.  
  25. sub vec_sum ($$) {
  26.     my ($p,$q) = @_;
  27.     return ([$p->[0] + $q->[0], $p->[1] + $q->[1]]);
  28. }
  29.  
  30. sub move_block {
  31.     my ($blk, $pos) = @_;
  32.     my $dropped;
  33.  
  34.     my @squares = map { vec_sum( $pos, $_ ) } $Blocks[$blk]->@*;
  35.  
  36.     do {
  37.         my $move = $Input[$Inptr = ($Inptr + 1) % $Input_len];
  38.  
  39.         # Try sliding
  40.         my @try = map { vec_sum( $_, $Dirs{$move} ) } @squares;
  41.         @squares = @try if (all {0 <= $_->[1] < 7 and !$Grid{$_->[0],$_->[1]}} @try);
  42.  
  43.         # Try dropping
  44.         @try = map { vec_sum( $_, [-1,0] ) } @squares;
  45.         @squares = @try if ($dropped = all {!$Grid{$_->[0],$_->[1]}} @try);
  46.     } while ($dropped);
  47.  
  48.     # Place piece:
  49.     $Grid{$_->[0],$_->[1]} = '#' foreach (@squares);
  50.  
  51.     return (@squares);
  52. }
  53.  
  54. #
  55. # Mainline
  56. #
  57. my %hash;
  58.  
  59. # Initialize floor
  60. my @tops;
  61. my $peak = 0;
  62.  
  63. foreach (0 .. 6) {
  64.     $tops[$_] = 0;
  65.     $Grid{$peak,$_} = '-';
  66. }
  67.  
  68. for (my $rock = 0; $rock < $Num_rocks; $rock++) {
  69.     my $blk = $rock % $Num_blocks;
  70.     my $pos = [$peak + 4 - $Blocks[$blk][0][0], 2];
  71.  
  72.     my @squares = &move_block( $blk, $pos );
  73.     my $blktop  = reduce { max($a, $b->[0]) } (0, @squares);
  74.  
  75.     # Adjust relative top positions if needed:
  76.     if ($blktop > $peak) {
  77.         my $delta = $blktop - $peak;
  78.         @tops = map { $_ - $delta } @tops;
  79.         $peak = $blktop;
  80.     }
  81.  
  82.     # Account for piece changing top positions:
  83.     $tops[$_->[1]] = max( $tops[$_->[1]], $_->[0] - $peak ) foreach (@squares);
  84.  
  85.     # Look for looping cycle and jump ahead:
  86.     my $key = "$Inptr:$blk:" . join( ',', @tops );
  87.     if (!exists $hash{$key}) {
  88.         $hash{$key} = [$rock,$peak];
  89.     } elsif (($Num_rocks - $rock - 1) % ($rock - $hash{$key}[0]) == 0) {
  90.         my $len_cycle  = $rock - $hash{$key}[0];
  91.         my $num_cycles = ($Num_rocks - $rock - 1) / $len_cycle;
  92.  
  93.         $peak += $num_cycles * ($peak - $hash{$key}[1]);
  94.         print "Part 2: $peak\n";
  95.         exit;
  96.     }
  97. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement