Guest User

Untitled

a guest
Jan 29th, 2026
36
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.27 KB | None | 0 0
  1. import numpy as np
  2. from numba import cuda
  3. import pygame
  4. import random
  5. import time
  6.  
  7. # ====================== META DECAY RULE ======================
  8. RULE_TRIGGERING_NEIGHBORS = [1, 1, 1, 1, 1, 1, 1, 1, 1]
  9.  
  10. # ====================== TWEAKABLE PARAMETERS ======================
  11. GRID_WIDTH = 1920
  12. GRID_HEIGHT = 1080
  13. MAX_VALUE = 20
  14. CIRCLE_RADIUS = 180
  15. CIRCLE_INTENSITY = MAX_VALUE
  16. FALLOFF_EXPONENT = 1.6
  17. NOISE_DENSITY = 0.002
  18.  
  19. MAX_POSSIBLE_SUM = MAX_VALUE * 8
  20.  
  21. # ── Classic rule counts ──────────────────────────────────────────
  22. RANDOM_RULE_COUNT_MIN_IGNITE = [0, 2, 2, 2, 0, 0, 0, 0]
  23. RANDOM_RULE_COUNT_MAX_IGNITE = [0, 2, 2, 2, 0, 0, 0, 0]
  24. RANDOM_RULE_COUNT_MIN_KILL = [0, 6, 6, 6, 0, 0, 0, 0]
  25. RANDOM_RULE_COUNT_MAX_KILL = [0, 6, 6, 6, 0, 0, 0, 0]
  26. RANDOM_RULE_COUNT_MIN_SURVIVE = [0, 0, 0, 0, 0, 0, 0, 0]
  27. RANDOM_RULE_COUNT_MAX_SURVIVE = [0, 0, 0, 0, 0, 0, 0, 0]
  28.  
  29. DEFAULT_NUM_IGNITES = [2, 3, 4, 5, 6, 6, 7, 7]
  30. DEFAULT_NUM_KILLS = [3, 4, 5, 6, 8, 10, 12, 16]
  31. DEFAULT_NUM_SURVIVES = [0, 0, 1, 2, 2, 3, 3, 4]
  32.  
  33. # ── Neighbor-based rules ─────────────────────────────────────────
  34. DEFAULT_NUM_NEIGHBOR_IGNITES = [1, 1, 1, 1, 1, 1, 1, 1]
  35. DEFAULT_NUM_NEIGHBOR_KILLS = [0, 1, 0, 1, 0, 1, 0, 1] # example: sparse kills
  36.  
  37. RANDOM_RULE_COUNT_MIN_NEIGHBOR_IGNITE = [2] * 8
  38. RANDOM_RULE_COUNT_MAX_NEIGHBOR_IGNITE = [2] * 8
  39. RANDOM_RULE_COUNT_MIN_NEIGHBOR_KILL = [6] * 8
  40. RANDOM_RULE_COUNT_MAX_NEIGHBOR_KILL = [6] * 8
  41.  
  42. # ── Initial rule generation ──────────────────────────────────────
  43. random.seed()
  44. initial_random_state = random.getstate()
  45.  
  46. current_num_ignites = DEFAULT_NUM_IGNITES.copy()
  47. current_num_kills = DEFAULT_NUM_KILLS.copy()
  48. current_num_survives = DEFAULT_NUM_SURVIVES.copy()
  49. current_num_neighbor_ignites = DEFAULT_NUM_NEIGHBOR_IGNITES.copy()
  50. current_num_neighbor_kills = DEFAULT_NUM_NEIGHBOR_KILLS.copy()
  51.  
  52. def generate_random_rules(num_ignites, num_kills, num_survives):
  53. ignition_sums = [[] for _ in range(9)]
  54. kill_sums = [[] for _ in range(9)]
  55. survive_sums = [[] for _ in range(9)]
  56.  
  57. for n in range(1, 9):
  58. min_sum = n
  59. max_sum = n * MAX_VALUE
  60. all_possible = list(range(min_sum, max_sum + 1))
  61. possible_count = len(all_possible)
  62.  
  63. num_i = num_ignites[n-1]
  64. num_k = num_kills[n-1]
  65. num_s = num_survives[n-1]
  66. total = num_i + num_k + num_s
  67.  
  68. if total == 0:
  69. continue
  70. if total > possible_count:
  71. ratio = possible_count / total
  72. num_i = max(0, int(num_i * ratio))
  73. num_k = max(0, int(num_k * ratio))
  74. num_s = max(0, int(num_s * ratio))
  75. total = num_i + num_k + num_s
  76.  
  77. if total == 0:
  78. continue
  79.  
  80. chosen = random.sample(all_possible, total)
  81. ignition_sums[n] = sorted(chosen[:num_i])
  82. kill_sums[n] = sorted(chosen[num_i:num_i + num_k])
  83. survive_sums[n] = sorted(chosen[num_i + num_k:])
  84.  
  85. return ignition_sums, kill_sums, survive_sums
  86.  
  87.  
  88. def generate_neighbor_conditions(num_per_dir):
  89. conditions = [[] for _ in range(8)]
  90. for dir_idx in range(8):
  91. num = num_per_dir[dir_idx]
  92. if num == 0:
  93. continue
  94. possible = [(cv, ss) for cv in range(MAX_VALUE + 1) for ss in range(MAX_POSSIBLE_SUM + 1)]
  95. selected = random.sample(possible, min(num, len(possible)))
  96. conditions[dir_idx] = selected
  97. return conditions
  98.  
  99.  
  100. IGNITION_SUMS, KILL_SUMS, SURVIVE_SUMS = generate_random_rules(
  101. current_num_ignites, current_num_kills, current_num_survives
  102. )
  103. NEIGHBOR_IGNITE_CONDITIONS = generate_neighbor_conditions(current_num_neighbor_ignites)
  104. NEIGHBOR_KILL_CONDITIONS = generate_neighbor_conditions(current_num_neighbor_kills)
  105.  
  106. # Lookup tables
  107. ignition_lookup = np.zeros((9, MAX_POSSIBLE_SUM + 1), dtype=bool)
  108. kill_lookup = np.zeros((9, MAX_POSSIBLE_SUM + 1), dtype=bool)
  109. survive_lookup = np.zeros((9, MAX_POSSIBLE_SUM + 1), dtype=bool)
  110. neighbor_ignite_lookup = np.zeros((8, MAX_VALUE + 1, MAX_POSSIBLE_SUM + 1), dtype=bool)
  111. neighbor_kill_lookup = np.zeros((8, MAX_VALUE + 1, MAX_POSSIBLE_SUM + 1), dtype=bool)
  112.  
  113. d_meta_rule = cuda.to_device(np.array(RULE_TRIGGERING_NEIGHBORS, dtype=np.int32))
  114.  
  115. def update_lookups():
  116. global d_ignition_lookup, d_kill_lookup, d_survive_lookup
  117. global d_neighbor_ignite_lookup, d_neighbor_kill_lookup
  118.  
  119. ignition_lookup.fill(False)
  120. kill_lookup.fill(False)
  121. survive_lookup.fill(False)
  122. neighbor_ignite_lookup.fill(False)
  123. neighbor_kill_lookup.fill(False)
  124.  
  125. for n in range(1, 9):
  126. for s in IGNITION_SUMS[n]: ignition_lookup[n, s] = True
  127. for s in KILL_SUMS[n]: kill_lookup[n, s] = True
  128. for s in SURVIVE_SUMS[n]: survive_lookup[n, s] = True
  129.  
  130. for dir_idx in range(8):
  131. for cv, ss in NEIGHBOR_IGNITE_CONDITIONS[dir_idx]:
  132. neighbor_ignite_lookup[dir_idx, cv, ss] = True
  133. for cv, ss in NEIGHBOR_KILL_CONDITIONS[dir_idx]:
  134. neighbor_kill_lookup[dir_idx, cv, ss] = True
  135.  
  136. d_ignition_lookup = cuda.to_device(ignition_lookup)
  137. d_kill_lookup = cuda.to_device(kill_lookup)
  138. d_survive_lookup = cuda.to_device(survive_lookup)
  139. d_neighbor_ignite_lookup = cuda.to_device(neighbor_ignite_lookup)
  140. d_neighbor_kill_lookup = cuda.to_device(neighbor_kill_lookup)
  141.  
  142. update_lookups()
  143.  
  144. # ====================== CUDA SETUP ======================
  145. ZOOM_LEVELS = [1, 4, 9, 16, 25]
  146. current_zoom_idx = 0
  147. pixels_per_cell = ZOOM_LEVELS[current_zoom_idx]
  148.  
  149. viewport_x_float = 0.0
  150. viewport_y_float = 0.0
  151. viewport_x = 0
  152. viewport_y = 0
  153.  
  154. dragging = False
  155. last_mouse_pos = (0, 0)
  156.  
  157. d_current = cuda.device_array((GRID_HEIGHT, GRID_WIDTH), dtype=np.uint16)
  158. d_next = cuda.device_array((GRID_HEIGHT, GRID_WIDTH), dtype=np.uint16)
  159. d_visible = cuda.device_array((GRID_HEIGHT, GRID_WIDTH, 3), dtype=np.uint8)
  160.  
  161. SCALE_FACTOR = 255.0 / MAX_VALUE
  162. d_scale_factor = cuda.to_device(np.array([SCALE_FACTOR], dtype=np.float32))
  163.  
  164. threads_per_block = (16, 16)
  165. blocks = ((GRID_HEIGHT + 15) // 16, (GRID_WIDTH + 15) // 16)
  166.  
  167. meta_enabled = True
  168. neighbor_ignite_enabled = True
  169. neighbor_kill_enabled = True
  170.  
  171. @cuda.jit
  172. def update_kernel(current, next_state,
  173. ignition_lookup, kill_lookup, survive_lookup,
  174. meta_rule, max_val, meta_enabled,
  175. neighbor_ignite_lookup, neighbor_ignite_enabled,
  176. neighbor_kill_lookup, neighbor_kill_enabled):
  177. i, j = cuda.grid(2)
  178. if i >= current.shape[0] or j >= current.shape[1]:
  179. return
  180.  
  181. neighbor_sum = 0
  182. living_count = 0
  183. for di in range(-1, 2):
  184. for dj in range(-1, 2):
  185. if di == 0 and dj == 0:
  186. continue
  187. ni = (i + di) % current.shape[0]
  188. nj = (j + dj) % current.shape[1]
  189. val = current[ni, nj]
  190. neighbor_sum += val
  191. if val > 0:
  192. living_count += 1
  193.  
  194. # Meta decay calculation
  195. rule_triggering_neighbors = 0
  196. if meta_enabled:
  197. for di in range(-1, 2):
  198. for dj in range(-1, 2):
  199. if di == 0 and dj == 0:
  200. continue
  201. ni = (i + di) % current.shape[0]
  202. nj = (j + dj) % current.shape[1]
  203.  
  204. nn_sum = 0
  205. nn_living = 0
  206. for ddi in range(-1, 2):
  207. for ddj in range(-1, 2):
  208. if ddi == 0 and ddj == 0:
  209. continue
  210. nni = (ni + ddi) % current.shape[0]
  211. nnj = (nj + ddj) % current.shape[1]
  212. v = current[nni, nnj]
  213. nn_sum += v
  214. if v > 0:
  215. nn_living += 1
  216.  
  217. if ignition_lookup[nn_living, nn_sum] or kill_lookup[nn_living, nn_sum]:
  218. rule_triggering_neighbors += 1
  219.  
  220. this_cell_decay = 1
  221. if meta_enabled:
  222. idx = min(rule_triggering_neighbors, meta_rule.shape[0] - 1)
  223. this_cell_decay = meta_rule[idx]
  224.  
  225. val = current[i, j]
  226.  
  227. # Neighbor ignition check
  228. ignited_by_neighbor = False
  229. if neighbor_ignite_enabled:
  230. dir_idx = 0
  231. for di in [-1,0,1]:
  232. for dj in [-1,0,1]:
  233. if di == 0 and dj == 0:
  234. continue
  235. ni = (i + di) % current.shape[0]
  236. nj = (j + dj) % current.shape[1]
  237.  
  238. second_sum = 0
  239. for ddi in [-1,0,1]:
  240. for ddj in [-1,0,1]:
  241. if ddi == 0 and ddj == 0:
  242. continue
  243. nni = (ni + ddi) % current.shape[0]
  244. nnj = (nj + ddj) % current.shape[1]
  245. second_sum += current[nni, nnj]
  246.  
  247. if second_sum < neighbor_ignite_lookup.shape[2]:
  248. if neighbor_ignite_lookup[dir_idx, val, second_sum]:
  249. ignited_by_neighbor = True
  250. dir_idx += 1
  251.  
  252. # Neighbor kill check
  253. killed_by_neighbor = False
  254. if neighbor_kill_enabled:
  255. dir_idx = 0
  256. for di in [-1,0,1]:
  257. for dj in [-1,0,1]:
  258. if di == 0 and dj == 0:
  259. continue
  260. ni = (i + di) % current.shape[0]
  261. nj = (j + dj) % current.shape[1]
  262.  
  263. second_sum = 0
  264. for ddi in [-1,0,1]:
  265. for ddj in [-1,0,1]:
  266. if ddi == 0 and ddj == 0:
  267. continue
  268. nni = (ni + ddi) % current.shape[0]
  269. nnj = (nj + ddj) % current.shape[1]
  270. second_sum += current[nni, nnj]
  271.  
  272. if second_sum < neighbor_kill_lookup.shape[2]:
  273. if neighbor_kill_lookup[dir_idx, val, second_sum]:
  274. killed_by_neighbor = True
  275. dir_idx += 1
  276.  
  277. # Final decision (order: neighbor ignite > neighbor kill > classic rules)
  278. if ignited_by_neighbor:
  279. next_state[i, j] = max_val
  280. elif killed_by_neighbor:
  281. next_state[i, j] = 0
  282. elif ignition_lookup[living_count, neighbor_sum]:
  283. next_state[i, j] = max_val
  284. elif kill_lookup[living_count, neighbor_sum]:
  285. next_state[i, j] = 0
  286. elif survive_lookup[living_count, neighbor_sum]:
  287. next_state[i, j] = val
  288. else:
  289. next_state[i, j] = max(0, val - this_cell_decay)
  290.  
  291.  
  292. @cuda.jit
  293. def render_kernel(green, rgb, scale_factor_array):
  294. i, j = cuda.grid(2)
  295. if i < green.shape[0] and j < green.shape[1]:
  296. v = green[i, j]
  297. scaled = int(v * scale_factor_array[0] + 0.5)
  298. scaled = min(255, max(0, scaled))
  299. rgb[i, j, 0] = 0
  300. rgb[i, j, 1] = scaled
  301. rgb[i, j, 2] = 0
  302.  
  303.  
  304. # ── Grid seeding ─────────────────────────────────────────────────
  305. def create_centered_circle():
  306. np.random.seed(42)
  307. y, x = np.ogrid[:GRID_HEIGHT, :GRID_WIDTH]
  308. dist = np.sqrt((x - GRID_WIDTH//2)**2 + (y - GRID_HEIGHT//2)**2)
  309. falloff = np.clip(1 - dist / CIRCLE_RADIUS, 0, 1)
  310. return (falloff ** FALLOFF_EXPONENT * CIRCLE_INTENSITY).astype(np.uint16)
  311.  
  312.  
  313. def create_noise_seed(density=NOISE_DENSITY):
  314. grid = np.zeros((GRID_HEIGHT, GRID_WIDTH), dtype=np.uint16)
  315. avg_cluster_size = 5.0
  316. num_clusters = int(GRID_HEIGHT * GRID_WIDTH * density / avg_cluster_size)
  317. possible_rows = np.arange(1, GRID_HEIGHT - 1)
  318. possible_cols = np.arange(1, GRID_WIDTH - 1)
  319. num_possible = len(possible_rows) * len(possible_cols)
  320. indices = np.random.choice(num_possible, num_clusters, replace=False)
  321. centers_rows = possible_rows[indices // len(possible_cols)]
  322. centers_cols = possible_cols[indices % len(possible_cols)]
  323. deltas = np.array([[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]])
  324. for clus in range(num_clusters):
  325. cr = centers_rows[clus]
  326. cc = centers_cols[clus]
  327. k = np.random.randint(0, 9)
  328. grid[cr, cc] = np.random.randint(1, MAX_VALUE + 1)
  329. if k > 0:
  330. delta_idx = np.random.choice(8, k, replace=False)
  331. for dr, dc in deltas[delta_idx]:
  332. grid[cr + dr, cc + dc] = np.random.randint(1, MAX_VALUE + 1)
  333. return grid
  334.  
  335.  
  336. # Initial seed
  337. d_current.copy_to_device(create_centered_circle())
  338.  
  339. noise_mode = False
  340.  
  341. # ── Main loop ────────────────────────────────────────────────────
  342. pygame.init()
  343. screen = pygame.display.set_mode((GRID_WIDTH, GRID_HEIGHT), pygame.RESIZABLE)
  344. pygame.display.set_caption("Ignition Sim – Neighbor Ignite & Kill")
  345. clock = pygame.time.Clock()
  346. small_font = pygame.font.SysFont("consolas", 24)
  347.  
  348. rule_flash_frames = 0
  349. MAX_FLASH_FRAMES = 90
  350.  
  351. running = True
  352.  
  353. while running:
  354. mouse_x, mouse_y = pygame.mouse.get_pos()
  355.  
  356. for event in pygame.event.get():
  357. if event.type == pygame.QUIT:
  358. running = False
  359.  
  360. elif event.type == pygame.MOUSEBUTTONDOWN:
  361. if event.button == 1 and pixels_per_cell > 1:
  362. dragging = True
  363. last_mouse_pos = event.pos
  364.  
  365. elif event.type == pygame.MOUSEBUTTONUP:
  366. if event.button == 1:
  367. dragging = False
  368.  
  369. elif event.type == pygame.MOUSEMOTION:
  370. if dragging:
  371. dx = event.pos[0] - last_mouse_pos[0]
  372. dy = event.pos[1] - last_mouse_pos[1]
  373. viewport_x_float -= dx / pixels_per_cell
  374. viewport_y_float -= dy / pixels_per_cell
  375. view_w = GRID_WIDTH // pixels_per_cell
  376. view_h = GRID_HEIGHT // pixels_per_cell
  377. viewport_x_float = max(0, min(viewport_x_float, GRID_WIDTH - view_w))
  378. viewport_y_float = max(0, min(viewport_y_float, GRID_HEIGHT - view_h))
  379. viewport_x = int(viewport_x_float)
  380. viewport_y = int(viewport_y_float)
  381. last_mouse_pos = event.pos
  382.  
  383. elif event.type == pygame.MOUSEWHEEL:
  384. if event.y != 0:
  385. old_ppc = pixels_per_cell
  386. if event.y > 0:
  387. current_zoom_idx = min(current_zoom_idx + 1, len(ZOOM_LEVELS) - 1)
  388. else:
  389. current_zoom_idx = max(current_zoom_idx - 1, 0)
  390. pixels_per_cell = ZOOM_LEVELS[current_zoom_idx]
  391. if pixels_per_cell != old_ppc:
  392. world_x = viewport_x_float + mouse_x / old_ppc
  393. world_y = viewport_y_float + mouse_y / old_ppc
  394. viewport_x_float = world_x - mouse_x / pixels_per_cell
  395. viewport_y_float = world_y - mouse_y / pixels_per_cell
  396. view_w = GRID_WIDTH // pixels_per_cell
  397. view_h = GRID_HEIGHT // pixels_per_cell
  398. viewport_x_float = max(0, min(viewport_x_float, GRID_WIDTH - view_w))
  399. viewport_y_float = max(0, min(viewport_y_float, GRID_HEIGHT - view_h))
  400. viewport_x = int(viewport_x_float)
  401. viewport_y = int(viewport_y_float)
  402.  
  403. elif event.type == pygame.KEYDOWN:
  404. if event.key == pygame.K_r:
  405. d_current.copy_to_device(create_noise_seed() if noise_mode else create_centered_circle())
  406. elif event.key == pygame.K_g:
  407. seed = time.time_ns()
  408. random.seed(seed)
  409. IGNITION_SUMS, KILL_SUMS, SURVIVE_SUMS = generate_random_rules(
  410. current_num_ignites, current_num_kills, current_num_survives)
  411. NEIGHBOR_IGNITE_CONDITIONS = generate_neighbor_conditions(current_num_neighbor_ignites)
  412. NEIGHBOR_KILL_CONDITIONS = generate_neighbor_conditions(current_num_neighbor_kills)
  413. update_lookups()
  414. rule_flash_frames = MAX_FLASH_FRAMES
  415. elif event.key == pygame.K_n:
  416. noise_mode = not noise_mode
  417. d_current.copy_to_device(create_noise_seed() if noise_mode else create_centered_circle())
  418. elif event.key == pygame.K_q:
  419. random.seed()
  420. current_num_ignites = [random.randint(RANDOM_RULE_COUNT_MIN_IGNITE[i], RANDOM_RULE_COUNT_MAX_IGNITE[i]) for i in range(8)]
  421. current_num_kills = [random.randint(RANDOM_RULE_COUNT_MIN_KILL[i], RANDOM_RULE_COUNT_MAX_KILL[i]) for i in range(8)]
  422. current_num_survives = [random.randint(RANDOM_RULE_COUNT_MIN_SURVIVE[i], RANDOM_RULE_COUNT_MAX_SURVIVE[i]) for i in range(8)]
  423. current_num_neighbor_ignites = [random.randint(RANDOM_RULE_COUNT_MIN_NEIGHBOR_IGNITE[i], RANDOM_RULE_COUNT_MAX_NEIGHBOR_IGNITE[i]) for i in range(8)]
  424. current_num_neighbor_kills = [random.randint(RANDOM_RULE_COUNT_MIN_NEIGHBOR_KILL[i], RANDOM_RULE_COUNT_MAX_NEIGHBOR_KILL[i]) for i in range(8)]
  425. IGNITION_SUMS, KILL_SUMS, SURVIVE_SUMS = generate_random_rules(
  426. current_num_ignites, current_num_kills, current_num_survives)
  427. NEIGHBOR_IGNITE_CONDITIONS = generate_neighbor_conditions(current_num_neighbor_ignites)
  428. NEIGHBOR_KILL_CONDITIONS = generate_neighbor_conditions(current_num_neighbor_kills)
  429. update_lookups()
  430. rule_flash_frames = MAX_FLASH_FRAMES
  431. elif event.key == pygame.K_d:
  432. meta_enabled = not meta_enabled
  433. print("Meta decay enabled:", meta_enabled)
  434. elif event.key == pygame.K_h:
  435. neighbor_ignite_enabled = not neighbor_ignite_enabled
  436. print("Neighbor ignite enabled:", neighbor_ignite_enabled)
  437. elif event.key == pygame.K_j:
  438. neighbor_kill_enabled = not neighbor_kill_enabled
  439. print("Neighbor kill enabled:", neighbor_kill_enabled)
  440. elif event.key == pygame.K_p:
  441. print("Meta decay rule: ", RULE_TRIGGERING_NEIGHBORS)
  442. print("Ignite counts: ", current_num_ignites)
  443. print("Kill counts: ", current_num_kills)
  444. print("Survive counts: ", current_num_survives)
  445. print("Neighbor ignite counts: ", current_num_neighbor_ignites)
  446. print("Neighbor kill counts: ", current_num_neighbor_kills)
  447. elif event.key == pygame.K_ESCAPE:
  448. running = False
  449.  
  450. # Simulation step
  451. update_kernel[blocks, threads_per_block](
  452. d_current, d_next,
  453. d_ignition_lookup, d_kill_lookup, d_survive_lookup,
  454. d_meta_rule, MAX_VALUE, meta_enabled,
  455. d_neighbor_ignite_lookup, neighbor_ignite_enabled,
  456. d_neighbor_kill_lookup, neighbor_kill_enabled
  457. )
  458. d_current, d_next = d_next, d_current
  459.  
  460. render_kernel[blocks, threads_per_block](d_current, d_visible, d_scale_factor)
  461. host_rgb = d_visible.copy_to_host()
  462.  
  463. # Extract visible portion
  464. step = pixels_per_cell
  465. view_h = GRID_HEIGHT // step
  466. view_w = GRID_WIDTH // step
  467.  
  468. y_start = viewport_y
  469. y_end = min(viewport_y + view_h, GRID_HEIGHT)
  470. x_start = viewport_x
  471. x_end = min(viewport_x + view_w, GRID_WIDTH)
  472.  
  473. view = host_rgb[y_start:y_end, x_start:x_end, :]
  474.  
  475. if view.shape[0] < view_h or view.shape[1] < view_w:
  476. padded = np.zeros((view_h, view_w, 3), dtype=np.uint8)
  477. padded[:view.shape[0], :view.shape[1]] = view
  478. view = padded
  479.  
  480. upscaled = np.repeat(np.repeat(view, step, axis=0), step, axis=1)
  481. upscaled = upscaled[:GRID_HEIGHT, :GRID_WIDTH, :]
  482.  
  483. surf = pygame.surfarray.make_surface(np.swapaxes(upscaled, 0, 1))
  484. screen.blit(surf, (0, 0))
  485.  
  486. # UI
  487. y_pos = 20
  488.  
  489. if rule_flash_frames > 0:
  490. screen.blit(small_font.render("RULES CHANGED!", True, (255,120,255)), (20, y_pos))
  491. rule_flash_frames -= 1
  492.  
  493. pygame.display.flip()
  494. clock.tick(60)
  495.  
  496. pygame.quit()
Advertisement
Add Comment
Please, Sign In to add comment