Advent of Code 2024

thoughts and solutions

 

Day 19

file:test/Day19Spec.jl
# add tests
file:src/Day19.jl
module Day19

function read_input(io::IO)
    lines = readlines(io) |> collect
    patterns = split(lines[1], ", ")
    designs = lines[3:end]
    return patterns, designs
end

mutable struct Tree{T}
    isleaf::Bool
    branches::Dict{T, Tree{T}}
end

Tree{T}() where {T} = Tree{T}(false, Dict{T, Tree{T}}())

add_path!(t::Tree{T}, it::I) where {T, I} =
    _add_path_helper!(t, it, iterate(it))

add_path!(t::Tree{T}, it::I, state::S) where {T, I, S} =
    _add_path_helper!(t, it, iterate(it, state))

function _add_path_helper!(t::Tree{T}, it::I, item::Nothing) where {T, I}
    t.isleaf = true
    return t
end

function _add_path_helper!(t::Tree{T}, it::I, item::Tuple{T, S}) where {T, I, S}
    value, state = item

    if value  keys(t.branches)
        t.branches[value] = Tree(false, Dict{T, Tree{T}}())
    end

    add_path!(t.branches[value], it, state)
end

function pattern_tree(pat::Vector{S}) where {S<:AbstractString}
    t = Tree{Char}()
    for p in pat
        add_path!(t, p)
    end
    return t
end

Base.match(p::Tree{Char}) = s -> match(p, s, Dict{String, Int}())

function Base.match(p::Tree{Char}, s::T, cache::Dict{String,Int}) where {T <: AbstractString}
    s  keys(cache) && return cache[s]

    function compute()
        isempty(s) && return 1
        s[1]  keys(p.branches) && return 0

        remainders = T[]
        partial_match(p.branches[s[1]], s[2:end], remainders)
        sum(r->match(p, r, cache), remainders; init=0)
    end

    return cache[s] = compute()
end

function partial_match(p::Tree{Char}, s::T, out::Vector{T}) where {T <: AbstractString}
    if p.isleaf
        push!(out, s)
    end
    if isempty(s) || s[1]  keys(p.branches)
        return
    end
    partial_match(p.branches[s[1]], s[2:end], out)
end

function main(io::IO)
    patterns, designs = read_input(io)
    ptree = pattern_tree(patterns)
    counts = map(match(ptree), designs)
    part1 = sum(counts .> 0)
    part2 = sum(counts)
    part1, part2
end

end