Advent of Code Day 21

Intcode

In [1]:
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 [3]:
input21 = readfile("AoC/input21.txt")
In [40]:
def out(program):
    while (output := next(program)):
        if output < 128:
            print(chr(output), end="")
        else:
            print(output, end="")

def inp(program, text):
    result = None
    for ch in text:
        result = program.send(ord(ch))
        if result:
            print(chr(result), end="")
    return result

def jumper(input21):
    program = compute(process(input21))
    out(program)

    inp(program, "NOT A J\n") # J = A is a hole
    inp(program, "NOT B T\n") # T = B is a hole
    inp(program, "OR T J\n")  # J = A OR B is a hole
    inp(program, "NOT C T\n") # T = C is a hole
    inp(program, "OR J T\n")  # T = A or B or C is a hole

    inp(program, "AND D T\n") # T = (A or B or C is a hole) AND D is not.

    inp(program, "NOT T J\n") # J = !T
    inp(program, "NOT J J\n") # J = !J = !!T

    inp(program, "WALK\n")

    out(program)


def jumper2(input21):
    program = compute(process(input21))
    out(program)

    # Jump if there is ground at 4, repeated twice

    inp(program, "NOT A J\n") # J = A is a hole
    inp(program, "NOT B T\n") # T = B is a hole
    inp(program, "OR T J\n")  # J = A OR B is a hole
    inp(program, "NOT C T\n") # T = C is a hole
    inp(program, "OR J T\n")  # T = A or B or C is a hole

    inp(program, "AND D T\n") # T = (A or B or C is a hole) AND D is not.

    inp(program, "NOT I J\n") # J = !I
    inp(program, "NOT J J\n") # J = I # Can jump from E

    inp(program, "OR F J\n") # J = I OR F # Can move forward twice

    inp(program, "AND E J\n") # J = E && (F || I) # Can move to E

    inp(program, "OR H J\n") # J = H || (E && (F || I))


    inp(program, "AND T J\n") # J = !T
    inp(program, "RUN\n")

    out(program)
In [41]:
jumper(input21)
Input instructions:

Walking...

19359316

StopIterationTraceback (most recent call last)
<ipython-input-41-a06bdcb033c8> in <module>
----> 1 jumper(input21)

<ipython-input-40-f55dbcfc39c5> in jumper(input21)
     31     inp(program, "WALK\n")
     32 
---> 33     out(program)
     34 
     35 

<ipython-input-40-f55dbcfc39c5> in out(program)
      1 def out(program):
----> 2     while (output := next(program)):
      3         if output < 128:
      4             print(chr(output), end="")
      5         else:

StopIteration: 
In [42]:
jumper2(input21)
Input instructions:

Running...

1141281622

StopIterationTraceback (most recent call last)
<ipython-input-42-20a5bbd1ec50> in <module>
----> 1 jumper2(input21)

<ipython-input-40-f55dbcfc39c5> in jumper2(input21)
     61     inp(program, "RUN\n")
     62 
---> 63     out(program)
     64 

<ipython-input-40-f55dbcfc39c5> in out(program)
      1 def out(program):
----> 2     while (output := next(program)):
      3         if output < 128:
      4             print(chr(output), end="")
      5         else:

StopIteration: 
In [ ]: