class Lane {
has @.begin;
has @.end;
has $.dir;
has $.is-wall is rw;
}
enum Direction <horizontal vertical>;
my %mapper = <R D L U>.pairs;
put 'part 1: ', solve($*IN.lines.map({ .split(' ')[0, 1] }));
put 'part 2: ', solve($*IN.lines.map({
with .split(' ')[2] { %mapper{.substr(7,1)}, .substr(2,5).parse-base(16) }
}));
sub count-row(@path, \row) {
my ($cnt, $col) = 0, 0;
my $in-pool = False;
for @path.grep({
.dir == vertical and (.begin[0] < row < .end[0] or .end[0] < row < .begin[0]) or
.dir == horizontal and row == .begin[0]
}) -> \lane {
if $in-pool {
my $end = max(lane.begin[1], lane.end[1]) + 1;
$cnt += $end - $col;
$col = $end;
} else {
$col = min(lane.begin[1], lane.end[1]);
$cnt += abs(lane.end[1] - lane.begin[1]) + 1 unless lane.is-wall;
}
$in-pool = !$in-pool if lane.is-wall;
}
$cnt
}
sub solve(@M) {
my ($row, $col) = 0, 0;
my @path;
for @M -> (\ort, \len) {
my Array $end;
given ort {
when 'U'|'D' {
$end = [$row + len * (ort eq 'D' ?? 1 !! -1), $col];
@path.push(Lane.new(:begin([$row, $col]), :end(@$end), :dir(vertical), :is-wall(True)));
}
when 'L'|'R' {
$end = [$row, $col + len * (ort eq 'R' ?? 1 !! -1)];
@path.push(Lane.new(:begin([$row, $col]), :end(@$end), :dir(horizontal), :is-wall(True)));
}
}
($row, $col) = $end;
}
@path.map(-> \lane {
lane.is-wall = False if lane.dir == horizontal and do {
my \prev-lane = @path.first({ .end eqv lane.begin });
my \next-lane = @path.first({ .begin eqv lane.end });
sign(prev-lane.begin[0] - lane.begin[0]) * sign(next-lane.end[0] - lane.end[0]) == 1
}
});
@path .= sort({ .begin[1] });
my ($cnt, $last-row) = 0, 0;
for @path.map({ .begin[0], .end[0] }).flat.unique.sort -> \row {
$cnt += (row - $last-row - 1) * count-row(@path, $last-row + 1) if row - $last-row > 1;
$cnt += count-row(@path, row);
$last-row = row;
}
$cnt
}