animate.py
2.3 kB · python · 61 lines
1from mrlypy.two import Cell2d, carpet_2d2import mrlypy.tile3import numpy as np4import time5from typing import List6from .config import Config7from .enums import Boundary, Fate8from .helpers import logger9from .models import Life1011def get_next_grid(cell: Cell2d, birth: List[int], survive: List[int], mask: np.ndarray, mode: str = "constant") -> Cell2d:12 cell.neighbors(mask, target=1, mode=mode)13 neighbor_grid = cell.tags14 grid = cell.types15 birth_mask = np.isin(neighbor_grid, birth) & (grid == 0)16 survive_mask = np.isin(neighbor_grid, survive) & (grid == 1)17 next_grid = np.zeros_like(grid)18 next_grid[birth_mask | survive_mask] = 119 return Cell2d(types=next_grid)2021def animate(config: Config, grid: Cell2d = None, mask: Cell2d = None) -> Life:22 # SETUP23 if grid is None:24 tile = mrlypy.tile.create(config.tile)25 tile = mrlypy.tile.build(tile)26 grid = tile.cell27 if mask is None:28 mask = carpet_2d(3)29 current_grid = grid.copy()30 if config.grid_size and config.grid_size > 1:31 current_grid = current_grid.tile(config.grid_size, config.grid_size)32 # PAD33 if config.padding > 0:34 padded_types = np.pad(current_grid.types, pad_width=config.padding, mode='constant', constant_values=0)35 current_grid = Cell2d(types=padded_types)36 # ANIMATE37 grids = [current_grid.copy()]38 history = {current_grid.types.tobytes(): 0}39 fate = None40 loop = 041 start_time = time.time()42 i = 043 for i in range(1, config.max_generations):44 next_grid = get_next_grid(current_grid, config.birth_counts, config.survive_counts, mask.types, mode=config.boundary.value)45 if np.array_equal(current_grid.types, next_grid.types):46 fate = Fate.DEAD if np.sum(next_grid.types) == 0 else Fate.LIFE47 break48 grid_bytes = next_grid.types.tobytes()49 if grid_bytes in history:50 loop = i - history[grid_bytes]51 fate = Fate.LOOP52 break53 history[grid_bytes] = i54 current_grid = next_grid55 grids.append(current_grid.copy())56 logger.debug(f"Animated: {i}")57 elapsed = round(time.time() - start_time, 2)58 logger.info(f"Animated {i} generations in {elapsed}s")59 if not fate:60 fate = Fate.TIME61 return Life(grids=grids, fate=fate, count=len(grids), time=elapsed, loop=loop)