def render(g): if isinstance(g, str): g = graph(g) xs = [int(z.real) for z in g.nodes] ys = [int(z.imag) for z in g.nodes] x0, x1 = min(xs) - 1, max(xs) + 2 y0, y1 = min(ys) - 1, max(ys) + 2 for y in range(y0, y1): line = "" for x in range(x0, x1): z = complex(x, y) if z == 0: line += "X" elif z in g.nodes: line += "." elif (z - 1, z + 1) in g.edges: line += "|" elif (z - 1j, z + 1j) in g.edges: line += "-" elif any(zn in g.nodes for zn in ZGrid.near(z, n=8)): line += "#" else: line += " " print(line) print()
def __init__(self, data, part="a"): grid = ZGrid(data, on=".", off="#") pos = ("@", ) if part == "b": [z0] = [z for z, v in grid.items() if v == "@"] if grid.count_near(z0, val=".", n=8, default=".") == 8: pos = ("@0", "@1", "@2", "@3") for z in grid.near(z0, n=5): grid[z] = grid.off for p, dz in zip(pos, [-1 - 1j, 1 - 1j, 1 + 1j, -1 + 1j]): grid[z0 + dz] = p graph = grid.graph(extra=frozenset(string.ascii_letters).union(pos)) self.all_keys = {k for k in graph.extra if k in string.ascii_lowercase} # map of the other keys that must be acquired before each key is acquired self.obstructions = {k: set() for k in self.all_keys} # precached distances between points of interest self.kdist = {} for k0 in self.all_keys: for p in pos: try: path = nx.shortest_path(graph, graph.extra[p], graph.extra[k0]) except nx.NetworkXNoPath: pass else: break else: raise Exception("nothing possible to do") self.kdist[k0, p] = self.kdist[p, k0] = len(path) - 1 assert path[0] == graph.extra[p] assert path[-1] == graph.extra[k0] for p in path[1:-1]: if p in graph.extra.values(): k1 = grid[p].lower() self.obstructions[k0].add(k1) for k1, k2 in combinations(self.all_keys, 2): z1 = graph.extra[k1] z2 = graph.extra[k2] try: d = nx.shortest_path_length(graph, z1, z2) except nx.NetworkXNoPath: continue self.kdist[k1, k2] = self.kdist[k2, k1] = d state0 = pos, frozenset() AStar.__init__(self, state0, target=None)
g = ZGrid(data, transform=int) a = b = 0 while True: b += 1 n = 0 flash = [] for z in g: if g[z] == 9: g[z] = 0 flash.append(z) else: g[z] += 1 while flash: z0 = flash.pop() n += 1 for z in g.near(z0, n=8): if g.get(z): if g[z] == 9: g[z] = 0 flash.append(z) else: g[z] += 1 if b <= 100: a += n if n == len(g): break print("part a:", a) print("part b:", b)