lines = readlines("input.txt")

function main(lines)
    init = "shiny gold" => 1

    part1 = let tree = Dict{String, Vector{String}}()
        for line in lines
            outer, innards = split(line, " bags contain ")
            for inner in filter(!isempty, split(innards, r" ?bags?[.,] ?"))
                bagtype = replace(inner, r"\d+ ?" => "")
                if haskey(tree, bagtype)
                    push!(tree[bagtype], outer)
                else
                    tree[bagtype] = [outer]
                end
            end
        end

        stack = String[first(init)]
        works = Set{String}()
        while !isempty(stack)
            top = pop!(stack)
            if top ∉ works
                if haskey(tree, top)
                    append!(stack, tree[top])
                end
                push!(works, top)
            end
        end
        length(works) - 1
    end

    part2 = let tree = Dict{String, Vector{Pair{String, Int}}}()
        for line in lines
            outer, innards = split(line, " bags contain ")
            for inner in filter(!isempty, split(innards, r" ?bags?[.,] ?"))
                m = match(r"(\d+)\s([\w\s]+)", inner)
                if isnothing(m)
                    tree[outer] = []
                else
                    n = parse(Int, m[1])
                    bagtype = m[2]
                    if haskey(tree, outer)
                        push!(tree[outer], bagtype => n)
                    else
                        tree[outer] = [bagtype => n]
                    end
                end
            end
        end

        stack = Pair{String, Int}[init]
        numbags = 0
        while !isempty(stack)
            bag, count = pop!(stack)
            numbags += count
            if haskey(tree, bag)
                for (b, c) in tree[bag]
                    push!(stack, b => count * c)
                end
            end
        end

        numbags - last(init)
    end

    @info "Solutions" part1 part2
end

main(lines)
