134 lines
4.0 KiB
Python
134 lines
4.0 KiB
Python
import sys
|
|
from matrix import load_matrix_file, get_neighbors, get_size
|
|
import shared
|
|
from scipy import ndimage
|
|
import imageio
|
|
from skimage.measure import euler_number, label
|
|
from skimage.morphology import flood_fill, flood
|
|
import matplotlib.pyplot as plt
|
|
import numpy as np
|
|
from math import prod
|
|
import random
|
|
|
|
|
|
class Smoke:
|
|
def __init__(self, name):
|
|
self.footprint = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
|
|
self.parse(name)
|
|
|
|
def parse(self, name):
|
|
_split = lambda line: list(map(int, [l for l in line]))
|
|
self.mx = np.array(load_matrix_file(name, func=_split))
|
|
self.mx = np.pad(self.mx, pad_width=1, mode="constant", constant_values="9")
|
|
self.set_values()
|
|
self.set_coords()
|
|
|
|
def set_values(self):
|
|
self.lows = (
|
|
ndimage.generic_filter(self.mx, np.min, footprint=self.footprint) == self.mx
|
|
)
|
|
self.low_values = self.mx[self.lows][self.mx[self.lows] < 9]
|
|
self.highs = (
|
|
ndimage.generic_filter(self.mx, np.max, footprint=self.footprint) == self.mx
|
|
)
|
|
mask = self.mx != 9
|
|
self.mask = mask.astype(int)
|
|
|
|
def set_coords(self):
|
|
lc = []
|
|
for idr, row in enumerate(self.lows):
|
|
if idr == 0 or idr == len(self.lows) - 1:
|
|
continue
|
|
for idc, col in enumerate(row):
|
|
if idc == 0 or idc == len(row) - 1:
|
|
continue
|
|
if col:
|
|
lc.append((idr, idc))
|
|
self.low_coords = lc
|
|
|
|
def total_low_values(self):
|
|
return (self.low_values + 1).sum()
|
|
|
|
def find_chunks(self):
|
|
cell_sizes = []
|
|
self.cells = []
|
|
by_center = []
|
|
for x, y in self.low_coords:
|
|
current = np.zeros_like(self.mx)
|
|
m = flood_fill(self.mask, (x, y), -1, connectivity=1)
|
|
current_cell = (m == -1).astype(int)
|
|
self.cells.append(current_cell)
|
|
cells = np.argwhere(current_cell == 1)
|
|
by_center.append((len(cells), (x, y), cells))
|
|
cell_sizes.append(len(cells))
|
|
cells_sorted = list(set(sorted(cell_sizes)))
|
|
self.by_center = by_center
|
|
largest = cells_sorted[-3:]
|
|
assert len(largest) == 3
|
|
self.largest = largest
|
|
return prod(largest)
|
|
|
|
def animate(self, save=False):
|
|
breakpoint()
|
|
largest = [x for x in self.by_center if x[0] in self.largest][-3:]
|
|
current = np.zeros_like(self.mx)
|
|
shuf = self.by_center[:]
|
|
random.shuffle(shuf)
|
|
|
|
last_file = 0
|
|
|
|
for idx, (length, xy, c) in enumerate(shuf):
|
|
last_file = idx
|
|
if length in largest:
|
|
continue
|
|
|
|
for x, y in c:
|
|
current[y][x] = 1
|
|
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(current, cmap=plt.cm.gray)
|
|
ax.axis("off")
|
|
if save:
|
|
plt.savefig(f"09/{idx:03}.png")
|
|
plt.close()
|
|
|
|
lg = np.zeros_like(self.mx)
|
|
for _, _, c in largest:
|
|
for x, y in c:
|
|
lg[y][x] = 1
|
|
|
|
fig, ax = plt.subplots()
|
|
ax.imshow(lg)
|
|
ax.axis("off")
|
|
plt.savefig(f"09/largest.png")
|
|
plt.close()
|
|
|
|
with imageio.get_writer("09/day09.gif", mode="I") as writer:
|
|
names = [f"09/{x:03}.png" for x in range(334)]
|
|
for filename in names:
|
|
try:
|
|
image = imageio.imread(filename)
|
|
writer.append_data(image)
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
for x in range(15):
|
|
image = imageio.imread("09/largest.png")
|
|
for x in range(5):
|
|
writer.append_data(image)
|
|
image = imageio.imread(f"09/{last_file:03}.png")
|
|
for x in range(5):
|
|
writer.append_data(image)
|
|
|
|
|
|
def main():
|
|
s = Smoke(shared.get_fname(9))
|
|
print(s.total_low_values())
|
|
print(s.find_chunks())
|
|
if sys.argv[-1] != "--sample":
|
|
s.animate(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|