-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolutionb.pl
85 lines (68 loc) · 2.1 KB
/
solutionb.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use strict;
use warnings;
use List::Priority;
use List::AllUtils;
my @dirs = ([0, 0], [-1, 0], [1, 0], [0, -1], [0, 1]);
my @board = map {chomp; [split //]} <>;
my $start = [0, List::AllUtils::firstidx {$_ eq '.'} $board[0]->@*];
my $end = [$#board, List::AllUtils::firstidx {$_ eq '.'} $board[-1]->@*];
my $ymax = scalar(@board) - 2;
my $xmax = scalar($board[0]->@*) - 2;
push(@board, [('#') x ($xmax + 2)]);
my %posgroups;
my @vblizz;
my @hblizz;
for my $y (1 .. $ymax) {
for my $x (1 .. $xmax) {
push($posgroups{$board[$y][$x]}->@*, [$y, $x]);
}
}
for (my $time = 0; $time < $ymax; $time++) {
for my $up ($posgroups{'^'}->@*) {
my $y = ($up->[0] - $time - 1) % $ymax + 1;
$vblizz[$time]{$y, $up->[1]} = 1;
}
for my $down ($posgroups{'v'}->@*) {
my $y = ($down->[0] + $time - 1) % $ymax + 1;
$vblizz[$time]{$y, $down->[1]} = 1;
}
}
for (my $time = 0; $time < $xmax; $time++) {
for my $left ($posgroups{'<'}->@*) {
my $x = ($left->[1] - $time - 1) % $xmax + 1;
$hblizz[$time]{$left->[0], $x} = 1;
}
for my $right ($posgroups{'>'}->@*) {
my $x = ($right->[1] + $time - 1) % $xmax + 1;
$hblizz[$time]{$right->[0], $x} = 1;
}
}
sub add {
my ($x, $y) = @_;
return [$x->[0] + $y->[0], $x->[1] + $y->[1]];
}
sub search {
my ($t0, $start, $end) = @_;
my $frontier = new List::Priority;
my %visited;
$frontier->insert(0, [$t0, $start]);
SEARCH:
while (my ($time, $pos) = ($frontier->shift)->@*) {
if ($pos->[0] == $end->[0] && $pos->[1] == $end->[1]) {
return $time;
}
next SEARCH if ($visited{$time, $pos->[0], $pos->[1]}++);
DIRECTION:
for my $dir (@dirs) {
my $neigh = add($pos, $dir);
next DIRECTION if (exists $vblizz[($time + 1) % $ymax]{$neigh->[0], $neigh->[1]}
|| exists $hblizz[($time + 1) % $xmax]{$neigh->[0], $neigh->[1]}
|| $board[$neigh->[0]][$neigh->[1]] eq '#');
$frontier->insert($time + 1, [$time + 1, $neigh]);
}
}
}
my $time = &search(0, $start, $end);
$time = &search($time, $end, $start);
my $result = &search($time, $start, $end);
print "$result\n";