Skip to content

Commit 4fb79ff

Browse files
committed
Solve 2022/16
1 parent 35c3d50 commit 4fb79ff

3 files changed

Lines changed: 182 additions & 0 deletions

File tree

lib/2022/day_16.ex

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
defmodule AdventOfCode.Y2022.Day16 do
2+
@moduledoc """
3+
--- Day 16: Proboscidea Volcanium ---
4+
Problem Link: https://adventofcode.com/2022/day/16
5+
Difficulty: hard
6+
Tags: graph floyd-warshall johnsons-algorithm dfs optimization
7+
"""
8+
import Bitwise
9+
alias AdventOfCode.Helpers.{InputReader, Transformers}
10+
alias Yog.Pathfinding.FloydWarshall
11+
12+
def input, do: InputReader.read_from_file(2022, 16)
13+
14+
def run(input \\ input()) do
15+
valves = parse(input)
16+
dist_map = build_dist_map(valves)
17+
18+
parts_map = explore(valves, dist_map, 30)
19+
p1 = parts_map |> Map.values() |> Enum.max()
20+
21+
p2_map = explore(valves, dist_map, 26)
22+
23+
p2 =
24+
for {m1, f1} <- p2_map, {m2, f2} <- p2_map, band(m1, m2) == 0, reduce: 0 do
25+
acc -> max(acc, f1 + f2)
26+
end
27+
28+
{p1, p2}
29+
end
30+
31+
defp explore(valves, dist_map, time) do
32+
# Only care about valves with flow > 0
33+
relevant =
34+
valves |> Enum.filter(fn {_, f, _} -> f > 0 end) |> Enum.map(fn {id, f, _} -> {id, f} end)
35+
36+
indices = relevant |> Enum.with_index() |> Map.new(fn {{id, _}, i} -> {id, i} end)
37+
38+
memo = dfs("AA", time, 0, 0, relevant, dist_map, indices, %{})
39+
memo
40+
end
41+
42+
defp dfs(curr, time, mask, flow, relevant, dist_map, indices, acc) do
43+
acc = Map.update(acc, mask, flow, &max(&1, flow))
44+
45+
Enum.reduce(relevant, acc, fn {next, f}, acc ->
46+
idx = indices[next]
47+
dist = dist_map[{curr, next}]
48+
rem_time = time - dist - 1
49+
50+
if band(mask, bsl(1, idx)) == 0 and rem_time > 0 do
51+
dfs(
52+
next,
53+
rem_time,
54+
bor(mask, bsl(1, idx)),
55+
flow + rem_time * f,
56+
relevant,
57+
dist_map,
58+
indices,
59+
acc
60+
)
61+
else
62+
acc
63+
end
64+
end)
65+
end
66+
67+
defp build_dist_map(valves) do
68+
graph = Yog.directed()
69+
70+
graph =
71+
Enum.reduce(valves, graph, fn {id, _, neighbors}, g ->
72+
Enum.reduce(neighbors, g, fn n, g_acc ->
73+
Yog.add_edge_ensure(g_acc, id, n, 1)
74+
end)
75+
end)
76+
77+
# Use Floyd-Warshall to get all-pairs shortest paths
78+
{:ok, res} = FloydWarshall.floyd_warshall(graph)
79+
80+
# relevant = AA + all with flow > 0
81+
ids = [
82+
"AA" | valves |> Enum.filter(fn {_, f, _} -> f > 0 end) |> Enum.map(fn {id, _, _} -> id end)
83+
]
84+
85+
for u <- ids, v <- ids, into: %{} do
86+
case Map.fetch(res, {u, v}) do
87+
{:ok, d} -> {{u, v}, d}
88+
# unreachable
89+
:error -> {{u, v}, 1000}
90+
end
91+
end
92+
end
93+
94+
def parse(data \\ input()) do
95+
data
96+
|> Transformers.lines()
97+
|> Enum.map(fn line ->
98+
[_, id, flow, tunnels] =
99+
Regex.run(~r/Valve ([A-Z]{2}) has flow rate=(\d+); tunnels? leads? to valves? (.*)/, line)
100+
101+
{id, String.to_integer(flow), String.split(tunnels, ", ")}
102+
end)
103+
end
104+
end

