my ($rows, $cols);
sub solve(@M, Complex:D $start, Complex:D $target --> UInt:D) {
my %dists = $start => 0.Int;
my @Q = $start;
while @Q {
my @Q_;
for @Q -> $p {
my $elevation = @M[$p.re;$p.im];
my $dist = %dists{$p};
for (-i, i, -1.Complex, 1.Complex) -> $move {
my $p_ = $p + $move;
next unless 0 ≤ $p_.re ≤ $rows - 1;
next unless 0 ≤ $p_.im ≤ $cols - 1;
my $elevation_ = @M[$p_.re;$p_.im];
next unless ord($elevation_) - ord($elevation) ≤ 1;
without %dists{$p_} {
%dists{$p_} = $dist + 1;
return($dist + 1) if $p_ == $target;
@Q_.push($p_);
}
}
}
@Q = @Q_;
}
$rows * $cols # ∞
}
my @M = $*IN.lines.map({ .comb.Array }).Array;
$rows = +@M;
$cols = +@M[0];
my $start = do with @M[*;*].first('S', :k) { ($_ div $cols + ($_ mod $cols)i).Complex };
@M[$start.re;$start.im] = 'a';
my $target = do with @M[*;*].first('E', :k) { ($_ div $cols + ($_ mod $cols)i).Complex };
@M[$target.re;$target.im] = 'z';
put 'part 1: ', solve(@M, $start, $target);
put 'part 2: ', do for @M[*;*].grep('a', :k) -> \ndx {
solve(@M, (ndx div $cols + (ndx mod $cols)i).Complex, $target)
}.min;