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];