priv/input_files/2022_16.txt

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
Valve DB has flow rate=0; tunnels lead to valves AC, UN
2+
Valve LC has flow rate=6; tunnels lead to valves UV, CM, RD, IM, YQ
3+
Valve SU has flow rate=0; tunnels lead to valves OH, BX
4+
Valve JS has flow rate=0; tunnels lead to valves GR, RW
5+
Valve BX has flow rate=18; tunnels lead to valves PA, SU
6+
Valve WI has flow rate=0; tunnels lead to valves GR, JI
7+
Valve YQ has flow rate=0; tunnels lead to valves LC, SB
8+
Valve HX has flow rate=10; tunnels lead to valves VR, GZ, ID
9+
Valve RI has flow rate=0; tunnels lead to valves HF, UV
10+
Valve JQ has flow rate=0; tunnels lead to valves AA, IF
11+
Valve RK has flow rate=0; tunnels lead to valves AA, CM
12+
Valve AC has flow rate=0; tunnels lead to valves DB, HF
13+
Valve JI has flow rate=12; tunnels lead to valves WI, YH, ND, ID
14+
Valve DF has flow rate=0; tunnels lead to valves JW, AA
15+
Valve PA has flow rate=0; tunnels lead to valves BX, RB
16+
Valve OU has flow rate=0; tunnels lead to valves OH, XM
17+
Valve YO has flow rate=0; tunnels lead to valves OK, HF
18+
Valve YY has flow rate=0; tunnels lead to valves UN, MC
19+
Valve OJ has flow rate=0; tunnels lead to valves SC, GR
20+
Valve VR has flow rate=0; tunnels lead to valves IR, HX
21+
Valve EY has flow rate=0; tunnels lead to valves HR, OK
22+
Valve LE has flow rate=0; tunnels lead to valves GV, GZ
23+
Valve HF has flow rate=14; tunnels lead to valves DS, YO, AC, RI, WP
24+
Valve OM has flow rate=0; tunnels lead to valves DS, GV
25+
Valve JW has flow rate=0; tunnels lead to valves UN, DF
26+
Valve OK has flow rate=9; tunnels lead to valves IF, EY, OV, YO, WM
27+
Valve RB has flow rate=0; tunnels lead to valves PA, XM
28+
Valve HR has flow rate=0; tunnels lead to valves EY, CQ
29+
Valve YM has flow rate=0; tunnels lead to valves GB, NB
30+
Valve UN has flow rate=5; tunnels lead to valves RD, DB, JW, YY, WC
31+
Valve SO has flow rate=0; tunnels lead to valves AA, RH
32+
Valve RW has flow rate=0; tunnels lead to valves JS, GV
33+
Valve IF has flow rate=0; tunnels lead to valves OK, JQ
34+
Valve WP has flow rate=0; tunnels lead to valves HF, CQ
35+
Valve YK has flow rate=0; tunnels lead to valves MO, GV
36+
Valve MQ has flow rate=0; tunnels lead to valves AA, HI
37+
Valve RH has flow rate=0; tunnels lead to valves SO, GB
38+
Valve GB has flow rate=7; tunnels lead to valves YM, RH, PU
39+
Valve XM has flow rate=16; tunnels lead to valves OU, ND, NB, RB
40+
Valve RD has flow rate=0; tunnels lead to valves UN, LC
41+
Valve HI has flow rate=0; tunnels lead to valves MQ, GR
42+
Valve OH has flow rate=19; tunnels lead to valves OU, SU
43+
Valve DS has flow rate=0; tunnels lead to valves OM, HF
44+
Valve GV has flow rate=24; tunnels lead to valves RW, MC, YK, OM, LE
45+
Valve AA has flow rate=0; tunnels lead to valves SO, DF, RK, MQ, JQ
46+
Valve CQ has flow rate=17; tunnels lead to valves SB, MO, WP, SC, HR
47+
Valve UV has flow rate=0; tunnels lead to valves LC, RI
48+
Valve OV has flow rate=0; tunnels lead to valves OK, WC
49+
Valve CM has flow rate=0; tunnels lead to valves RK, LC
50+
Valve YH has flow rate=0; tunnels lead to valves NW, JI
51+
Valve GZ has flow rate=0; tunnels lead to valves LE, HX
52+
Valve WC has flow rate=0; tunnels lead to valves UN, OV
53+
Valve ID has flow rate=0; tunnels lead to valves JI, HX
54+
Valve SC has flow rate=0; tunnels lead to valves OJ, CQ
55+
Valve GR has flow rate=11; tunnels lead to valves OJ, WI, HI, PU, JS
56+
Valve IM has flow rate=0; tunnels lead to valves LC, WM
57+
Valve NB has flow rate=0; tunnels lead to valves YM, XM
58+
Valve TS has flow rate=20; tunnel leads to valve NW
59+
Valve SB has flow rate=0; tunnels lead to valves CQ, YQ
60+
Valve MC has flow rate=0; tunnels lead to valves GV, YY
61+
Valve ND has flow rate=0; tunnels lead to valves JI, XM
62+
Valve MO has flow rate=0; tunnels lead to valves CQ, YK
63+
Valve PU has flow rate=0; tunnels lead to valves GB, GR
64+
Valve IR has flow rate=13; tunnel leads to valve VR
65+
Valve NW has flow rate=0; tunnels lead to valves YH, TS
66+
Valve WM has flow rate=0; tunnels lead to valves IM, OK

test/2022/day_16_test.exs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
defmodule AdventOfCode.Y2022.Day16Test do
2+
@moduledoc false
3+
4+
use ExUnit.Case, async: true
5+
@moduletag :y2216
6+
7+
alias AdventOfCode.Y2022.Day16, as: Solution
8+
9+
test "Year 2022, Day 16 run/1" do
10+
assert Solution.run() == {1673, 2343}
11+
end
12+
end

0 commit comments

Comments
 (0)