advent-of-code-2019/day25.py

121 lines
2.8 KiB
Python

from intcode import parse, emulator, REPL
import re
N = 'north'
S = 'south'
E = 'east'
W = 'west'
back = {N : S, S : N, W : E, E : W}
def add_vec(xy, d):
x, y = xy
if d == N:
return (x, y+1)
if d == S:
return (x, y-1)
if d == W:
return (x-1, y)
if d == E:
return (x+1, y)
class Room:
def __init__(self, mssg, path):
blocks = mssg.strip().split("\n\n")
head_str = blocks[0]
door_str = blocks[1]
item_str = '\n'.join(blocks[2:])
self.name = re.findall('=+ ([^=]+) =+', head_str)[0]
self.description = re.findall(r'=\n([\s\S]+)', head_str)[-1].rstrip()
self.doors = re.findall(r'- (\w+)\n?', door_str)
self.items = re.findall(r'- (.+)\n?', item_str)
self.path = path
def __eq__(self, other):
return self.name == other.name
def __repr__(self):
head = "== {} ==\n{}".format(self.name, self.description)
doors = "Doors here lead:\n- {}".format("\n- ".join(self.doors))
items = "" if self.items == [] else "\n\nItems here:\n- {}".format("\n- ".join(self.items))
path = " -> ".join(self.path)
return "{}\n\n{}{}\n{}".format(head, doors, items, path)
def encode(s):
return map(ord, s + '\n')
def decode(lst):
return ''.join(map(chr, lst))
def goto_room(repl, room):
for d in room.path:
repl.write(d)
next(repl)
def try_item(repl, item):
if item in ("infinite loop", "giant electromagnet"):
return False
repl = repl.copy()
repl.write("take " + item)
next(repl)
try:
repl.write('')
next(repl)
return True
except StopIteration:
return False
def map_ship(repl):
rooms = []
items = []
def aux(path):
s = next(repl)
try:
room = Room(s, path)
except:
return
if room in rooms:
return
rooms.append(room)
for item in room.items:
if not try_item(repl, item):
continue
repl.write("take " + item)
next(repl)
items.append(item)
for d in room.doors:
repl.write(d)
aux(path + [d])
repl.write(back[d])
next(repl)
aux([])
return rooms, items
def preproc(puzzle_input):
prog = parse(puzzle_input)
emul = emulator(prog)
repl = REPL(emul, decode=decode, encode=encode)
rooms, items = map_ship(repl)
checkpoint = list(filter(lambda room : room.name == "Security Checkpoint", rooms))[0]
goto_room(repl, checkpoint)
return repl
def partI(repl):
for item in ["coin", "mutex", "astronaut ice cream", "dehydrated water"]:
repl.write("drop " + item)
next(repl)
repl.write("north")
s = next(repl)
return re.findall(r'\d+', s)[0]
def partII(_):
return "No solution"