from contextlib import contextmanager from timeit import default_timer from pathlib import Path import cProfile import functools import pstats from itertools import groupby def all_equal(iterable): g = groupby(iterable) return next(g, True) and not next(g, False) def profile(func): @functools.wraps(func) def inner(*args, **kwargs): profiler = cProfile.Profile() profiler.enable() try: retval = func(*args, **kwargs) finally: profiler.disable() with open("profile.out", "w") as profile_file: stats = pstats.Stats(profiler, stream=profile_file) stats.print_stats() return retval return inner def spl(y): return [int(w) for w in y] def minmax(l): return min(l), max(l) def load_rows(day, part2=False): return [row for row in load(day, part2)] def load(day, part2=False): if part2: path = Path(get_fname(day) + ".part2") try: return path.read_text().rstrip().split("\n") except FileNotFoundError: # No part 2 file, use first file pass path = Path(get_fname(day)) return path.read_text().rstrip().split("\n") def get_fname(day: int) -> str: import sys if sys.argv[-1] == "--sample": return f"samples/day{day:02}.txt" else: return f"full/day{day:02}.txt" ############# def load_char_matrix(f): my_file = [] for line in f: my_file.append(line.rstrip()) return [list(x) for x in my_file] def load_file_char_matrix(name): with open(name, "r") as f: return load_char_matrix(f) def load_int_matrix(f): my_file = [] for line in f: my_file.append(line.rstrip()) return [list(map(int, x)) for x in my_file] def load_file_int_matrix(name): with open(name, "r") as f: return load_int_matrix(f) def load_word_matrix(f): my_file = [] for line in f: my_file.append(line.rstrip()) return [x.split(" ") for x in my_file] def load_file_word_matrix(name): with open(name, "r") as f: return load_word_matrix(f) ############# def rotate(WHAT, times=1): what = WHAT for x in range(times): what = list(zip(*what[::-1])) return what @contextmanager def elapsed_timer(): start = default_timer() elapser = lambda: default_timer() - start 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)) - 0.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()