aoc2021

Advent of Code 2021 solutions in Perl.
git clone git://git.samirparikh.com/aoc2021
Log | Files | Refs | README

day09.pl (2418B) - raw


      1 #!/usr/bin/env perl
      2 
      3 use strict;
      4 use warnings;
      5 use v5.22;
      6 
      7 sub get_filehandle {
      8   if (@ARGV !=1) {
      9     die "Usage: $0 [input-filename]";
     10   }
     11   my $input_filename = $ARGV[0];
     12   open my $filehandle, '<', $input_filename or
     13     die "Could not open input file $input_filename: $!";
     14   return $filehandle;
     15 }
     16 
     17 sub find_basin {
     18   my ($row, $column, $heightmap_ref) = @_;
     19   my $size = 1; # lowpoint is already part of basin
     20   my @queue = ( [$row, $column] );
     21   while ( @queue ) { # there are still locations in queue to check
     22     my $location = shift @queue;
     23     my $r = $location->[0];
     24     my $c = $location->[1];
     25     # don't want to double-count the initial lowpoint
     26     $heightmap_ref->[$r][$c] = 9;
     27     # check surrounding locations for increase in height
     28     foreach my $offset ([0, -1], [0, 1], [-1, 0], [1, 0]) {
     29       my $neighbor_row     = $r + $offset->[0];
     30       my $neighbor_col     = $c + $offset->[1];
     31       my $neighbor_height = $heightmap_ref->[$neighbor_row][$neighbor_col];
     32       next if ($neighbor_height == 9);
     33       # add neighbor coordinates to queue and set its height to 9 to prevent
     34       # it from being checked again (double-counted)
     35       push @queue => [ $neighbor_row, $neighbor_col ];
     36       $heightmap_ref->[$neighbor_row][$neighbor_col] = 9;
     37       $size++;
     38     }
     39   }
     40   return $size;
     41 }
     42 
     43 my $filehandle  =  get_filehandle();
     44 my @heightmap   =  map{ [m/\d/g, 9] } <$filehandle>; # add extra column of 9s
     45 my $columns     =  @{$heightmap[0]};
     46 push @heightmap => [ (9) x $columns ]; # add extra row of 9s
     47 my $rows        =  @heightmap;
     48 my $risk_level  =  0;
     49 my @basin_sizes;
     50 
     51 foreach my $row (0 .. $rows - 2) { # don't care about last row that we added
     52   foreach my $column (0 .. $columns - 2) { # don't care about the last column
     53     my $height = $heightmap[$row][$column];
     54     my $lowpoint = 1; # true
     55     foreach my $offset ([0, -1], [0, 1], [-1, 0], [1, 0]) {
     56       if ($height >=
     57           $heightmap[$row + $offset->[0]][$column + $offset->[1]]) {
     58         $lowpoint = 0; # set to false
     59         last;
     60       }
     61     }
     62     # found low point
     63     if ($lowpoint) {
     64       $risk_level += $height + 1;
     65       my $basin_size = find_basin( $row, $column, \@heightmap );
     66       push @basin_sizes => $basin_size;
     67     }
     68   }
     69 }
     70 
     71 say $risk_level;
     72 # plain `sort` routine just sorts strings by code point order
     73 @basin_sizes = sort { $a <=> $b} @basin_sizes;
     74 say $basin_sizes[-3] * $basin_sizes[-2] * $basin_sizes[-1];