game.py
6.7 kB · python · 208 lines
1import os2import sys34# MRLYPROD56HERE = os.path.dirname(os.path.abspath(__file__))7MRLYPROD = os.path.normpath(os.path.join(HERE, ".."))89if not os.path.isdir(os.path.join(MRLYPROD, "mrlypy", "six")):10 sys.exit(f"missing mrlypy: expected it at {MRLYPROD}")1112sys.path.insert(0, MRLYPROD)1314import math15import mrlypy.two as m216import mrlypy.three as m317import mrlypy.six as m618from mrlypy.core.colors import black, blue, gradient, gray, white19from mrlypy.core.enums import Mode20import numpy as np21from colors import *22from config import DATA_DIR23from PIL import Image2425ORIENTATION = "landscape"26FRAME_SIZES = {27 "portrait": (1080, 1920),28 "landscape": (1920, 1080),29 "square": (1080, 1080),30}31IMAGE_SIZE = FRAME_SIZES[ORIENTATION]32SCALE = 103334GENERATIONS = 2535BIRTH_RULE = [2, 4, 6, 8]36SURVIVE_RULE = [2, 4, 6, 8]37TARGET = 138START = 03940KEY = "test"41os.makedirs(f"{DATA_DIR}/{KEY}", exist_ok=True)4243def save_gif(images: list[Image.Image], title: str):44 if not images:45 return46 fp = f"{DATA_DIR}/{KEY}/{title}.gif"47 images[0].save(fp, save_all=True, append_images=images[1:], duration=200, loop=0)48 print(f"Saved: {fp}")4950class Renderer:5152 def __init__(self, target_size):53 self.target_width, self.target_height = target_size5455 def render(self, cell):56 tile_img = m6.rect_draw(cell, scale=SCALE, start=START)57 ratio = math.sqrt(3) / 258 w, h = tile_img.size59 orientation = m6.get_orientation(cell.width, cell.height)60 match orientation:61 case m6.Orientation.HORIZONTAL:62 new_h = int(h * ratio)63 tile_img = tile_img.resize((w, new_h), Image.Resampling.NEAREST)64 case m6.Orientation.VERTICAL:65 new_w = int(w * ratio)66 tile_img = tile_img.resize((new_w, h), Image.Resampling.NEAREST)67 tile_arr = np.array(tile_img)68 h, w, _ = tile_arr.shape69 target_h, target_w = self.target_height, self.target_width70 if h > target_h:71 start_y = (h - target_h) // 272 tile_arr = tile_arr[start_y:start_y+target_h, :, :]73 h = target_h74 if w > target_w:75 start_x = (w - target_w) // 276 tile_arr = tile_arr[:, start_x:start_x+target_w, :]77 w = target_w78 pad_h = max(0, target_h - h)79 pad_w = max(0, target_w - w)80 pad_top = (pad_h + 1) // 281 pad_bottom = pad_h - pad_top82 pad_left = (pad_w + 1) // 283 pad_right = pad_w - pad_left84 if pad_h > 0 or pad_w > 0:85 tile_arr = np.pad(86 tile_arr,87 ((pad_top, pad_bottom), (pad_left, pad_right), (0, 0)),88 mode='reflect'89 )90 return Image.fromarray(tile_arr)9192def print_cell(cell: m2.Cell2d):93 mapping = {0: "⬜️", 1: "⬛️", 2: "🟦", 3: "🟥", 4: "🟩", 5: "🟪"}94 for row in cell.text(mapping):95 print(row)96 print()9798def new_cell():99 cell = m3.net_3d(3, 2)100 cell = m6.cut(cell)101 return cell.cell102103def new_mask():104 cell = m2.carpet_2d(3, 1)105 return cell.types106107def animate() -> list[m2.Cell2d]:108 cell = new_cell()109 mask = new_mask()110 grids = [cell.copy()]111 current_cell = cell112 for i in range(GENERATIONS):113 print(f"Generation: {i+1}")114 current_cell.neighbors(types=mask, target=TARGET, mode='constant')115 neighbors = current_cell.tags116 current_grid = current_cell.types117 birth_mask = (current_grid == 0) & (np.isin(neighbors, BIRTH_RULE))118 survive_mask = (current_grid == 1) & (np.isin(neighbors, SURVIVE_RULE))119 new_grid = np.zeros_like(current_grid)120 new_grid[birth_mask | survive_mask] = 1121 boundary_mask = (current_grid == 2)122 new_grid[boundary_mask] = 2123 current_cell.types = new_grid124 grids.append(current_cell.copy())125 return grids126127def frames(grids: list[m2.Cell2d]):128 title = "frames"129 os.makedirs(f"{DATA_DIR}/{KEY}/{title}", exist_ok=True)130 renderer = Renderer(IMAGE_SIZE)131 images = []132 gradient_colors = gradient([random_secondary(), random_secondary()], steps=5)133 mapping = {0: [white], 1: gradient_colors, 2: [alpha]}134 for i, grid in enumerate(grids):135 grid.paint(mapping, mode=Mode.RANDOM)136 img = renderer.render(grid)137 fp = f"{DATA_DIR}/{KEY}/{title}/frame_{i:02d}.png"138 img.save(fp)139 print(f"Saved: {fp}")140 images.append(img)141 save_gif(images, title)142143def heatmap(grids: list[m2.Cell2d]):144 title = "heatmap"145 os.makedirs(f"{DATA_DIR}/{KEY}/{title}", exist_ok=True)146 renderer = Renderer(IMAGE_SIZE)147 images = []148 all_types = [g.types for g in grids]149 ones_stack = [(t == 1).astype(int) for t in all_types]150 total_cumulative = np.sum(ones_stack, axis=0)151 max_val = int(np.max(total_cumulative))152 if max_val < 1: max_val = 1153 start_color = gray154 end_color = black155 gradient_colors = gradient([start_color, end_color], steps=max_val + 1)156 gradient_rgba = np.array([c.to_rgba() for c in gradient_colors], dtype=np.uint8)157 cumulative_grid = np.zeros_like(grids[0].types, dtype=np.int32)158 boundary_color = blue.to_rgba()159 background_color = white.to_rgba()160 for i, grid in enumerate(grids):161 cumulative_grid += (grid.types == 1).astype(np.int32)162 height, width = grid.height, grid.width163 colors = np.full((height, width, 4), background_color, dtype=np.uint8)164 boundary_mask = (grid.types == 2)165 colors[boundary_mask] = boundary_color166 heat_mask = (cumulative_grid > 0) & (~boundary_mask)167 heat_values = cumulative_grid[heat_mask]168 colors[heat_mask] = gradient_rgba[heat_values]169 hm_cell = grid.copy()170 hm_cell.colors = colors171 img = renderer.render(hm_cell)172 fp = f"{DATA_DIR}/{KEY}/{title}/heatmap_{i:02d}.png"173 img.save(fp)174 print(f"Saved: {fp}")175 images.append(img)176 save_gif(images, title)177178def main():179 grids = animate()180 frames(grids)181 heatmap(grids)182183def test_pad():184 cell = m3.carpet_3d(3, 1)185 cell = m6.iso(cell)186 print("ISO")187 for i in range(20):188 test_cell = cell.copy()189 test_cell = m6.pad(test_cell, k=i)190 print(f"Pad: {i}")191 print(f"Width: {test_cell.width}")192 print(f"Height: {test_cell.height}")193 print(f"Is_hex: {m6.is_hex(test_cell)}")194 print_cell(test_cell)195196def test_blank():197 orientation = "vertical"198 for i in range(1, 20):199 test_cell = m6.blank(i, orientation)200 print(f"Orientation: {orientation}")201 print(f"Radius: {i}")202 print(f"Width: {test_cell.width}")203 print(f"Height: {test_cell.height}")204 print(f"Is_hex: {m6.is_hex(test_cell)}")205 print_cell(test_cell)206207if __name__ == "__main__":208 main()