2019-02-23 19:38:37 +00:00
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
CELL_IS_ALIVE = 0b1
|
|
|
|
CELL_WILL_BE_ALIVE = 0b10
|
|
|
|
CELL_WILL_BE_DEAD = 0b100
|
|
|
|
|
|
|
|
def is_alive(model, i, j):
|
|
|
|
return model[i][j] & CELL_IS_ALIVE
|
|
|
|
|
|
|
|
def get_cells_around(model, i, j):
|
|
|
|
# Most common case. Handle this first.
|
|
|
|
# Fortunately the most common case is also the fastets to handle.
|
|
|
|
if(i > 2 and j > 2 and i < model.shape[0] and j < model.shape[1]):
|
|
|
|
return model[i - 2: i + 2, j - 2: j + 2]
|
|
|
|
|
|
|
|
# Neither negative indices nor indices that overflow
|
|
|
|
# are handled properly by numpy. So basically I have to do that manually:
|
|
|
|
cells_around = np.zeros([3, 3], np.int8)
|
|
|
|
for k, m in enumerate(range(i - 1, i + 2)):
|
|
|
|
for l, n in enumerate(range(j - 1, j + 2)):
|
|
|
|
real_m = m
|
|
|
|
if(m >= model.shape[0]):
|
|
|
|
real_m = m - model.shape[0]
|
|
|
|
if(m < 0):
|
|
|
|
real_m = m + model.shape[0]
|
|
|
|
real_n = n
|
|
|
|
if(n >= model.shape[1]):
|
|
|
|
real_n = n - model.shape[1]
|
|
|
|
if(n < 0):
|
|
|
|
real_n = n + model.shape[1]
|
|
|
|
cells_around[k][l] = model[real_m][real_n]
|
|
|
|
return cells_around
|
|
|
|
|
|
|
|
def count_living_cells_around(model, i, j):
|
|
|
|
cells_around = get_cells_around(model, i, j)
|
|
|
|
living_cells_around = (cells_around & CELL_IS_ALIVE) == 1
|
|
|
|
living_cells_around[1][1] = False
|
2019-02-23 20:01:16 +00:00
|
|
|
unique, counts = np.unique(living_cells_around, return_counts=True)
|
|
|
|
if(True not in unique):
|
|
|
|
return 0
|
|
|
|
return counts[np.where(unique == True)[0]]
|
2019-02-23 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_cell(model, i, j):
|
|
|
|
living_cells_around = count_living_cells_around(model, i, j)
|
|
|
|
if(not is_alive(model, i, j)):
|
|
|
|
if(living_cells_around == 3):
|
|
|
|
model[i][j] = CELL_WILL_BE_ALIVE
|
|
|
|
return
|
|
|
|
|
|
|
|
if(living_cells_around > 3 or living_cells_around < 2):
|
|
|
|
model[i][j] = CELL_WILL_BE_DEAD
|
|
|
|
|
|
|
|
def after_tick_finished(model):
|
|
|
|
# kill the cells that have died
|
|
|
|
model[(model & CELL_WILL_BE_DEAD) != 0] = 0
|
|
|
|
|
|
|
|
# create the new cells
|
|
|
|
model[(model & CELL_WILL_BE_ALIVE) != 0] = 1
|
|
|
|
|
|
|
|
def total_living_cells(model):
|
|
|
|
living_cells = (model & CELL_IS_ALIVE) == 1
|
2019-02-23 20:01:16 +00:00
|
|
|
unique, counts = np.unique(living_cells, return_counts=True)
|
|
|
|
if(True not in unique):
|
|
|
|
return 0
|
|
|
|
return counts[np.where(unique == True)[0]]
|