# Advent of Code Day 19¶

In [2]:
def readfile(path):
with open(path) as input_file:

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])
elif modes[x] == "2":
result.append(program[program.offset + arg])
else:
result.append(arg)

output = program[i + count]
if len(modes) >= count and modes[count - 1] == "2":
output += program.offset

result.append(output) # output
return result

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[i]} program[{out}] = {program[out]}")
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

def rbo(program, i, **kwargs):
assert program[i] % 100 == 9
delta, _ = params(program, i, 2)
program.offset += delta
# print (f"> rbo = {program.offset}" )
return i + 2, None

operations = { 1: add, 2: mul, 3: inp, 4: out, 5: jit, 6: jif, 7: lt, 8: eq, 9: rbo }

class Program(list):
def __init__(self, *args, **kwargs):
super(Program, self).__init__(args[0])
self.offset = 0

def compute(program, debug=False):
program = Program(program)

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

if debug:
print(f">> {i}, {list(enumerate(program))[i:i+5]}")

if op % 100 == 3:
input_value = yield
else:
input_value = None

i, output_value = operations[op % 100](program, i, input_value=input_value)

if output_value is not None:
yield output_value

raise Exception("Didn't terminate properly")

def process(listing):
lst = list(map(int, listing.split(",")))
lst.extend([0] * 100000)
return lst

In [4]:
program = readfile("AoC/input19.txt")

In [33]:
total = 0
for y in range(50):
for x in range(50):
p = compute(process(program.strip()))
assert next(p) == None
assert p.send(x) == None
result = p.send(y)
print(result, end='')
total += result
print()

total

10000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000100000000000000000000000000000000000000000000
00000010000000000000000000000000000000000000000000
00000001000000000000000000000000000000000000000000
00000000100000000000000000000000000000000000000000
00000000011000000000000000000000000000000000000000
00000000001100000000000000000000000000000000000000
00000000000110000000000000000000000000000000000000
00000000000011000000000000000000000000000000000000
00000000000001110000000000000000000000000000000000
00000000000000111000000000000000000000000000000000
00000000000000011100000000000000000000000000000000
00000000000000001110000000000000000000000000000000
00000000000000000111100000000000000000000000000000
00000000000000000011110000000000000000000000000000
00000000000000000001111000000000000000000000000000
00000000000000000000111110000000000000000000000000
00000000000000000000011111000000000000000000000000
00000000000000000000001111100000000000000000000000
00000000000000000000000111110000000000000000000000
00000000000000000000000011111100000000000000000000
00000000000000000000000001111110000000000000000000
00000000000000000000000000011111000000000000000000
00000000000000000000000000001111100000000000000000
00000000000000000000000000000111111000000000000000
00000000000000000000000000000011111100000000000000
00000000000000000000000000000001111110000000000000
00000000000000000000000000000000111111000000000000
00000000000000000000000000000000011111110000000000
00000000000000000000000000000000001111111000000000
00000000000000000000000000000000000111111100000000
00000000000000000000000000000000000011111110000000
00000000000000000000000000000000000001111111100000
00000000000000000000000000000000000000111111110000
00000000000000000000000000000000000000011111111000
00000000000000000000000000000000000000001111111110
00000000000000000000000000000000000000000111111111
00000000000000000000000000000000000000000011111111
00000000000000000000000000000000000000000001111111
00000000000000000000000000000000000000000000111111
00000000000000000000000000000000000000000000011111
00000000000000000000000000000000000000000000001111
00000000000000000000000000000000000000000000000111
00000000000000000000000000000000000000000000000011
00000000000000000000000000000000000000000000000001
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000

Out[33]:
209
In [31]:
def test_point(x, y):
p = compute(process(program.strip()))
assert next(p) == None
assert p.send(x) == None
return p.send(y)

def find(size):
x, y = 0, 0
while True:
if y >= size - 1:
if test_point(x + size - 1, y - size + 1):
return x, y - size + 1

i = 0
passed = False
while not (passed := test_point(x + i, y + 1)) and i <= 10:
i += 1

if passed:
x = x + i
y = y + 1

x, y = find(100)

In [32]:
x * 10000 + y

Out[32]:
10450905
In [ ]:
 012345
0#......
1.#.....
2..##...
3...###.
4 ...###