Advent of Code: Day 23

For Day 23, the challenge is to understand what some assembly code is doing and calculate the answer. This is probably my favourite challenge so far.

My initial interpreter is:

import time
import Queue
from itertools import cycle
with open("input.txt", "r") as o:
    commands = o.read().split("\n")


class Program():
    def __init__(self, commands, debug_mode=True):
        self.registers = {}
        if not debug_mode:
            self.registers["a"] = 1
        self.ptr = 0
        self.commands = commands

    def get_value(self, f):
        try:
            return int(f)
        except ValueError:
            return self.registers.get(f, 0)

    def run(self):
        self.mul_counter = 0
        while True:
            if self.ptr >= len(self.commands):
                break
            cmd = self.commands[self.ptr].split(" ")
            self.ptr += 1
            if cmd[0] == "set":
                self.registers[cmd[1]] = self.get_value(cmd[2])
            elif cmd[0] == "sub":
                self.registers[cmd[1]] = self.get_value(cmd[1]) - self.get_value(cmd[2])
            elif cmd[0] == "mul":
                self.registers[cmd[1]] = self.get_value(cmd[1]) * self.get_value(cmd[2])
                self.mul_counter += 1
            elif cmd[0] == "jnz":
                if not self.get_value(cmd[1]) == 0:
                    self.ptr += self.get_value(cmd[2]) - 1


part1 = Program(commands)
part1.run()
print "Part 1", part1.mul_counter

part2 = Program(commands, False)
part2.run()
print "Part 2", part2.registers["h"]

However this of course will not run fast enough to execute part 2. Here is my input:

set b 67
set c b
jnz a 2
jnz 1 5
mul b 100
sub b -100000
set c b
sub c -17000
set f 1
set d 2
set e 2
set g d
mul g e
sub g b
jnz g 2
set f 0
sub e -1
set g e
sub g b
jnz g -8
sub d -1
set g d
sub g b
jnz g -13
jnz f 2
sub h -1
set g b
sub g c
jnz g 2
jnz 1 3
sub b -17
jnz 1 -23

I first converted that into something a little higher level:

        b = 67
        c = b
        if (a != 0) goto JMP1
        goto JMP2
JMP1:   b = b * 100
        b = b + 100000
        c = b
        c = c + 17000
JMP2:   f = 1
        d = 2
JMP5:   e = 2
JMP4:   g = d
        g = g * e
        g = g - b
        if (g != 0) goto JMP3
        f = 0
JMP3:   e = e + 1
        g = e
        g = g - b
        if (g != 0) goto JMP4
        d = d + 1
        g = d
        g = g - b
        if (g != 0) goto JMP5
        if (f != 0) goto JMP6
        h = h + 1
JMP6:   g = b
        g = g - c
        if (g != 0) goto JMP7
        exit
JMP7:   b = b + 17
        goto JMP2

And then through a series of further conversions realised more about what it was doing until I converted it into valid Python:

from math import sqrt
b = 106700
c = 123700
h = 0

for i in range(b, c + 17, 17):
    for d in range(2, int(sqrt(i))):
        if i % d == 0:
            h += 1
            break

print h

(Only looping until the square root is an optimization because if it is not prime a factor must be found by the square root). Running this gave me the correct answer.

A really nice challenge!

Advent of Code runs every day up to Christmas, you should join in!.

Show Comments

Get the latest posts delivered right to your inbox.