Advent of Code 2022 day 18
Part 1 was simple. Part 2 was not. It’s interesting how working in more than
two dimensions becomes non-trivial very quickly. I am possibly overly chuffed
with the function name try_to_get_out
.
Part 2 takes a long time to run. There may have been a smarter way, but I’m reasonably happy with it.
from itertools import combinations, product # with open("18_test.txt") as f: with open("18.txt") as f: lines = f.read().splitlines() def get_cube(line: str) -> dict: x, y, z = line.split(",") return {"x": int(x), "y": int(y), "z": int(z)} def next_to(a: dict, b: dict): if ( sum([ a["x"] == b["x"], a["y"] == b["y"], a["z"] == b["z"] ]) == 2 and max([ abs(a["x"] - b["x"]), abs(a["y"] - b["y"]), abs(a["z"] - b["z"]) ]) == 1 ): return True return False cubes = [get_cube(line) for line in lines] total_faces = len(cubes)*6 for (a, b) in combinations(cubes, 2): if next_to(a, b): total_faces -= 2 print(total_faces) # part 2 import sys sys.setrecursionlimit(2000) min_x = min(a["x"] for a in cubes) max_x = max(a["x"] for a in cubes) min_y = min(a["y"] for a in cubes) max_y = max(a["y"] for a in cubes) min_z = min(a["z"] for a in cubes) max_z = max(a["z"] for a in cubes) def get_all_possible_cubes(cubes: list[dict]) -> list[dict]: for x in range(min_x, max_x+1): for y in range(min_y, max_y+1): for z in range(min_z, max_z+1): yield {"x": x, "y": y, "z": z} possibly_inside = [x for x in get_all_possible_cubes(cubes)] inside_cubes = cubes.copy() original_cubes = cubes.copy() def try_to_get_out(cube, history): def next_cubes(cube): for i, j, k in ( (-1, 0, 0), (0, -1, 0), (0, 0, -1), (1, 0, 0), (0, 1, 0), (0, 0, 1), ): yield {"x": cube["x"]+i, "y": cube["y"]+j, "z": cube["z"]+k} if cube in history: return True if ( cube["x"] < min_x or cube["x"] > max_x or cube["y"] < min_y or cube["y"] > max_y or cube["z"] < min_z or cube["z"] > max_z ): return False history.append(cube) for next_cube in next_cubes(cube): if try_to_get_out(next_cube, history) is False: return False return True def inside(cube, cubes): if cube in cubes: return False history = cubes.copy() return try_to_get_out(cube, history=history) for i, cube in enumerate(possibly_inside): # print(i, "out of", len(possibly_inside)) if ( sum([next_to(cube, x) for x in original_cubes]) > 0 and inside(cube, cubes) ): total_faces -= sum([next_to(cube, x) for x in original_cubes]) cubes.append(cube) print(total_faces)