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
input15 = readfile("AoC/input15.txt")
def print_grid(grid, x=0, y=0):
grid[(x, y)] = "@"
keys = grid.keys()
minx = min(x[0] for x in keys)
miny = min(x[1] for x in keys)
maxx = max(x[0] for x in keys)
maxy = max(x[1] for x in keys)
for y in range(miny, maxy + 1):
for x in range(minx, maxx + 1):
print(grid.get((x, y), " "), end="")
print()
return "Printed"
dirs = {1: (0, -1), 2: (0, 1), 3: (-1, 0), 4: (1, 0)}
opp = {1: 2, 2: 1, 3: 4, 4: 3}
def walk_droid():
droid = compute(process(input15))
grid = {}
queue = [[]]
visited = set()
visited.add((0, 0))
oxy = None
oxy_pos = None
testset = set([1, 2])
while queue:
steps = queue.pop(0)
x, y = 0, 0
for step in steps:
assert next(droid) == None
assert droid.send(step) in testset
x += dirs[step][0]
y += dirs[step][1]
for d in range(1, 5):
assert next(droid) == None
result = droid.send(d)
nx, ny = (x + dirs[d][0], y + dirs[d][1])
ch = '#'
if result == 1 or result == 2:
ch = '.' if result == 1 else 'o'
assert next(droid) == None
assert droid.send(opp[d]) in testset
if (nx, ny) not in visited:
queue.append(steps[:] + [d])
visited.add((nx, ny))
if result == 2:
oxy = len(steps) + 1
oxy_pos = nx, ny
else:
assert result == 0
grid[(nx, ny)] = ch
for step in steps[::-1]:
assert next(droid) == None
assert droid.send(opp[step]) in testset
return oxy, oxy_pos, grid
oxy, oxypos, grid = walk_droid()
print_grid(grid)
oxypos
def deepest(grid, oxypos):
q = [oxypos]
depths = {oxypos: 0}
while q:
cur = q.pop(0)
for d in range(1, 5):
nx = (cur[0] + dirs[d][0], cur[1] + dirs[d][1])
if grid[nx] == '.' and nx not in depths:
q.append(nx)
depths[nx] = depths[cur] + 1
return max(depths.values())
deepest(grid, oxypos)