def __init__(self, file_name): self.computer = Intcode(file_name) self._do_not_take = [ "escape pod", # "You're launched into space! Bye!" "giant electromagnet", # "The giant electromagnet is stuck to you. You can't move!!" "infinite loop", # Literally halts the program in an infinite loop "molten lava", # "The molten lava is way too hot! You melt!" "photons", # "It is suddenly completely dark! You are eaten by a Grue!" "mug", # Too heavy, by itself "prime number", # Too heavy, by itself "weather machine", # Too heavy, by itself "festive hat", # Don't take this and our weight is correct with other items ]
class Y2019D2(object): def __init__(self, file_name): self.computer = Intcode(file_name) def part1(self): self.computer.reset() self.computer.ram[1] = 12 self.computer.ram[2] = 2 self.computer.run() print("Part 1:", self.computer.ram[0]) def part2(self): result = 0 for noun in range(100): for verb in range(100): self.computer.reset() self.computer.ram[1] = noun self.computer.ram[2] = verb self.computer.run() if self.computer.ram[0] == 19690720: result = 100 * noun + verb break print("Part 2:", result)
def __init__(self, file_name): self.NICs: Dict[int, Intcode] = {} self.queues: Dict[int, Queue] = {} for i in range(50): self.NICs[i] = Intcode(file_name) self.queues[i] = Queue() self.queues[255] = Queue()
class Y2019D11(object): def __init__(self, file_name): self.robot = Intcode(file_name) self.grid = InfiniteGrid[bool]() # False -> black; True -> white def _paint(self): self.robot.reset() self.robot.run() turtle = Turtle(direction=TurtleDirection.UP) painted_tiles = set() while not self.robot.halted: if turtle.coordinate not in self.grid: tile_is_white = False else: tile_is_white = self.grid[turtle.coordinate] self.robot.input(1 if tile_is_white else 0) new_color = self.robot.output() # Paint the current tile white or black self.grid[turtle.coordinate] = True if new_color == 1 else False painted_tiles.add(turtle.coordinate) turn = self.robot.output() if turn == 0: turtle = turtle.turn_left() else: turtle = turtle.turn_right() turtle = turtle.forward() return painted_tiles def part1(self): self.grid.clear() painted_tiles = self._paint() result = len(painted_tiles) print("Part 1:", result) def part2(self): self.grid.clear() self.grid[Coordinate(0, 0)] = True self._paint() print("Part 2:") self.grid.to_grid().print(key=lambda is_white: '#' if is_white else ' ')
class Y2019D21(object): def __init__(self, file_name): self.computer = Intcode(file_name) def part1(self): result = self._run("NOT A J\n" "NOT B T\n" "OR T J\n" "NOT C T\n" "OR T J\n" "AND D J\n" "WALK\n") print("Part 1:", result) def part2(self): result = self._run("NOT H T\n" "OR C T\n" "AND B T\n" "AND A T\n" "NOT T J\n" "AND D J\n" "RUN\n") print("Part 2:", result) def _run(self, *program: str): self.computer.reset() self.computer.run() self.computer.output_str() for command in program: self.computer.input_str(command) result = self.computer.output_str() if "Didn't make it across" in result: print(result) return -1 else: return self.computer.output()
def __init__(self, file_name): self.drone = Intcode(file_name)
class Y2019D5(object): def __init__(self, file_name): self.computer = Intcode(file_name) def part1(self): self.computer.reset() self.computer.run() self.computer.input(1) outputs = [] while not self.computer.halted: if self.computer.has_output: output = self.computer.output() outputs.append(output) is_valid_output = len(list(filter(None, outputs))) == 1 and outputs[-1] > 0 if is_valid_output: print("Part 1:", outputs[-1]) else: print("INVALID!") for output in outputs: print(output) def part2(self): self.computer.reset() self.computer.run() self.computer.input(5) result = self.computer.output() print("Part 2:", result)
def __init__(self, file_name): self.comp_a = Intcode(file_name) self.comp_b = Intcode(file_name) self.comp_c = Intcode(file_name) self.comp_d = Intcode(file_name) self.comp_e = Intcode(file_name)
class Y2019D7(object): def __init__(self, file_name): self.comp_a = Intcode(file_name) self.comp_b = Intcode(file_name) self.comp_c = Intcode(file_name) self.comp_d = Intcode(file_name) self.comp_e = Intcode(file_name) @staticmethod def _iterator(start, end): for a in range(start, end + 1): for b in range(start, end + 1): for c in range(start, end + 1): for d in range(start, end + 1): for e in range(start, end + 1): if len({a, b, c, d, e}) == 5: yield [a, b, c, d, e] def _reset_and_start_computers(self): self.comp_a.reset() self.comp_a.run() self.comp_b.reset() self.comp_b.run() self.comp_c.reset() self.comp_c.run() self.comp_d.reset() self.comp_d.run() self.comp_e.reset() self.comp_e.run() def part1(self): result = 0 for settings in self._iterator(0, 4): self._reset_and_start_computers() self.comp_a.input(settings[0]) self.comp_b.input(settings[1]) self.comp_c.input(settings[2]) self.comp_d.input(settings[3]) self.comp_e.input(settings[4]) self.comp_a.input(0) self.comp_b.input(self.comp_a.output()) self.comp_c.input(self.comp_b.output()) self.comp_d.input(self.comp_c.output()) self.comp_e.input(self.comp_d.output()) result = max(result, self.comp_e.output()) print("Part 1:", result) def part2(self): result = 0 for settings in self._iterator(5, 9): self._reset_and_start_computers() self.comp_a.input(settings[0]) self.comp_b.input(settings[1]) self.comp_c.input(settings[2]) self.comp_d.input(settings[3]) self.comp_e.input(settings[4]) self.comp_a.input(0) while not self.comp_a.halted: self.comp_b.input(self.comp_a.output()) self.comp_c.input(self.comp_b.output()) self.comp_d.input(self.comp_c.output()) self.comp_e.input(self.comp_d.output()) if not self.comp_a.halted: self.comp_a.input(self.comp_e.output()) result = max(result, self.comp_e.output()) print("Part 2:", result)
def __init__(self, file_name): self.arcade = Intcode(file_name) self.grid: InfiniteGrid[Tile] = InfiniteGrid[Tile]() self.score = 0
class Y2019D13(object): def __init__(self, file_name): self.arcade = Intcode(file_name) self.grid: InfiniteGrid[Tile] = InfiniteGrid[Tile]() self.score = 0 def reset(self): self.score = 0 self.grid.clear() self.arcade.reset() def _get_game_update(self): while self.arcade.has_output: x = self.arcade.output() y = self.arcade.output() tile_id = self.arcade.output() if x == -1 and y == 0: self.score = tile_id else: self.grid[x, y] = Tile.from_id(tile_id) # self.grid.to_grid().print(key=lambda x: x.character) def part1(self): self.reset() self.arcade.run() self._get_game_update() result = len(self.grid.find(Tile.BLOCK)) print("Part 1:", result) def part2(self): self.reset() self.arcade.ram[0] = 2 self.arcade.run() self._get_game_update() while not self.arcade.halted: ball = self.grid.find(Tile.BALL)[0] paddle = self.grid.find(Tile.PADDLE)[0] # Move the paddle if needed if ball.x > paddle.x: self.arcade.input(1) elif ball.x < paddle.x: self.arcade.input(-1) else: self.arcade.input(0) self._get_game_update() print("Part 2:", self.score)
def __init__(self, file_name): self.droid = Intcode(file_name) self.grid = InfiniteGrid[Tile]()
def __init__(self, file_name): self.computer = Intcode(file_name)
class Y2019D19(object): def __init__(self, file_name): self.drone = Intcode(file_name) def _is_beam(self, x: int, y: int): if x < 0 or y < 0: return False self.drone.reset() self.drone.run() self.drone.input(x) self.drone.input(y) return self.drone.output() == 1 def part1(self): result = 0 for x in range(50): for y in range(50): if self._is_beam(x, y): result += 1 print("Part 1:", result) def part2(self): square_side = 100 end_cache = {} def valid_y(y): # Bit of a hack, but the beam isn't continuous if y < 10: return False if y in end_cache: end_x = end_cache[y] else: start_search = BinarySearch(lambda x: self._is_beam(x, y)) start_x = start_search.earliest(0, lambda x: x + 1) end_x = start_search.latest(start_x, lambda x: x * 2) end_cache[y] = end_x test_x = end_x - square_side + 1 test_y = y + square_side - 1 beam = self._is_beam(test_x, test_y) return beam search = BinarySearch(valid_y) found_y = search.earliest(1, lambda x: x * 2) found_x = end_cache[found_y] - square_side + 1 result = found_x * 10000 + found_y print("Part 2:", result) def _find_beam_right(self, start_x: int, y: int, max_search_x=10000): seen_beam = False for x in range(start_x, max_search_x): is_beam = self._is_beam(x, y) if not is_beam and seen_beam: return x - 1 if is_beam: seen_beam = True return None
class Y2019D9(object): def __init__(self, file_name): self.computer = Intcode(file_name) def part1(self): self.computer.reset() self.computer.run() self.computer.input(1) outputs = [] while not self.computer.halted: outputs.append(self.computer.output()) if len(outputs) == 1: print("Part 1:", outputs[-1]) else: print("Something went wrong, invalid output:") for output in outputs: print(output) def part2(self): self.computer.reset() self.computer.run() self.computer.input(2) print("Part 2:", self.computer.output())
def __init__(self, file_name): self.robot = Intcode(file_name) self.grid = InfiniteGrid[bool]() # False -> black; True -> white
class Y2019D17(object): def __init__(self, file_name): self.computer = Intcode(file_name) def part1(self): self.computer.reset() self.computer.run() map_string = self.computer.output_str() grid = Grid.from_str(map_string) result = 0 scaffolding = grid.find('#') for scaffold in scaffolding: intersecting = all(grid[neighbor] == '#' for neighbor in scaffold.neighbors()) if intersecting: result += scaffold.x * scaffold.y print("Part 1:", result) def part2(self): self.computer.reset() self.computer.ram[0] = 2 self.computer.run() self.computer.output_str() self.computer.input_str("B,C,B,C,A,B,C,A,B,A\n") self.computer.output_str() self.computer.input_str("R,6,L,8,L,10,R,6\n") self.computer.output_str() self.computer.input_str("R,6,L,6,L,10\n") self.computer.output_str() self.computer.input_str("L,8,L,6,L,10,L,6\n") self.computer.output_str() self.computer.input_str("n\n") map_string = self.computer.output_str() grid = Grid.from_str(map_string) result = self.computer.output() print("Part 2:", result)
class Y2019D15(object): def __init__(self, file_name): self.droid = Intcode(file_name) self.grid = InfiniteGrid[Tile]() def _map_out_grid(self): self.grid.clear() self.droid.reset() all_directions = [ TurtleDirection.NORTH, TurtleDirection.SOUTH, TurtleDirection.EAST, TurtleDirection.WEST ] droid_coordinate = Coordinate(0, 0) self.grid[droid_coordinate] = Tile.EMPTY backtrack = [] need_to_check = {droid_coordinate: all_directions.copy()} self.droid.run() while backtrack or need_to_check: test_directions = need_to_check[droid_coordinate] # Nowhere to move, try to go back if not test_directions: del need_to_check[droid_coordinate] if backtrack: back = backtrack.pop() self.droid.input(self._get_move_input(back)) self.droid.output( ) # Read an output, although we know we can move back droid_coordinate = back.move(droid_coordinate) continue direction = test_directions.pop() if backtrack and direction == backtrack[-1]: continue # Don't go back, use backtrack stack for that self.droid.input(self._get_move_input(direction)) output = self.droid.output() next_coordinate = direction.move(droid_coordinate) self.grid[next_coordinate] = Tile.from_id(output) if output != 0: droid_coordinate = next_coordinate backtrack.append(direction.opposite()) need_to_check[droid_coordinate] = all_directions.copy() def _get_move_input(self, direction: TurtleDirection): if direction == TurtleDirection.NORTH: return 1 elif direction == TurtleDirection.SOUTH: return 2 elif direction == TurtleDirection.WEST: return 3 elif direction == TurtleDirection.EAST: return 4 def part1(self): self._map_out_grid() start = Coordinate(0, 0) oxygen = self.grid.find(Tile.OXYGEN)[0] graph = self.grid.to_graph(Tile.EMPTY, Tile.OXYGEN) # -1 is because path includes start and they want "steps to oxygen" result = len(graph.find_path(start, oxygen, CoordinateHeuristic())) - 1 print("Part 1:", result) def part2(self): self._map_out_grid() empty_tiles = self.grid.find(Tile.EMPTY) minutes = 0 while empty_tiles: oxygen = self.grid.find(Tile.OXYGEN) for oxygen_space in oxygen: for neighbor in oxygen_space.neighbors(): if self.grid[neighbor] == Tile.EMPTY: self.grid[neighbor] = Tile.OXYGEN minutes += 1 empty_tiles = self.grid.find(Tile.EMPTY) print("Part 2:", minutes)
class Y2019D25(object): def __init__(self, file_name): self.computer = Intcode(file_name) self._do_not_take = [ "escape pod", # "You're launched into space! Bye!" "giant electromagnet", # "The giant electromagnet is stuck to you. You can't move!!" "infinite loop", # Literally halts the program in an infinite loop "molten lava", # "The molten lava is way too hot! You melt!" "photons", # "It is suddenly completely dark! You are eaten by a Grue!" "mug", # Too heavy, by itself "prime number", # Too heavy, by itself "weather machine", # Too heavy, by itself "festive hat", # Don't take this and our weight is correct with other items ] def part1(self): self.computer.reset() self.computer.run() back_moves: List[str] = [] path_from_security: Optional[List[str]] = None seen: Set[Tuple[str, str]] = set() taken: Set[str] = set() while True: output = self.computer.output_str() # print(output) location = DungeonLocation.read(output) if location.name == "Security Checkpoint": path_from_security = back_moves.copy() previous_move = back_moves.pop() # print(f"Going back {previous_move}") self.computer.input_str(f"{previous_move}\n") continue for item in location.items: if item not in self._do_not_take: taken.add(item) input_str = f"take {item}\n" # print(input_str) self.computer.input_str(input_str) response = self.computer.output_str() # print(response) moved_through_a_door = False opposite_direction = None for direction in location.doors_here_lead: back_direction = back_moves[-1] if len( back_moves) > 0 else None if back_direction == direction: continue movement = (location.name, direction) if movement in seen: continue if direction == "north": opposite_direction = "south" elif direction == "south": opposite_direction = "north" elif direction == "east": opposite_direction = "west" elif direction == "west": opposite_direction = "east" seen.add(movement) back_moves.append(opposite_direction) moved_through_a_door = True # print(f"Going {direction}") self.computer.input_str(f"{direction}\n") break if not moved_through_a_door: if len(back_moves) > 0: previous_move = back_moves.pop() # print(f"Going back {previous_move}") self.computer.input_str(f"{previous_move}\n") else: break for movement in path_from_security: if movement == "north": movement = "south" elif movement == "south": movement = "north" elif movement == "east": movement = "west" elif movement == "west": movement = "east" self.computer.input_str(f"{movement}\n") self.computer.output_str() self.computer.input_str("east\n") output = self.computer.output_str() result = re.search(r"(\d+)", output).group(1) print("Part 1:", result) def part2(self): pass