diff --git a/day15.py b/day15.py new file mode 100644 index 0000000..53c7aee --- /dev/null +++ b/day15.py @@ -0,0 +1,129 @@ +from intcode import Interpreter, WaitForInput + +NORTH = 1 +SOUTH = 2 +WEST = 3 +EAST = 4 + +DIRS = [NORTH, SOUTH, EAST, WEST] + +OPPOSITE = {NORTH : SOUTH, + SOUTH : NORTH, + EAST : WEST, + WEST : EAST + } + +WALL = 0 +EMPTY = 1 +OXY = 2 + +ENCODING = {WALL : '#', + EMPTY : '.', + OXY : 'O' + } + +def move(pos, dir): + if dir == NORTH: + return pos[0], pos[1] + 1 + if dir == SOUTH: + return pos[0], pos[1] - 1 + if dir == EAST: + return pos[0] + 1, pos[1] + if dir == WEST: + return pos[0] - 1, pos[1] + return NotImplemented + +class DroidIO: + def __init__(self): + self._input = None + self._output = None + + def pop_input(self): + i = self._input + if i == None: + raise WaitForInput + self._input = None + return i + + def append_output(self, x): + self._output = x + + def flush(self): + o = self._output + self._output = None + return o + + def write(self, x): + self._input = x + +class Droid(Interpreter): + def __init__(self, program): + super().__init__(program, DroidIO) + self.pos = 0, 0 + + def move(self, dir): + out = self.eval(dir) + if out != WALL: + self.pos = move(self.pos, dir) + return out + + +class Map(dict): + def __init__(self, encoding): + super().__init__() + self.encoding = encoding + + def __str__(self): + xs, ys = tuple(zip(*self.keys())) + r = str() + for y in range(min(ys), max(ys)+1): + for x in range(min(xs), max(xs)+1): + if x == y == 0: + r += 'X' + elif (x, y) not in self: + r += ' ' + else: + r += self.encoding[self[(x, y)]] + r += '\n' + return r + +def map_space(droid, map=None): + if map == None: + map = Map(ENCODING) + for dir in DIRS: + new_pos = move(droid.pos, dir) + if new_pos in map: + continue + object = droid.move(dir) + map[new_pos] = object + if object == WALL: + continue + map_space(droid, map) + droid.move(OPPOSITE[dir]) + return map + +def shortest_paths(map, pos, visited=None): + if visited == None: + visited = {pos : 0} + path = visited[pos] + 1 + for dir in DIRS: + new = move(pos, dir) + if map[new] == WALL or (new in visited and visited[new] <= path): + continue + visited[new] = path + shortest_paths(map, new, visited) + return visited + +def preproc(puzzle_input): + program = list(map(int, puzzle_input.split(','))) + droid = Droid(program) + area_map = map_space(droid) + x, y = tuple(filter(lambda x: x[1]==OXY, area_map.items()))[0][0] + path_map = shortest_paths(area_map, (x, y)) + return path_map + +def partI(path_map): + return path_map[(0, 0)] + +def partII(path_map): + return max(path_map.values())