]> www.fi.muni.cz Git - aoc.git/blobdiff - 2023/28.pl
Day 14: more polished solution
[aoc.git] / 2023 / 28.pl
index 7135ca558336ee5b39994d2d2cff5c5ab335fadf..0699eb466166399800d4de012419d68b218bd3c8 100755 (executable)
@@ -7,86 +7,43 @@ my $xmax = $#{ $map[0] };
 my $ymax = $#map;
 
 my %seen;
-my @rounds;
+my @score;
 my $round;
-while (1) {
-       $round++;
-       my $retry;
-       $retry = 1;
-       while ($retry) {
-               $retry = 0;
-               for my $y (1 .. $ymax) {
-                       for my $x (0 .. $xmax) {
-                               if ($map[$y][$x] eq 'O' && $map[$y-1][$x] eq '.') {
-                                       $map[$y-1][$x] = 'O';
-                                       $map[$y][$x] = '.';
-                                       $retry = 1;
-                               }
-                       }
-               }
-       }
-       $retry = 1;
-       while ($retry) {
-               $retry = 0;
-               for my $x (1 .. $xmax) {
-                       for my $y (0 .. $ymax) {
-                               if ($map[$y][$x] eq 'O' && $map[$y][$x-1] eq '.') {
-                                       $map[$y][$x-1] = 'O';
-                                       $map[$y][$x] = '.';
-                                       $retry = 1;
-                               }
-                       }
-               }
-       }
-       $retry = 1;
-       while ($retry) {
-               $retry = 0;
-               for my $y (reverse 0 .. $ymax-1) {
+my $key;
+
+while (++$round) {
+       for (1 .. 4) {
+               for my $y (0 .. $ymax) {
                        for my $x (0 .. $xmax) {
-                               if ($map[$y][$x] eq 'O' && $map[$y+1][$x] eq '.') {
-                                       $map[$y+1][$x] = 'O';
-                                       $map[$y][$x] = '.';
-                                       $retry = 1;
-                               }
-                       }
-               }
-       }
-       $retry = 1;
-       while ($retry) {
-               $retry = 0;
-               for my $x (reverse 0 .. $xmax-1) {
-                       for my $y (0 .. $ymax) {
-                               if ($map[$y][$x] eq 'O' && $map[$y][$x+1] eq '.') {
-                                       $map[$y][$x+1] = 'O';
-                                       $map[$y][$x] = '.';
-                                       $retry = 1;
+                               next if $map[$y][$x] ne 'O';
+                               my $y1 = $y;
+                               while ($y1 && $map[$y1-1][$x] eq '.') {
+                                       $map[$y1][$x] = '.';
+                                       $map[--$y1][$x] = 'O';
                                }
                        }
                }
+
+               @map = map { # rotate clockwise
+                       my $x = $_;
+                       [ map { $map[$_][$x] } reverse 0 .. $ymax ]
+               } 0 .. $xmax;
+               ($xmax, $ymax) = ($ymax, $xmax);
        }
-               
-       # say join('', @$_) for @map;
 
-       my $sum;
+       $key = join("\n", map { join('', @$_) } @map);
+       last if $seen{$key};
+
+       my $sum = 0;
        for my $y (0 .. $ymax) {
                for my $x (0 .. $xmax) {
                        $sum += $ymax + 1 - $y if $map[$y][$x] eq 'O';
                }
        }
-       say $sum;
-       $rounds[$round] = $sum;
-       say "round $round sum $sum";
-       my $map = join("\n", map { join('', @$_) } @map);
-       if ($seen{$map}) {
-               say "round $round seen also at $seen{$map}";
-               my $period = $round - $seen{$map};
-               my $total = 1000000000;
-               $total -= $round;
-               $total %= $period;
-               say "looking at ", $round - $period + $total;
-               say $rounds[$round-$period+$total];
-               last;
-       }
-       $seen{$map} = $round;
+
+       $seen{$key} = $round;
+       $score[$round] = $sum;
 }
 
+my $remains = (1000000000 - $round) % ($round - $seen{$key});
+say $score[$seen{$key} + $remains];