Implement 2019 day 15

This commit is contained in:
2021-02-01 22:39:09 +01:00
parent eff22abf8a
commit 165159cba9
2 changed files with 105 additions and 0 deletions

102
2019/aoc2019/day15.py Normal file
View File

@@ -0,0 +1,102 @@
import sys
from collections import defaultdict
from typing import TextIO
import networkx # type: ignore
from aoc2019.intcode import Computer, read_program
def step(computer: Computer, direction: int) -> int:
computer.input.append(direction)
try:
computer.run()
except IndexError:
return computer.get_output()
sys.exit("computer terminated unexpectedly")
def inverse(direction: int):
if direction % 2 == 1:
return direction + 1
else:
return direction - 1
def read_graph(data: TextIO) -> networkx.Graph:
computer = Computer(read_program(data))
pos = (0, 0)
tiles = defaultdict(int)
tiles[0, 0] = 1
prev = [((0, 0), 1)]
while prev:
x, y = pos
if (x, y + 1) not in tiles:
movement = 1
next_pos = (x, y + 1)
elif (x, y - 1) not in tiles:
movement = 2
next_pos = (x, y - 1)
elif (x - 1, y) not in tiles:
movement = 3
next_pos = (x - 1, y)
elif (x + 1, y) not in tiles:
movement = 4
next_pos = (x + 1, y)
else:
# No movement available, backtrack
prev_pos, prev_dir = prev.pop()
step(computer, inverse(prev_dir))
pos = prev_pos
continue
result = step(computer, movement)
tiles[next_pos] = result
if result != 0:
# Movement was successful
prev.append((pos, movement))
pos = next_pos
graph = networkx.Graph()
for pos, value in tiles.items():
if value == 0:
continue
if value == 2:
# Create an imaginary edge to the oxygen
graph.add_edge('O', pos, weight=0)
x, y = pos
neighbours = [
(x - 1, y),
(x + 1, y),
(x, y - 1),
(x, y + 1),
]
for neighbour in neighbours:
if tiles[neighbour] != 0:
graph.add_edge(pos, neighbour)
return graph
def part1(data: TextIO) -> int:
graph = read_graph(data)
return networkx.shortest_path_length(graph, (0, 0), 'O') - 1
def part2(data: TextIO) -> int:
graph = read_graph(data)
return networkx.eccentricity(graph, 'O') - 1

View File

@@ -73,6 +73,9 @@ class Computer:
while self._execute_current():
pass
def get_output(self) -> int:
return self.output.popleft()
def _execute_current(self) -> bool:
"""
Execute a single instruction