diff --git a/2022/python/day18.py b/2022/python/day18.py index 0fea73d..126758d 100644 --- a/2022/python/day18.py +++ b/2022/python/day18.py @@ -4,6 +4,11 @@ from pprint import pprint from dataclasses import dataclass from typing import Set, Tuple from functools import cached_property +from mpl_toolkits.mplot3d import Axes3D +import numpy as np +import matplotlib.pyplot as plt + + @dataclass @@ -31,12 +36,24 @@ def get_neighbors(x,y,z): (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 + return set([(x+o[0], y+o[1], z+o[2]) for o in offsets]) -def count_neighbor_coords(x,y,z): - pass +def get_flat_neighbors(x,y,z): + # Generate the six neighbor_coords + # Look at a die 6 to the left, 2 on top, one on right + # ignore top and bottom + 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 + ) + return set([(x+o[0], y+o[1], z+o[2]) for o in offsets]) +def get_flat_neighbors_from(x,y,z, f): + return get_flat_neighbors(x,y,z).intersection(f) # @shared.profile @@ -53,7 +70,7 @@ def part1(rows): -def part2(rows): +def surface_area(rows): cubes = {} maxX,maxY,maxZ = 0,0,0 for idx, (x,y,z) in enumerate(rows): @@ -68,78 +85,93 @@ def part2(rows): for other in cube['not_me']: if other in cube['n']: potential -= 1 + return potential, maxX,maxY,maxZ, cubes, _cubes + + +def part2(rows): + potential, maxX, maxY,maxZ,cubes,_cubes = surface_area(rows) + air = set() for x in range(0,maxX+1): for y in range(0,maxY+1): for z in range(0,maxZ+1): - air.add((x,y,z)) + if (x,y,z) not in _cubes: + air.add((x,y,z)) air -= _cubes # Remove all lava from air + all_air_count = len(air) + all_lava_count = len(_cubes) + possible_count = (maxX+1)*(maxY+1)*(maxZ+1) + print("all_air: ", all_air_count) + print("all_lava:", all_lava_count) + print("possible:", possible_count) + print(maxZ,maxY,maxX) + print() + + air_nx = {} for a in air: neighbors = get_neighbors(*a) - if len(neighbors & _cubes)==6: - #print(a, "====", neighbors & _cubes) - potential -= 6 + air_nx[a] = { + 'lava':neighbors & _cubes or None, + 'air': neighbors & air or None + } - - # _ns = get_neighbors(x,y,z) - # lava_neighbors = _ns & _cubes - # if len(lava_neighbors) == 6: - # potential -= 6 - print(potential) - - - -# @shared.profile -def _part2(rows): - cubes = [] - - _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): + # loop row by row + inside = [] + for z in range(0,maxZ+1): + seen = set() + seen.add((0,0,z)) for y in range(0,maxY+1): - for z in range(0,maxZ+1): - lava_count = 0 - if (x,y,z) in _lava: + for x in range(0,maxX+1): + xyz = (x,y,z) + if xyz in _cubes: + #print(xyz,'is cube') continue + ns = get_flat_neighbors_from(x,y,z, air) + for neigh in ns: + if neigh in seen and neigh not in _cubes: + seen.add(xyz) + this_level = air_in_row(air, z) + print(this_level, seen) + print(len(this_level), len(seen)) + inside.extend([x for x in this_level if x not in seen]) + #print() + #print(inside) + #print() + actually_inside = [] + for i in inside: + ns = get_neighbors(*i) + # check for surrounded 100% by rock + rock_count = 0 + for n in ns: + if n in _cubes: + rock_count +=1 + if rock_count == 6: + print("in rock") + actually_inside.append(i) + continue + #check for surrounded 100% by air + air_count = 0 + for n in ns: + if n in air: + air_count +=1 + print("in air") + break + actually_inside.append(i) + #print(actually_inside) + tot, _, _, _, _, _ = surface_area(actually_inside) + print(tot) + print(potential - tot) + shared.render_cubes(maxX,maxY,maxZ, [x for x in actually_inside]) - # is air - air_touching_lava = False - for _n in _ns: - if _n in _lava: - lava_count += 1 - air_touching_lava = True +def air_in_row(air, z): + x = [] + for a in air: + if a[2] == z: + x.append(a) + return x - if air_touching_lava: - air.append((x,y,z)) - - if lava_count == 6: - potential -= 6 - - - print(potential, air) - def main(): diff --git a/2022/python/shared.py b/2022/python/shared.py index 0f7c2e6..3ad982a 100644 --- a/2022/python/shared.py +++ b/2022/python/shared.py @@ -102,3 +102,60 @@ def elapsed_timer(): yield lambda: elapser() end = default_timer() elapser = lambda: end - start + + + + +def render_cubes(maxX,maxY,maxZ, my_cubes): + from mpl_toolkits.mplot3d import Axes3D + import numpy as np + import matplotlib.pyplot as plt + from mpl_toolkits.mplot3d.art3d import Poly3DCollection + + def cuboid_data(o, size=(1,1,1)): + X = [[[0, 1, 0], [0, 0, 0], [1, 0, 0], [1, 1, 0]], + [[0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0]], + [[1, 0, 1], [1, 0, 0], [1, 1, 0], [1, 1, 1]], + [[0, 0, 1], [0, 0, 0], [0, 1, 0], [0, 1, 1]], + [[0, 1, 0], [0, 1, 1], [1, 1, 1], [1, 1, 0]], + [[0, 1, 1], [0, 0, 1], [1, 0, 1], [1, 1, 1]]] + X = np.array(X).astype(float) + for i in range(3): + X[:,:,i] *= size[i] + X += np.array(o) + return X + + def plotCubeAt(positions,sizes=None,colors=None, **kwargs): + if not isinstance(colors,(list,np.ndarray)): colors=["C0"]*len(positions) + if not isinstance(sizes,(list,np.ndarray)): sizes=[(1,1,1)]*len(positions) + g = [] + for p,s,c in zip(positions,sizes,colors): + g.append( cuboid_data(p, size=s) ) + return Poly3DCollection(np.concatenate(g), + facecolors=np.repeat(colors,6, axis=0), **kwargs) + + N1 = maxX + N2 = maxY + N3 = maxZ + ma = np.random.choice([0,1], size=(N1,N2,N3), p=[0.99, 0.01]) + x,y,z = np.indices((N1,N2,N3))-.5 + #positions = np.c_[x[ma==1],y[ma==1],z[ma==1]] + positions = np.c_[my_cubes] + colors= np.random.rand(len(positions),3) + + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + ax.set_aspect('equal') + + pc = plotCubeAt(positions, colors=colors,edgecolor="k") + ax.add_collection3d(pc) + + ax.set_xlim([0,maxX]) + ax.set_ylim([0,maxY]) + ax.set_zlim([0,maxZ]) + #plotMatrix(ax, ma) + #ax.voxels(ma, edgecolor="k") + + plt.show() + +