Mercurial > lbo > hg > aoc22
changeset 29:3c7df4d9b8cb
Start on day 16 - but likely wrong ansatz
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sat, 17 Dec 2022 20:50:31 +0100 |
parents | 72bbee9f4d9e |
children | bf87eee356fc |
files | 16/16.jl 16/test_input.txt |
diffstat | 2 files changed, 128 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/16/16.jl Sat Dec 17 20:50:31 2022 +0100 @@ -0,0 +1,118 @@ + +using ParserCombinator + +const PValveList = (E"s " + Repeat(p"[A-Z]{2}" + Repeat(E", ", 0, 1)) + Eos()) | (E" " + p"[A-Z]{2}" + Eos()); +const PValveSpec = E"Valve " + p"[A-Z]{2}" + E" has flow rate=" + PInt64() + P"; tunnels? leads? to valve" + PValveList; + +struct ValveSpec + name::String + flowrate::Int + tunnels::Vector{String} +end + +function parse_valve_line(s::String)::ValveSpec + vs = parse_one(s, PValveSpec); + ValveSpec(String(vs[1]), vs[2]::Int, [String(s) for s in vs[3:end]]) +end + +struct Peer + valve::ValveSpec + dist::Int +end + +struct Node + valve::ValveSpec + routes::Dict{String, Peer} +end + +function build_graph(lines::IOStream)::Dict{String,Node} + l = [Node(parse_valve_line(s), Dict()) for s in eachline(lines)]; + Dict(n.valve.name => n for n in l) +end + +function update_connections(neigh::Node, dist::Int, mine::Dict{String, Peer})::Int + count = 0; + for (s, p) = mine + if s == neigh.valve.name + continue + end + if !(s in keys(neigh.routes)) || neigh.routes[s].dist > p.dist+dist + pp = Peer(p.valve, p.dist+dist); + neigh.routes[s] = pp; + count += 1; + end + end + count +end + +function populate_graph(g::Dict{String,Node}) + for (id, valve) in g + for neigh in valve.valve.tunnels + # Insert neighbors with distance = 1. + valve.routes[neigh] = Peer(g[neigh].valve, 1); + end + end + #print_graph(g); + + count = 1; + # While information propagates through the graph, keep updating. + while count > 0 + count = 0; + for (id, node) = g + for (id2, node2) = node.routes + if id == id2 + continue + end + count += update_connections(g[id2], node2.dist, node.routes); + end + end + @show count + end + print_graph(g); +end + +# Sort key +function expected_total_flow(time::Int, peer::Peer)::Int + (30 - time - peer.dist - 1) * peer.valve.flowrate +end + +function find_best_next(g::Dict{String,Node}, current::String, time::Int, opened::Set{String})::Tuple{String,Int,Int} + cands = [(s, p.dist, expected_total_flow(time, p)) for (s, p) = g[current].routes]; + sort!(cands; lt=(a, b) -> a[3] < b[3], rev=true); + @show cands + for (s, dist, tf) = cands + if !in(s, opened) + return (s, dist, tf); + end + end +end + +function find_order(g::Dict{String,Node}, start::String) + opened = Set{String}(); + time = 0; + while time < 30 + best, dist, tf = find_best_next(g, start, time, opened); + println("found best: $best at $dist with tf = $tf"); + push!(opened, best); + time += dist + 1; + println("time now: $time"); + start = best; + end +end + +function print_graph(g::Dict{String,Node}) + for (id, n) = g + println("=== $id === "); + println(" flowrate: $(n.valve.flowrate)"); + println(" neighbors:"); + for (id2, neigh) = n.routes + println(" $id2 => $(neigh.dist)"); + end + end +end + +open("16/test_input.txt"; read=true) do fh + g = build_graph(fh); + populate_graph(g); + find_order(g, "AA"); +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/16/test_input.txt Sat Dec 17 20:50:31 2022 +0100 @@ -0,0 +1,10 @@ +Valve AA has flow rate=0; tunnels lead to valves DD, II, BB +Valve BB has flow rate=13; tunnels lead to valves CC, AA +Valve CC has flow rate=2; tunnels lead to valves DD, BB +Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE +Valve EE has flow rate=3; tunnels lead to valves FF, DD +Valve FF has flow rate=0; tunnels lead to valves EE, GG +Valve GG has flow rate=0; tunnels lead to valves FF, HH +Valve HH has flow rate=22; tunnel leads to valve GG +Valve II has flow rate=0; tunnels lead to valves AA, JJ +Valve JJ has flow rate=21; tunnel leads to valve II