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;
- use Math::Vector::Real;
- my ($Y,$X) = Math::Vector::Real->canonical_base(2);
- my @Dirs = ($Y, $X, -$Y, -$X);
- # Read in grid, adding sentinel 0s to right and bottom
- my @Grid = map { chomp; [map {int} split(//), 0] } <>;
- push( @Grid, [(0) x $Grid[0]->@*] );
- my $End = V($#Grid - 1, $Grid[0]->$#* - 1);
- sub grid_at ($) { my $p = shift; return ($Grid[$p->[0]][$p->[1]]) }
- sub print_grid { say "\t", join( '', @$_ ) foreach (@Grid); }
- my %visit;
- my $queue = new Array::Heap::PriorityQueue::Numeric;
- $queue->add( [0, V(0,0), 0], 0 );
- $queue->add( [0, V(0,0), 1], 0 );
- my $time = 0;
- QUEUE:
- while (my $state = $queue->get) {
- my ($cool, $pos, $dir) = @$state;
- if ($pos == $End) {
- say "\nPart 1: $cool";
- last QUEUE;
- }
- print ::stderr "[$time] Cooling: $cool (", $queue->size(), ") \r" if (++$time % 50000 == 0);
- next QUEUE if (exists $visit{$pos,$dir} and $cool >= $visit{$pos,$dir});
- $visit{$pos,$dir} = $cool;
- foreach my $turn (($dir + 1) % 4, ($dir - 1) % 4) {
- my $new_pos = $pos;
- my $new_cool = $cool;
- my $dist = $pos->manhattan_dist($End);
- my $delta = ($turn >= 2) ? 1 : -1;
- STEP:
- foreach my $steps (1 .. 3) {
- $new_pos += $Dirs[$turn];
- $dist += $delta;
- my $cooling = grid_at( $new_pos );
- last STEP if ($cooling == 0);
- $new_cool += $cooling;
- next STEP if (exists $visit{$new_pos,$turn} and $new_cool >= $visit{$new_pos,$turn});
- $queue->add( [$new_cool, $new_pos, $turn], $new_cool + $dist );
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement