Merge branch 'gol' of ssh://daknuett.eu:10022/daknuett/scientific-programming-exercises into gol
This commit is contained in:
commit
d813e674a0
64
exam/ex13/backend.py
Normal file
64
exam/ex13/backend.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
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
|
||||
_, counts = np.unique(living_cells_around, return_counts=True)
|
||||
print(counts)
|
||||
return counts[True]
|
||||
|
||||
|
||||
|
||||
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
|
||||
_, counts = np.unique(living_cells, return_counts=True)
|
||||
return counts[True]
|
11
exam/ex13/executor.py
Normal file
11
exam/ex13/executor.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from backend import handle_cell, after_tick_finished
|
||||
|
||||
def execute_tick(model):
|
||||
n, m = model.shape
|
||||
|
||||
for i in range(n):
|
||||
for j in range(m):
|
||||
handle_cell(model, i, j)
|
||||
after_tick_finished(model)
|
||||
|
||||
|
25
exam/ex13/main.py
Normal file
25
exam/ex13/main.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
from model import prepare_model
|
||||
from backend import total_living_cells
|
||||
from executor import execute_tick
|
||||
|
||||
def cells_alive_at_ticks(model, ticks):
|
||||
for i in range(ticks):
|
||||
execute_tick(model)
|
||||
cell_count = total_living_cells(model)
|
||||
yield i, cell_count
|
||||
|
||||
plot_data = {
|
||||
0.3 : ("r", "p=0.3")
|
||||
, 0.5: ("g", "p=0.5")
|
||||
, 0.7: ("b", "p=0.7")
|
||||
}
|
||||
|
||||
for p, (color, label) in plot_data.items():
|
||||
model = prepare_model(100, p)
|
||||
living_cells = np.array(list(cells_alive_at_ticks(model, 1000)))
|
||||
plt.plot(living_cells[:, 0], living_cells[:, 1], color, label=label)
|
||||
|
||||
plt.show()
|
13
exam/ex13/model.py
Normal file
13
exam/ex13/model.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
import numpy as np
|
||||
|
||||
def prepare_model(n, p):
|
||||
"""
|
||||
p must be between 0 and 1.
|
||||
"""
|
||||
|
||||
return (np.random.rand(n, n) < p).astype(np.int8)
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user