[Life game] [link01], which is famous as a cellular automaton, seemed to be interesting, so I wrote the code to generate the map array of the life game with Python and numpy. By giving an early generation map array written in 0
(dead) and 1
(live), iterative is implemented as a generator to generate the next generation map array. The map also supports periodic boundary conditions (end-to-end connection)!
Import and use the following lifegame.py
as a module. See the sample code below for an actual usage example. The evolution rules are based on the 23/3
featured on Wikipedia, but you can easily change them by tweaking in the code.
usage
>>> lg_map = lifegame.MapGenerator(map_init, periodic=False)
>>> lg_map.evolve()
array([...]) #0th generation map array(= map_init)
>>> lg_map.evolve()
array([...]) #1st generation map array
>>> ...
map_init
: Early generation map array (list or numpy.ndarray)periodic
: Whether to use periodic boundary conditions for the map (bool)lifegame.py
lifegame.py
import numpy as np
from itertools import product
class MapGenerator(object):
def __init__(self, map_init, periodic=False):
self.map_init = np.array(map_init, np.int64)
self.periodic = periodic
self.generator = self.map_evolver()
def map_evolver(self):
map_now = self.map_init
map_shape = self.map_init.shape
while True:
map_next = np.zeros_like(map_now, np.int64)
for (i,j) in product(range(map_shape[0]), range(map_shape[1])):
islive = bool(map_now[i,j])
nlive = self.num_live_neighbours(map_now, i, j)
# write the rules of lifegame here!
# ........................................
if nlive == 2:
if islive: map_next[i,j] = 1
elif nlive == 3:
map_next[i,j] = 1
# ........................................
yield map_now
map_now = map_next
def num_live_neighbours(self, map_now, i, j):
if self.periodic:
neighbours = np.roll(np.roll(map_now, -i+1, 0), -j+1, 1)[:3,:3]
else:
sl_i = slice(0,i+2) if i == 0 else slice(i-1,i+2)
sl_j = slice(0,j+2) if j == 0 else slice(j-1,j+2)
neighbours = map_now[sl_i,sl_j]
return neighbours.sum() - map_now[i,j]
def evolve(self):
return self.generator.next()
Below is a sample code of a type of oscillator called [pulsar] [link02] that evolves endlessly on a 15x15 map. Since it is just a sample, it seems that it is limited by the drawing efficiency of matplotlib rather than the calculation speed of the array ...
pulsar.py
import time
import numpy as np
import matplotlib.pyplot as plt
import lifegame
pulsar = np.array([
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
lg_map = lifegame.MapGenerator(map_init=pulsar, periodic=False)
plt.ion()
while True:
plt.pcolormesh(lg_map.evolve())
plt.xlim([0, pulsar.shape[1]])
plt.ylim([0, pulsar.shape[0]])
plt.draw()
plt.clf()
time.sleep(0.05)
![lifegame-pulsar.png][link03]
At the moment, it is necessary to prepare the map array of the early generation in text in advance, so I would like to use matplotlib.widgets
so that the map array can be input from the screen. It's a play, so it's undecided when to make it (laughs)
[link01]: http://ja.wikipedia.org/wiki/ Conway's Game of Life [link02]: http://ja.wikipedia.org/wiki/pulsar_ (life game) [link03]: https://qiita-image-store.s3.amazonaws.com/0/44000/18e4ac52-9120-dae6-b683-8ca29cd1d507.png
Recommended Posts