Advent of Code: Day 23

Source

Part 1: Create a simple virtual machine with two registers (a and b, non-negative integers) and six instructions:

  • hlf (a|b) - divide the given register by half, round down
  • tpl (a|b) - triple the given register
  • inc (a|b) - add 1 to the given register
  • jmp [+-]\d+ - jump forward/backwards by the given number of instructions
  • jie (a|b), [+-]\d+ - if the given register is even, jump
  • jio (a|b), [+-]\d+ - if the given register equals one, jump

I do love writing a good virtual machine. Check out my ‘Tiny’ virtual machine in Racket.

def read_program():
    return [
        tuple(re.split('[, ]+', line.strip()))
        for line in sys.stdin
    ]

def run(program, **initial_state):
    pc = 0
    registers = {'a': 0, 'b': 0}
    registers.update(initial_state)

    while True:
        op = program[pc][0]
        args = program[pc][1:]

        if op == 'hlf':
            registers[args[0]] //= 2
            pc += 1
        elif op == 'tpl':
            registers[args[0]] *= 3
            pc += 1
        elif op == 'inc':
            registers[args[0]] += 1
            pc += 1
        elif op == 'jmp':
            pc += int(args[0])
        elif op == 'jie':
            if registers[args[0]] % 2 == 0:
                pc += int(args[1])
            else:
                pc += 1
        elif op == 'jio':
            if registers[args[0]] == 1:
                pc += int(args[1])
            else:
                pc += 1

        if not (0 <= pc < len(program)):
            break

    return registers

if __name__ == '__main__':
    program = read_program()
    output = run(program)
    print(output['b'])

It’s not the most abstracted thing ever, but it really doesn’t matter. It works great.

Part 2: Re-run with the initial state a=1, b=0.

I’ll reuse the same trick I’ve used a few times before to load part 1:

part1 = imp.load_source('part1', 'part-1.py')

if __name__ == '__main__':
    program = part1.read_program()
    output = part1.run(program, a = 1)
    print(output['b'])