Skip to content

Commit 684cc4b

Browse files
committed
feat: 2022 Day 16 Part 1
1 parent 04fe1b7 commit 684cc4b

File tree

2 files changed

+104
-0
lines changed

2 files changed

+104
-0
lines changed

2022/day/16/part/1/solve.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import solve from "./solve.ts";
2+
3+
import { assertEquals } from "@std/assert";
4+
5+
Deno.test("example", () => {
6+
const input = `\
7+
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
8+
Valve BB has flow rate=13; tunnels lead to valves CC, AA
9+
Valve CC has flow rate=2; tunnels lead to valves DD, BB
10+
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
11+
Valve EE has flow rate=3; tunnels lead to valves FF, DD
12+
Valve FF has flow rate=0; tunnels lead to valves EE, GG
13+
Valve GG has flow rate=0; tunnels lead to valves FF, HH
14+
Valve HH has flow rate=22; tunnel leads to valve GG
15+
Valve II has flow rate=0; tunnels lead to valves AA, JJ
16+
Valve JJ has flow rate=21; tunnel leads to valve II`;
17+
18+
assertEquals(solve(input), 1651);
19+
});

2022/day/16/part/1/solve.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
type ValueGraph = ReturnType<typeof parseFlowRateGraph>;
2+
type Distances = ReturnType<typeof computeDistances>;
3+
4+
const regExp =
5+
/^Valve (?<id>.+) has flow rate=(?<flowRateText>\d+); tunnels? leads? to valves? (?<destinationsText>.+?)$/gm;
6+
7+
function parseFlowRateGraph(text: string) {
8+
const flowRates = new Map<string, number>();
9+
const tunnels = new Map<string, string[]>();
10+
for (const { groups } of text.matchAll(regExp)) {
11+
const { id, flowRateText, destinationsText } = groups!;
12+
flowRates.set(id, +flowRateText);
13+
tunnels.set(id, destinationsText.split(", "));
14+
}
15+
const nodes = () => flowRates.keys();
16+
const value = (valve: string) => flowRates.get(valve);
17+
const connected = (valve: string) => tunnels.get(valve) ?? [];
18+
return { nodes, value, connected };
19+
}
20+
21+
function computeDistances(graph: ValueGraph) {
22+
const result = new Map<string, Map<string, number>>();
23+
{
24+
for (const u of graph.nodes()) {
25+
const u2 = new Map<string, number>().set(u, 0);
26+
result.set(u, u2);
27+
for (const v of graph.connected(u)) u2.set(v, 1), u2.set(v, 1);
28+
}
29+
for (const m of graph.nodes()) {
30+
for (const u of graph.nodes()) {
31+
const u2 = result.get(u)!;
32+
const u2m = u2.get(m);
33+
if (u2m === undefined) continue;
34+
for (const v of graph.nodes()) {
35+
const m2v = result.get(m)?.get(v);
36+
if (m2v === undefined) continue;
37+
const u2m2v = u2m + m2v;
38+
const u2v = u2.get(v);
39+
if (u2v !== undefined && u2v < u2m2v) continue;
40+
u2.set(v, u2m2v);
41+
}
42+
}
43+
}
44+
}
45+
return result;
46+
}
47+
48+
function findMaxPressure(
49+
graph: ValueGraph,
50+
distances: Distances,
51+
targets: Set<string>,
52+
) {
53+
let max = 0;
54+
const stack = [{
55+
valve: "AA",
56+
t: 30,
57+
opened: new Set<string>(),
58+
released: 0,
59+
}];
60+
while (stack.length) {
61+
const { valve, t, opened, released } = stack.pop()!;
62+
if (released > max) max = released;
63+
if (t === 0) continue;
64+
for (const destination of targets.difference(opened)) {
65+
const remaining = t - distances.get(valve)!.get(destination)! - 1;
66+
if (remaining < 0) continue;
67+
stack.push({
68+
valve: destination,
69+
t: remaining,
70+
opened: new Set(opened).add(destination),
71+
released: released + remaining * graph.value(destination)!,
72+
});
73+
}
74+
}
75+
return max;
76+
}
77+
78+
export default function solve(input: string) {
79+
const flowRateGraph = parseFlowRateGraph(input);
80+
const distances = computeDistances(flowRateGraph);
81+
const targets = flowRateGraph.nodes()
82+
.filter((valve) => flowRateGraph.value(valve))
83+
.reduce((set, value) => set.add(value), new Set<string>());
84+
return findMaxPressure(flowRateGraph, distances, targets);
85+
}

0 commit comments

Comments
 (0)