from collections import deque from intcode import IntCode from tools.aoc import AOCDay from tools.coordinate import Coordinate from tools.grid import Grid from typing import Any MOVEMENTS = [Coordinate(0, -1), Coordinate(0, 1), Coordinate(-1, 0), Coordinate(1, 0)] OXYGEN_POS = None def discover(comp: IntCode, grid: Grid, pos: Coordinate, visited: set = None) -> Grid: global OXYGEN_POS if visited is None: visited = set() visited.add(pos) for m in range(4): next_pos = pos + MOVEMENTS[m] if next_pos in visited: continue comp.addInput(m + 1) outcome = comp.getOutput() if outcome == 0: grid.set(next_pos) else: if outcome == 2: OXYGEN_POS = next_pos grid = discover(comp, grid, next_pos, visited) comp.addInput(MOVEMENTS.index(MOVEMENTS[m].reverse()) + 1) comp.getOutput() # just ignore one to keep the queue clear return grid class Day(AOCDay): inputs = [ [ (354, "input15") ], [ (370, "input15") ] ] def get_grid(self) -> Grid: comp = IntCode(self.getInputAsArraySplit(",", int)) comp.start() pos = Coordinate(0, 0) grid = discover(comp, Grid(), pos) comp.stop() return grid def part1(self) -> Any: return len(self.get_grid().getPath(Coordinate(0, 0), OXYGEN_POS, includeDiagonal=False, walls=[True])) - 1 def part2(self) -> Any: grid = self.get_grid() queue = deque() queue.append(OXYGEN_POS) grid.set(OXYGEN_POS, 2) count = 0 while queue: count += 1 next_queue = deque() for pos in queue: for next_pos in grid.getNeighboursOf(pos, includeDefault=True, includeDiagonal=False): if grid.get(next_pos) is False: next_queue.append(next_pos) grid.set(next_pos, 2) queue = next_queue return count - 1 if __name__ == '__main__': day = Day(2019, 15) day.run(verbose=True)