import matrix import shared import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np from dataclasses import dataclass from typing import Set, Tuple from functools import cached_property @dataclass class Cube: x: int y: int z: int neighbor_coords: Set[Tuple[int,int,int]] = None @cached_property def xyz(self): return (self.x,self.y,self.z) def set_neighbor_coords(self): self.neighbor_coords = get_neighbors(self.x,self.y,self.z) def get_neighbors(x,y,z): # Generate the six neighbor_coords # Look at a die 6 to the left, 2 on top, one on right offsets = ( (1,0,0), # 1 (0,0,1), # 2 (0,-1,0),# 3 (0,1,0), # 4 (0,0,-1),# 5 (-1,0,0) # 6 ) neighbor_coords = set([(x+o[0], y+o[1], z+o[2]) for o in offsets]) return neighbor_coords def count_neighbor_coords(x,y,z): pass # @shared.profile def part1(rows): cubes = [] for row in rows: x,y,z = row cube = Cube(x=x,y=y,z=z) cube.set_neighbor_coords() cubes.append(cube) potential = len(cubes) * 6 for idx in range(len(cubes)): cube = cubes[idx] for other in cubes[:idx] + cubes[idx+1:]: if other.xyz in cube.neighbor_coords: potential -= 1 print(potential) # @shared.profile def part2(rows): cubes = [] maxX,maxY,maxZ = 0,0,0 _lava = set() for row in rows: x,y,z = row maxX = max(maxX,x) maxY = max(maxY,y) maxZ = max(maxZ,z) cube = Cube(x=x,y=y,z=z) cube.set_neighbor_coords() cubes.append(cube) _lava.add((x,y,z)) print(maxX,maxY,maxZ) potential = len(cubes) * 6 for idx in range(len(cubes)): cube = cubes[idx] others = cubes[:idx] + cubes[idx+1:] for other in others: if other.xyz in cube.neighbor_coords: potential -= 1 air = [] for x in range(0,maxX+1): for y in range(0,maxY+1): for z in range(0,maxZ+1): lava_count = 0 if (x,y,z) in _lava: continue # is air _ns = get_neighbors(x,y,z) air_touching_lava = False for _n in _ns: if _n in _lava: lava_count += 1 air_touching_lava = True if air_touching_lava: air.append((x,y,z)) if lava_count == 6: potential -= 6 print(potential, air) def main(): rows = [map(int,row.split(",")) for row in shared.load_rows(18)] with shared.elapsed_timer() as elapsed: part1(rows) print("🕒", elapsed()) rows = [map(int,row.split(",")) for row in shared.load_rows(18)] with shared.elapsed_timer() as elapsed: part2(rows) print("🕒", elapsed()) if __name__ == "__main__": main()