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
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_values, **kwargs):
assert program[i] % 100 == 3
out, = params(program, i, 1)
program[out] = input_values.pop(0)
# print(f"> 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
operations = { 1: add, 2: mul, 3: inp, 4: out, 5: jit, 6: jif, 7: lt, 8: eq }
def compute(program, input_values, 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}")
yield None
if debug:
print(f">> {i}, {list(enumerate(program))[max(0, i-15):i+15]}")
i, output_value = operations[op % 100](program, i, input_values=input_values)
if output_value is not None:
yield output_value
raise Exception("Didn't terminate properly")
def process(listing):
return list(map(int, listing.split(",")))
testinput="3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0"
def check_phases(program):
max_set = None
for permutation in permutations(list(range(5))):
inp = 0
for p in permutation:
computation = compute(process(program), [p, inp])
inp = next(computation)
if not max_set or max_set[0] < inp:
max_set = (inp, permutation)
return max_set
check_phases(testinput)
def permutations(x):
if len(x) == 1:
yield x
else:
cur = x[0]
rest = x[1:]
for inner in permutations(rest):
for posn in range(len(inner) + 1):
option = inner[:]
option.insert(posn, cur)
yield option
check_phases("3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0")
with open("AoC/input7.txt") as inputfile:
print( check_phases(inputfile.read().strip()))
test_input2 = "3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5"
def check_phases2(permutation, program):
inputs = [[p] for p in permutation]
inputs[0].append(0)
amplifiers = [compute(process(program), inp) for inp in inputs]
last_outputs = [None] * len(permutation)
i = 0
while True:
out = next(amplifiers[i])
if out is None:
break
elif out != "blocked":
inputs[(i + 1) % 5].append(out)
last_outputs[i] = out
i = (i + 1) % 5
return last_outputs
def find_max(program):
max_set = None
for permutation in permutations(list(range(5, 10))):
result = check_phases2(permutation, program)
if not max_set or result[4] > max_set[0]:
max_set = (result[4], permutation)
return max_set
find_max(test_input2)
list(range(9, 4, -1))
with open("AoC/input7.txt") as inputfile:
print( find_max(inputfile.read().strip()))
Rough solution again: received my highest rank till date - ranked 338 on the second star. Python's coroutines make this significantly easier to reason about.