-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday15.py
executable file
·117 lines (87 loc) · 2.55 KB
/
day15.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env python3
# [Day 15: Oxygen System](https://adventofcode.com/2019/day/15)
import sys
from collections import deque
from pathlib import Path
sys.path.append(Path(__file__).parent.parent.as_posix())
from intcode.Intcode import Computer # noqa
filename = sys.argv[1] if len(sys.argv) > 1 else "input.txt"
software = Path(filename).read_text()
droid = Computer()
droid.load(software)
droid.start(output_mode="yield")
NORTH = 1
SOUTH = 2
WEST = 3
EAST = 4
WALL = 0
EMPTY = 1
OXYGEN = 2
MOVES = [
None,
(0, 1), # north
(0, -1), # south
(-1, 0), # west
(1, 0), # east
]
def bfs(droid, show):
positions = {}
x, y = 0, 0
positions[(x, y)] = 4 # for S
direction = EAST
q = deque()
q.append((0, 0, 0))
seen = set()
droids = {}
droids[(0, 0)] = droid.clone()
oxygen = None
max_steps = 0
# need to clone the droid state to avoid testing all directions and walk back to them
# when there is a T or X junction
while q:
x, y, steps = q.popleft()
max_steps = max(max_steps, steps)
droid = droids[(x, y)]
for direction in (NORTH, SOUTH, WEST, EAST):
dx, dy = MOVES[direction]
mx, my = x + dx, y + dy
if (mx, my) in seen:
continue
seen.add((x, y))
new_droid = droid.clone()
new_droid.input.append(direction)
state = new_droid.resume()
assert state == "yield"
status = new_droid.output.popleft()
assert 0 <= status <= 2
positions[(mx, my)] = status
if status == OXYGEN:
oxygen = (new_droid, steps + 1)
q.clear() # stop the bfs
break
if status != WALL:
droids[(mx, my)] = new_droid
q.append((mx, my, steps + 1))
droids.clear()
seen.clear()
if show:
inf = int(1e6)
minx, maxx, miny, maxy = inf, -inf, inf, -inf
for (x, y), _ in positions.items():
minx = min(minx, x)
maxx = max(maxx, x)
miny = min(miny, y)
maxy = max(maxy, y)
lines = []
for y in range(maxy, miny - 1, -1):
row = ""
for x in range(minx, maxx + 1):
status = positions.get((x, y), 3)
row += "# O?S"[status]
lines.append(row)
print("\n".join(lines))
return oxygen, max_steps
(oxygen, steps), _ = bfs(droid, False)
print(steps)
_, distance = bfs(oxygen, False)
print(distance)