From 165159cba946591a91f1835bd0cd96c34e23b62f Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Mon, 1 Feb 2021 22:39:09 +0100 Subject: [PATCH] Implement 2019 day 15 --- 2019/aoc2019/day15.py | 102 ++++++++++++++++++++++++++++++++++++++++ 2019/aoc2019/intcode.py | 3 ++ 2 files changed, 105 insertions(+) create mode 100644 2019/aoc2019/day15.py diff --git a/2019/aoc2019/day15.py b/2019/aoc2019/day15.py new file mode 100644 index 0000000..2373d25 --- /dev/null +++ b/2019/aoc2019/day15.py @@ -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 diff --git a/2019/aoc2019/intcode.py b/2019/aoc2019/intcode.py index d00801d..d90fac9 100644 --- a/2019/aoc2019/intcode.py +++ b/2019/aoc2019/intcode.py @@ -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