Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- use strict;
- use warnings;
- use feature qw(say);
- use Array::Heap::PriorityQueue::Numeric;
- my @Dirs = ([0,1], [1,0], [0,-1], [-1,0]);
- sub vec_sum ($$) { my ($v,$w) = @_; return [$v->[0] + $w->[0], $v->[1] + $w->[1]] }
- my @Grid = map { chomp; [split(//)] } <>;
- sub grid_at ($) { my $p = shift; return ($Grid[$p->[0]][$p->[1]]) }
- sub as_str ($) { my $p = shift; return (join(',', @$p)) }
- sub print_grid { say "\t", join( '', @$_ ) foreach (@Grid); }
- my ($start, $end);
- foreach my $y (0 .. $#Grid) {
- foreach my $x (0 .. $Grid[0]->$#*) {
- $start = [$y,$x] if ($Grid[$y][$x] eq 'S');
- $end = [$y,$x] if ($Grid[$y][$x] eq 'E');
- }
- }
- my %paths; # collects all path elements
- my $min = ~0; # minium path seen
- my $time;
- my %visit;
- my $queue = new Array::Heap::PriorityQueue::Numeric;
- $queue->add( [$start, 0, 0, [], 0], 0 );
- QUEUE:
- while (my $state = $queue->get) {
- my ($pos, $face, $turn, $path, $moves) = @$state;
- next QUEUE if ($moves > $min);
- if (grid_at($pos) eq 'E') {
- say "Part 1: $moves " if ($moves < $min);
- $min = $moves;
- %paths = (%paths, map {as_str($_) => 1} @$path);
- next QUEUE;
- }
- print ::stderr "[$time] ",$queue->size," \r" if (++$time % 10000 == 0);
- next QUEUE if (($visit{@$pos, $face} // ~0) < $moves);
- $visit{@$pos, $face} = $moves;
- # Try straight if valid
- my $step = &vec_sum( $pos, $Dirs[$face] );
- if (grid_at($step) ne '#') {
- $queue->add( [$step, $face, 0, [@$path, $step], $moves + 1], $moves + 1 );
- }
- # Try turns, with an immediate step
- # ASSUME: Never want to turn twice, only place this would matter is a U-turn at the start
- if (!$turn) {
- foreach my $t (1,-1) {
- $queue->add( [$pos, ($face+$t) % 4, $t, $path, $moves + 1000], $moves + 1000 );
- }
- }
- }
- # +1 for missing End
- say "Part 2: ", 1 + keys %paths, " ";
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement