Advent of Code Day 19

In [2]:
def readfile(path):
    with open(path) as input_file: 
        return input_file.read().strip()

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 ...###