Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- use v5.12;
- use warnings;
- my @dirs = ([0, 1], [0, -1], [1, 0], [-1, 0]);
- # Read in grid and put a ring of '~' around it
- my @grid = map { chomp; [ '~', split( // ), '~' ] } <>;
- my $MAX_X = scalar @{$grid[0]};
- unshift( @grid, [split //, ('~' x $MAX_X)] );
- push( @grid, [split //, ('~' x $MAX_X)] );
- my $MAX_Y = scalar @grid;
- # Find start and end points (and change them to their heights)
- my $start;
- my $end;
- foreach my $y (1 .. $MAX_Y - 2) {
- foreach my $x (1 .. $MAX_X - 2) {
- if ($grid[$y][$x] eq 'S') {
- $start = [$y,$x];
- $grid[$y][$x] = 'a';
- }
- if ($grid[$y][$x] eq 'E') {
- $end = [$y,$x];
- $grid[$y][$x] = 'z';
- }
- last if ($start && $end);
- }
- }
- # Path finding routine:
- # - starts at $start
- # - uses &$found_end( pos ) to detect if at end
- # - uses &$good_height( current, move ) to tell if move is valid
- sub find_path {
- my ($start, $found_end, $good_height) = @_;
- my @visited;
- my @queue = ( [0, $start] );
- while (my $state = shift @queue) {
- my ($time, $pos) = @$state;
- return ($time) if (&$found_end( $pos->[0], $pos->[1] ));
- next if ($visited[$pos->[0]][$pos->[1]]++);
- my $height = ord( $grid[$pos->[0]][$pos->[1]] );
- foreach my $d (@dirs) {
- my $move = [$pos->[0] + $d->[0], $pos->[1] + $d->[1]];
- my $move_height = ord( $grid[$move->[0]][$move->[1]] );
- if (&$good_height( $height, $move_height )) {
- push( @queue, [$time + 1, $move] );
- }
- }
- }
- }
- say "Part 1: ", &find_path( $start,
- sub {$_[0] == $end->[0] && $_[1] == $end->[1]}, # find end
- sub {$_[0] + 1 >= $_[1]} ); # going up
- say "Part 2: ", &find_path( $end,
- sub {$grid[$_[0]][$_[1]] eq 'a'}, # find a
- sub {$_[0] - 1 <= $_[1] <= ord('z')} ); # going down
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement