From c1540f20967f4dac3380e97f6c9dfb5ba1fd982d Mon Sep 17 00:00:00 2001 From: Adrien Abraham Date: Wed, 18 Dec 2019 18:01:42 +0100 Subject: [PATCH] Day 18: WIP --- 2019/day18.py | 104 +++++++++++++++++++++++++++++++++++++++++++++++++- 2019/grid.py | 45 ++++++++++------------ 2 files changed, 123 insertions(+), 26 deletions(-) diff --git a/2019/day18.py b/2019/day18.py index 4508354..32a2833 100644 --- a/2019/day18.py +++ b/2019/day18.py @@ -1,13 +1,59 @@ +import string + from grid import Grid +from vector import v2a + + +EX1 = [ + "#########", + "#b.A.@.a#", + "#########", +] +# reqs: +# a: [] +# b: [a] +EX2 = [ + "########################", + "#f.D.E.e.C.b.A.@.a.B.c.#", + "######################.#", + "#d.....................#", + "########################", +] +# reqs: +# a: [] +# b: [a] +# c: [b] +# d: [b] +# e: [a, c] +# f: [a, c, e, d] +# +# - get a +# - get b +# - get c or d? +# - get c +# - get d or e? +# - d def main(): with open("day18.txt", "rt") as input_file: lines = input_file.readlines() - lab = Lab(lines) + lab = Lab(lines=EX1) lab.dumb_print() + lab.find_positions() + pos = lab.start + missing_keys = list(lab.key_pos.keys()) + obtained_keys = set("a") + while missing_keys: + + for key, bt in lab.get_all_backtracks(pos).items(): + steps, reqs, founds = bt + if len(reqs - obtained_keys) == 0: + print(key, "is accessible") + break + class Lab(Grid): @@ -15,6 +61,62 @@ class Lab(Grid): TILE_WALL = "#" TILE_START = "@" + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs, value_factory=lambda: " ") + self.start = None + self.key_pos = {} + self.door_pos = {} + + def find_positions(self): + for x, y, v in self.values_gen(): + if v == Lab.TILE_START: + self.start = (x, y) + if v in string.ascii_lowercase: + self.key_pos[v] = (x, y) + if v in string.ascii_uppercase: + self.door_pos[v] = (x, y) + self.setv(self.start[0], self.start[1], Lab.TILE_PATH) + + def get_all_backtracks(self, start): + return { + kname: self.backtrack(self.path(start, kpos), kpos, start) + for kname, kpos in self.key_pos.items() + } + + def path(self, s, e): + discovered = Grid(value_factory=bool) + discovered.setv(s[0], s[1], True) + parents = {} + q = [s] + while q: + pos = q.pop(0) + if pos == e: + return parents + nears = self.near_objects(pos) + for near_pos, near_tile in nears.items(): + if near_tile == Lab.TILE_WALL: + continue + if discovered.getv(near_pos[0], near_pos[1]): + continue + discovered.setv(near_pos[0], near_pos[1], True) + parents[near_pos] = pos + q.append(near_pos) + return parents + + def backtrack(self, parents, pos, end): + count = 0 + requirements = set() + keys_found = set() + while pos != end: + pos = parents[pos] + count += 1 + tile = self.getv(pos[0], pos[1]) + if tile in string.ascii_uppercase: + requirements.add(tile.lower()) + elif tile in string.ascii_lowercase: + keys_found.add(tile) + return count, requirements, keys_found + if __name__ == "__main__": main() diff --git a/2019/grid.py b/2019/grid.py index c65672e..f442284 100644 --- a/2019/grid.py +++ b/2019/grid.py @@ -5,25 +5,30 @@ from collections import defaultdict class Grid: - def __init__(self, lines=None): - self.g = defaultdict(lambda: defaultdict(int)) + def __init__(self, value_factory=int, lines=None): + self.g = defaultdict(lambda: defaultdict(value_factory)) if lines: self.load(lines) - def load(self, lines, f=lambda v: v): - for y, line in enumerate(lines): - for x, c in enumerate(line.rstrip()): - self.g[y][x] = f(c) - def getv(self, x, y): return self.g[y][x] def setv(self, x, y, value): self.g[y][x] = value - def near_items(self, p): + def load(self, lines, f=lambda v: v): + for y, line in enumerate(lines): + for x, c in enumerate(line.rstrip()): + self.g[y][x] = f(c) + + def values_gen(self): + for y, row in self.g.items(): + for x, v in row.items(): + yield (x, y, v) + + def near_objects(self, p): """Return a dict of neighbor positions to values (U, L, D, R).""" - return {pos: self.g[pos[1]][pos[0]] for pos in Grid.near(p)} + return {q: self.g[q[1]][q[0]] for q in Grid.near(p)} def dumb_print(self, f=lambda v: v): for row in self.g.values(): @@ -31,22 +36,12 @@ class Grid: print(f(x), end="") print() - def print_near(self, p): - print("".join([ - chr(self.g[p[1] - 1][p[0] - 1]), - chr(self.g[p[1] - 1][p[0]]), - chr(self.g[p[1] - 1][p[0] + 1]), - ])) - print("".join([ - chr(self.g[p[1] ][p[0] - 1]), - chr(self.g[p[1] ][p[0]]), - chr(self.g[p[1] ][p[0] + 1]), - ])) - print("".join([ - chr(self.g[p[1] + 1][p[0] - 1]), - chr(self.g[p[1] + 1][p[0]]), - chr(self.g[p[1] + 1][p[0] + 1]), - ])) + def print_near(self, p, view_size=2): + for dy in range(-view_size, view_size + 1): + print("".join([ + self.g[p[1] + dy][p[0] + dx] + for dx in range(-view_size, view_size + 1) + ])) @staticmethod def near(p):