view 09/09.jl @ 14:4bad3ee77ef2

Day 09 part 2
author Lewin Bormann <lbo@spheniscida.de>
date Sun, 11 Dec 2022 11:15:16 +0100
parents dfed6e6ea69b
children
line wrap: on
line source


const test_input::String = "R 4
U 4
L 3
D 1
R 4
D 1
L 5
R 2";

const test_input2::String = "R 5
U 8
L 8
D 3
R 17
D 10
L 25
U 20";

@enum Direction begin
    U
    D
    L
    R
end

function to_direction(c::Char)::Direction
    if c == 'U'
        U
    elseif c == 'D'
        D
    elseif c == 'L'
        L
    elseif c == 'R'
        R
    end
end

struct Step
    direction::Direction
    n::Int
end

function parse_input(lines::Iter)::Vector{Step} where {Iter}
    v = Vector{Step}();
    for l in lines
        a, b = split(l, ' ');
        push!(v, Step(to_direction(a[1]), parse(Int, b)));
    end
    v
end

function wheretogo(H::Tuple{Int,Int}, T::Tuple{Int,Int})::Vector{Direction}
    # This might have a more elegant solution...
    if H == T
        []
    elseif H[1]==T[1]
        if abs(H[2]-T[2]) < 2
            []
        else
            (H[2] > T[2] ? [U] : [D])
        end
    elseif H[2]==T[2]
        if abs(H[1]-T[1]) < 2
            []
        else
            (H[1] < T[1] ? [L] : [R])
        end
    elseif abs(H[1]-T[1]) + abs(H[2]-T[2]) == 3  # diagonal
        if abs(H[1]-T[1]) > abs(H[2]-T[2])
            snd = (H[2]-T[2]) > 0 ? U : D;
            (H[1]-T[1]) > 0 ? ([R, snd]) : ([L, snd])
        else
            snd = (H[1]-T[1]) > 0 ? R : L;
            (H[2]-T[2]) > 0 ? ([U, snd]) : ([D, snd])
        end
    elseif abs(H[1]-T[1])==abs(H[2]-T[2]) && abs(H[1]-T[1]) > 1
        [(H[1]>T[1] ? R : L), (H[2]>T[2] ? U : D)]
    else
        if abs(H[1]-T[1])+abs(H[2]-T[2]) == 2
            []
        else
            error("unhandled case: ", H, T)
        end
    end
end

function apply(p::Tuple{Int,Int}, dir::Direction)::Tuple{Int,Int}
    if dir == U
        p .+ (0,1)
    elseif dir == D
        p .+ (0,-1)
    elseif dir == L
        p .+ (-1,0)
    else
        p .+ (1,0)
    end
end

function process1(v::Vector{Step}; ntails=1)::Int
    H = (0, 0);
    T = [(0,0) for i in 1:ntails];
    visited = Set{Tuple{Int,Int}}([H])

    for step in v
        for i = 1:step.n
            H = apply(H, step.direction);
            # Tail follow
            pred = H
            for (i,t) in enumerate(T)
                wtg = wheretogo(pred, t);
                for w in wtg::Vector{Direction}
                    T[i] = apply(T[i], w);
                end
                pred = T[i];
            end
            push!(visited, pred);
        end
    end
    length(visited)
end

println("test input (should be 13):");
println(process1(parse_input(split(test_input, '\n'))));
println("part 1:");
open("09/input.txt"; read=true) do fh
    @time println(process1(parse_input(eachline(fh))));
end

println("part 2:");
println(process1(parse_input(split(test_input2, '\n')); ntails=9));
open("09/input.txt"; read=true) do fh
    @time println(process1(parse_input(eachline(fh)); ntails=9));
end