Merge branch 'gol' of ssh://daknuett.eu:10022/daknuett/scientific-programming-exercises into gol

This commit is contained in:
Daniel Knüttel 2019-02-23 20:39:39 +01:00
commit d813e674a0
4 changed files with 113 additions and 0 deletions

64
exam/ex13/backend.py Normal file
View 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
View 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
View 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
View 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)