Quick actions

cmd+k|ctrl+k

Navigation

Languages

AoC 2023, day 18

Snippet info

Language

Raku

Visibility

public

Author

seaker

Created

2023-12-19T03:15:20.778214Z

Updated

2023-12-19T03:15:45.268314Z

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
}
INFO