# Advent of Code Day 5¶

In :
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]

In :
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 }

In :
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")

In :
listing = None
with open("AoC/input5.txt") as input_file:

In :
def process(listing):
return list(map(int, listing.split(",")))

In :
compute(process("3,0,4,0,99"), 1)

> program = 1
> 1

Out:
(1, [1, 0, 4, 0, 99])
In :
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)

> program = 8
> 1
> program = 3
> 0
> program = 5
> 1
> program = 9
> 0
> program = 8
> 1
> program = 100
> 0
> program = -100
> 1
> program = 0
> 0

Out:
(None, [3, 12, 6, 12, 15, 1, 13, 14, 13, 4, 13, 99, 0, 0, 1, 9])
In :
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)

> program = 7
> 999

Out:
999
In :
compute(process(listing), 1)

> program = 1
> 0
> 0
> 0
> 0
> 0
> 0
> 0
> 0
> 0
> 13294380

Out:
13294380
In :
compute(process(listing), 5)

> program = 5
> 11460760

Out:
11460760

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.