def params(program, i, count):
modes = str(program[i] // 100)[::-1]
result = []
for x in range(count - 1):
arg = program[i + 1 + x]
if x >= len(modes) or modes[x] == "0":
result.append(program[arg])
else:
result.append(arg)
result.append(program[i + count]) # output
return result
assert params([1101, 0, 1], 0, 2) == [0, 1]
assert params([1, 0, 1], 0, 2) == [1, 1]
assert params([101, 0, 1], 0, 2) == [0, 1]
def add(program, i, **kwargs):
assert program[i] % 100 == 1
a, b, out = params(program, i, 3)
program[out] = a + b
return i + 4, None
def mul(program, i, **kwargs):
assert program[i] % 100 == 2
a, b, out = params(program, i, 3)
program[out] = a * b
return i + 4, None
def inp(program, i, input_value, **kwargs):
assert program[i] % 100 == 3
out, = params(program, i, 1)
program[out] = input_value
print(f"> program[{out}] = {input_value}")
return i + 2, None
def out(program, i, **kwargs):
assert program[i] % 100 == 4
val, _ = params(program, i, 2)
print(f"> {val}")
return i + 2, val
def jit(program, i, **kwargs):
assert program[i] % 100 == 5
test, ip, _ = params(program, i, 3)
if test != 0:
return ip, None
return i + 3, None
def jif(program, i, **kwargs):
assert program[i] % 100 == 6
test, ip, _ = params(program, i, 3)
if test == 0:
return ip, None
return i + 3, None
def lt(program, i, **kwargs):
assert program[i] % 100 == 7
a, b, out = params(program, i, 3)
program[out] = int(a < b)
return i + 4, None
def eq(program, i, **kwargs):
assert program[i] % 100 == 8
a, b, out = params(program, i, 3)
program[out] = int(a == b)
return i + 4, None
operations = { 1: add, 2: mul, 3: inp, 4: out, 5: jit, 6: jif, 7: lt, 8: eq }
def compute(program, input_value, debug=False):
l = len(program)
i = 0
output_value = None
last_output = None
while i < l:
op = program[i]
if op == 99:
if debug:
print(f">> exit {output_value}")
return last_output, program
if debug:
print(f">> {i}, {list(enumerate(program))[max(0, i-15):i+15]}")
i, output_value = operations[op % 100](program, i, input_value=input_value)
if output_value:
last_output = output_value
raise Exception("Didn't terminate properly")
listing = None
with open("AoC/input5.txt") as input_file:
listing = input_file.read()
def process(listing):
return list(map(int, listing.split(",")))
compute(process("3,0,4,0,99"), 1)
compute(process("3,9,8,9,10,9,4,9,99,-1,8"), 8)
compute(process("3,9,8,9,10,9,4,9,99,-1,8"), 3)
compute(process("3,9,7,9,10,9,4,9,99,-1,8"), 5)
compute(process("3,9,7,9,10,9,4,9,99,-1,8"), 9)
compute(process("3,3,1108,-1,8,3,4,3,99"), 8)
compute(process("3,3,1108,-1,8,3,4,3,99"), 100)
compute(process("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9"), -100)
compute(process("3,12,6,12,15,1,13,14,13,4,13,99,-1,0,1,9"), 0)
compute(process("3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99"), 7)[0]
compute(process(listing), 1)[0]
compute(process(listing), 5)[0]
This one took me a ridiculous amount of time to complete: around halfway I gave up on hacked together code and decided to clean it up to handle opcodes more neatly and to make debugging slightly easier. I'm definitely struggling a bit against the notebook at this point, particularly around refactoring code across cells simply and quickly.
Having cleaner unit tests is also hard; I almost wish I could split cells vertically too and attach a unit test to the right half of the cell.