Skip to content

Commit 73eebca

Browse files
committed
Add 2022/16 py
1 parent afc0ab7 commit 73eebca

File tree

8 files changed

+214
-0
lines changed

8 files changed

+214
-0
lines changed

2022/16/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Advent of Code - 2022 Day 16
2+
Here are my solutions to this puzzle.
3+
4+
* Problem instructions: [adventofcode.com/2022/day/16](https://adventofcode.com/2022/day/16)
5+
* Input: [adventofcode.com/2022/day/16/input](https://adventofcode.com/2022/day/16/input)
6+
7+
Fetch input by exporting `$AOC_SESSION` in your shell and then:
8+
```bash
9+
curl -OJLsb session=$AOC_SESSION adventofcode.com/2022/day/16/input
10+
```
11+
12+
or run `fetch_input.sh` in this directory.

2022/16/fetch_input.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env sh
2+
# Make sure $AOC_SESSION is exported before running this script.
3+
4+
curl --remote-name --remote-header-name --silent --fail -A 'https://erikw.me/contact' --cookie "session=$AOC_SESSION" "https://adventofcode.com/2022/day/16/input"
5+
test "$?" -eq 0 && echo "Fetched input" && exit 0 || echo "Failed to fetch input" && exit 1

2022/16/input1.0

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Valve AA has flow rate=0; tunnels lead to valves DD, II, BB
2+
Valve BB has flow rate=13; tunnels lead to valves CC, AA
3+
Valve CC has flow rate=2; tunnels lead to valves DD, BB
4+
Valve DD has flow rate=20; tunnels lead to valves CC, AA, EE
5+
Valve EE has flow rate=3; tunnels lead to valves FF, DD
6+
Valve FF has flow rate=0; tunnels lead to valves EE, GG
7+
Valve GG has flow rate=0; tunnels lead to valves FF, HH
8+
Valve HH has flow rate=22; tunnel leads to valve GG
9+
Valve II has flow rate=0; tunnels lead to valves AA, JJ
10+
Valve JJ has flow rate=21; tunnel leads to valve II

2022/16/instructions.url

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[InternetShortcut]
2+
URL = https://adventofcode.com/2022/day/16

2022/16/output1.0

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1651

2022/16/output2.0

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1707

2022/16/part1.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env python3
2+
import functools
3+
import re
4+
import sys
5+
from typing import DefaultDict
6+
7+
from python_mermaid.diagram import Link, MermaidDiagram, Node
8+
9+
TOTAL_MIN = 30
10+
VALVE_START = "AA"
11+
VALVE_PATTERN = re.compile(
12+
r"Valve (?P<name>[A-Z]{2}) has flow rate=(?P<flow>\d+); tunnels? leads? to valves? (?P<neighbors>.+)"
13+
)
14+
15+
16+
def read_network():
17+
nodes = set()
18+
edges = []
19+
flow = {}
20+
for node, flow_str, neighbors in VALVE_PATTERN.findall(open(sys.argv[1]).read()):
21+
nodes.add(node)
22+
for neighbor in neighbors.split(", "):
23+
edges.append((node, neighbor))
24+
if flow_str != "0": # Remove as possible destination.
25+
flow[node] = int(flow_str)
26+
return nodes, edges, flow
27+
28+
29+
# Ref: https://en.wikipedia.org/wiki/Floyd–Warshall_algorithm
30+
def floyd_warshall_pairwise_shortes_paths(nodes, edges, weights):
31+
n = len(nodes)
32+
dist = DefaultDict(lambda: float("inf"))
33+
34+
for u, v in edges:
35+
dist[u, v] = weights[u, v]
36+
37+
for n in nodes:
38+
dist[n, n] = 0
39+
40+
for k in nodes:
41+
for i in nodes:
42+
for j in nodes:
43+
alt = dist[i, k] + dist[k, j]
44+
dist[i, j] = min(dist[i, j], alt)
45+
46+
return dist
47+
48+
49+
def mermaid_diagram(vertices, edges):
50+
nodes = {v: Node(v) for v in vertices}
51+
links = [Link(nodes[u], nodes[v]) for u, v in edges]
52+
chart = MermaidDiagram(title="Network", nodes=nodes.values(), links=links)
53+
print(chart) # Paste output at https://mermaid.live/
54+
55+
56+
def main():
57+
nodes, edges, flow = read_network()
58+
59+
# mermaid_diagram(nodes, edges)
60+
61+
weights = DefaultDict(lambda: 1)
62+
dist = floyd_warshall_pairwise_shortes_paths(nodes, edges, weights)
63+
64+
# h/t https://www.reddit.com/r/adventofcode/comments/zn6k1l/comment/j0fti6c/
65+
@functools.cache
66+
def max_pressure(time, node_cur, nodes_unvisited):
67+
pressures = [0]
68+
for node_other in nodes_unvisited:
69+
node_dist = dist[node_cur, node_other]
70+
if node_dist < time:
71+
time_left = time - node_dist - 1
72+
pressure = flow[node_other] * time_left
73+
pressure += max_pressure(
74+
time_left, node_other, nodes_unvisited - {node_other}
75+
)
76+
pressures.append(pressure)
77+
78+
return max(pressures)
79+
80+
pressure = max_pressure(
81+
TOTAL_MIN, VALVE_START, frozenset(flow.keys() - {VALVE_START})
82+
)
83+
print(pressure)
84+
85+
86+
if __name__ == "__main__":
87+
main()

2022/16/part2.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/env python3
2+
import functools
3+
import re
4+
import sys
5+
from typing import DefaultDict
6+
7+
from python_mermaid.diagram import Link, MermaidDiagram, Node
8+
9+
TOTAL_MIN = 30 - 4
10+
VALVE_START = "AA"
11+
VALVE_PATTERN = re.compile(
12+
r"Valve (?P<name>[A-Z]{2}) has flow rate=(?P<flow>\d+); tunnels? leads? to valves? (?P<neighbors>.+)"
13+
)
14+
15+
16+
def read_network():
17+
nodes = set()
18+
edges = []
19+
flow = {}
20+
for node, flow_str, neighbors in VALVE_PATTERN.findall(open(sys.argv[1]).read()):
21+
nodes.add(node)
22+
for neighbor in neighbors.split(", "):
23+
edges.append((node, neighbor))
24+
if flow_str != "0": # Remove as possible destination.
25+
flow[node] = int(flow_str)
26+
return nodes, edges, flow
27+
28+
29+
# Ref: https://en.wikipedia.org/wiki/Floyd–Warshall_algorithm
30+
def floyd_warshall_pairwise_shortes_paths(nodes, edges, weights):
31+
n = len(nodes)
32+
dist = DefaultDict(lambda: float("inf"))
33+
34+
for u, v in edges:
35+
dist[u, v] = weights[u, v]
36+
37+
for n in nodes:
38+
dist[n, n] = 0
39+
40+
for k in nodes:
41+
for i in nodes:
42+
for j in nodes:
43+
alt = dist[i, k] + dist[k, j]
44+
dist[i, j] = min(dist[i, j], alt)
45+
46+
return dist
47+
48+
49+
def mermaid_diagram(vertices, edges):
50+
nodes = {v: Node(v) for v in vertices}
51+
links = [Link(nodes[u], nodes[v]) for u, v in edges]
52+
chart = MermaidDiagram(title="Network", nodes=nodes.values(), links=links)
53+
print(chart) # Paste output at https://mermaid.live/
54+
55+
56+
def main():
57+
nodes, edges, flow = read_network()
58+
59+
# mermaid_diagram(nodes, edges)
60+
61+
weights = DefaultDict(lambda: 1)
62+
dist = floyd_warshall_pairwise_shortes_paths(nodes, edges, weights)
63+
64+
# Same as before, but try releasing an elephant at each stage to see if how it performs.
65+
@functools.cache
66+
def max_pressure(time, node_cur, nodes_unvisited, release_elephant=False):
67+
pressures = [
68+
(
69+
max_pressure(TOTAL_MIN, VALVE_START, nodes_unvisited)
70+
if release_elephant
71+
else 0
72+
)
73+
]
74+
for node_other in nodes_unvisited:
75+
node_dist = dist[node_cur, node_other]
76+
if node_dist < time:
77+
time_left = time - node_dist - 1
78+
pressure = flow[node_other] * time_left
79+
pressure += max_pressure(
80+
time_left,
81+
node_other,
82+
nodes_unvisited - {node_other},
83+
release_elephant,
84+
)
85+
pressures.append(pressure)
86+
87+
return max(pressures)
88+
89+
pressure = max_pressure(
90+
TOTAL_MIN, VALVE_START, frozenset(flow.keys() - {VALVE_START}), True
91+
)
92+
print(pressure)
93+
94+
95+
if __name__ == "__main__":
96+
main()

0 commit comments

Comments
 (0)