def main(): program = load_input("d17.txt") grid = Grid.build(program) junctions = grid.get_junctions() p1 = sum(j[0] * j[1] for j in junctions) print(f"Part 1: {p1}") routine, functions = grid.get_dust_routine() def encode(data): x = [ord(c) for c in list(data)] + [10] if len(x) > 20: raise ValueError(data) return x def encode_fn(data): fn = [] elements = data.split(",") for e in elements: fn.append(e[0]) fn.append(str(e[1:])) return encode(",".join(fn)) cpu = IntCodeCPU(program) cpu.poke(0, 2) cpu.run(encode(routine)) for f in functions: cpu.run(encode_fn(f[1])) cpu.run(encode("n")) print(f"Part 2: {cpu.pop_output()[-1]}")
def test_unsupported_intcode(self): program = [42] cpu = IntCodeCPU(program) with self.assertRaises(ValueError) as exc_ctx: cpu.run() self.assertEqual("Unsupported instr: 42", str(exc_ctx.exception))
def test_read_no_input(self): program = [3, 3, 99, 0] cpu = IntCodeCPU(program) res = cpu.run() self.assertEqual(InterruptCode.WAITING_ON_INPUT, res) self.assertEqual(0, cpu._ip)
def test_ld_invalid_mode(self): program = [] cpu = IntCodeCPU(program) cpu._modes = [42] with self.assertRaises(ValueError) as exc_ctx: cpu._ld(0) self.assertEqual("Unsupported mode: 42", str(exc_ctx.exception))
def test_get_operation(self): params = ( (1, (1, [])), (101102, (2, [1, 1, 0, 1])), ) for op, expected in params: cpu = IntCodeCPU([op]) self.assertEqual(expected, cpu._get_instruction())
def get_thruster_output(program, phase_settings): outputs = [] for ps in phase_settings: inputs = (ps, outputs[0] if outputs else 0) runner = IntCodeCPU(program, ps) runner.run(inputs) outputs = runner.pop_output() return outputs[0]
def test_relative_mode_addressing(self): program = [ int(i) for i in "109,1,204,-1,1001,100,1,100,1008,100,16,101,1006,101,0,99".split( ",") ] cpu = IntCodeCPU(program[:]) cpu.run() self.assertEqual(program, cpu.pop_output())
def get_program_output(program, n=None, v=None): program = [int(i) for i in program.split(",")] if n is not None: program[1] = n if v is not None: program[2] = v icr = IntCodeCPU(program) icr.run() return icr.peek(0)
def get_blocks_after_first_run(program): cpu = IntCodeCPU(program) cpu.run() output = cpu.pop_output() c = 0 for i in range(2, len(output), 3): if output[i] == 2: c += 1 return c
def play(program, coins=2, render=False): if render: print("\033[2J") cpu = IntCodeCPU(program) cpu.poke(0, coins) interrupt = cpu.run() if interrupt != InterruptCode.WAITING_ON_INPUT: raise ValueError(f"Unexpected program state: Interrupt = {interrupt}") gs = GameState.init(cpu.pop_output()) while True: delta = gs.ball_x - gs.paddle_x if delta > 0: in_ = (1, ) elif delta < 0: in_ = (-1, ) else: in_ = (0, ) res = cpu.run(in_) gs.update(cpu.pop_output()) if render: gs.render() sleep(0.015) if res is None: break return gs.score
def _get_runner(n): r = runners[n] if not r: r = IntCodeCPU(program, n) runners[n] = r return r
def build(cls, program): cpu = IntCodeCPU(program) res = cpu.run() if res is not None: raise ValueError(f"CPU raised an interrupt: {res}") grid = "".join([chr(i) for i in cpu.pop_output()]) grid = [list(r) for r in grid.split("\n") if r] direction_chars = {d.value for d in Direction} for x, y in itertools.product(range(len(grid[0])), range(len(grid))): if grid[y][x] in direction_chars: pos = (x, y) dir_ = Direction(grid[y][x]) grid[y][x] = "#" break else: raise ValueError("Vacuum not found") return cls(grid, pos, dir_)
def run_robot(program, initial_coords, initial_color): panels = {initial_coords: Panel(*initial_coords, initial_color)} robot = Robot(*initial_coords) cpu = IntCodeCPU(program) while True: p = panels.get(robot.position) if not p: p = Panel(*robot.position) panels[robot.position] = p res = cpu.run((p.color.value, )) if res == InterruptCode.WAITING_ON_INPUT: c, td = cpu.pop_output() p.paint(Color(c)) robot.turn(TurnDirection(td)) robot.move_forward() else: break return panels
def generate_floor(program): robot = Robot(0, 0, Direction.UP) floor = Map(robot) cpu = IntCodeCPU(program) interrupt = cpu.run() if interrupt != InterruptCode.WAITING_ON_INPUT: raise ValueError(f"Unexpected program state: Interrupt = {interrupt}") while True: res = cpu.run((robot.direction,)) out = cpu.pop_output() if len(out) > 1: raise ValueError(f"Output too long: {out}") out = out[0] new_pos = robot.next_pos() if out == 0: floor.set_tile(new_pos.x, new_pos.y, Tile.WALL) robot.turn_left() elif out == 1: floor.set_tile(new_pos.x, new_pos.y, Tile.EMPTY) robot.set_pos(new_pos) robot.turn_right() elif out == 2: floor.set_tile(new_pos.x, new_pos.y, Tile.OXYGEN) floor.oxy_pos = Point(new_pos.x, new_pos.y) robot.set_pos(new_pos) robot.turn_right() else: raise ValueError(f"Invalid output: {out}") if res is None or robot.pos == floor.orig: break return floor
def test_big_numbers(self): program = "1102,34915192,34915192,7,4,7,99,0" cpu = IntCodeCPU(program) cpu.run() self.assertEqual([1219070632396864], cpu.pop_output())
def test_output_middle_number(self): program = "104,1125899906842624,99" cpu = IntCodeCPU(program[:]) cpu.run() self.assertEqual([1125899906842624], cpu.pop_output())
def test_add(self): program = [1, 5, 6, 7, 99, 5, 8, 0] cpu = IntCodeCPU(program) cpu.run() self.assertEqual(13, cpu.peek(7))
def test_mul(self): program = [2, 5, 6, 7, 99, 5, 8, 0] cpu = IntCodeCPU(program) cpu.run() self.assertEqual(40, cpu.peek(7))
def get_diagnostic_code(program, system_id): r = IntCodeCPU(program) r.run((system_id, )) return r.pop_output()[-1]
def test_beq_jump(self): program = [6, 5, 4, 42, 7, 0, 0, 99] cpu = IntCodeCPU(program) cpu.run() self.assertEqual(7, cpu._ip)
def get_coords(program): cpu = IntCodeCPU(program) cpu.run((2,)) output = cpu.pop_output() assert len(output) == 1 return output[0]
def test_read_with_input(self): program = [3, 3, 99, 0] cpu = IntCodeCPU(program) cpu.run((42, )) self.assertEqual(42, cpu.peek(3))
def test_eq_is_not_equal(self): program = [8, 5, 6, 7, 99, 8, 5, 42] cpu = IntCodeCPU(program) cpu.run() self.assertEqual(0, cpu.peek(7))
def test_lt_is_lower(self): program = [7, 5, 6, 7, 99, 5, 8, 42] cpu = IntCodeCPU(program) cpu.run() self.assertEqual(1, cpu.peek(7))
def test_ld_mode_0(self): program = [0, 99] cpu = IntCodeCPU(program) cpu._modes = [0] self.assertEqual(99, cpu._ld(1))
def test_ld_mode_1(self): program = [] cpu = IntCodeCPU(program) cpu._modes = [1] self.assertEqual(99, cpu._ld(99))
def get_boost_keycode(program): cpu = IntCodeCPU(program) cpu.run((1,)) output = cpu.pop_output() assert len(output) == 1 return output[0]
def test_beq_no_jump(self): program = [6, 0, 3, 99, 0, 0, 0, 0] cpu = IntCodeCPU(program) cpu.run() self.assertEqual(3, cpu._ip)
def test_write(self): program = [4, 3, 99, 42] cpu = IntCodeCPU(program) cpu.run() self.assertEqual([42], cpu.pop_output())