簡介
元胞自動機(cellular automata) 是離散而抽象的計算系統。元胞自動機在時間和空間上是離散的,最小單位是簡單元胞(單元格)。每個元胞會產生有限數量的狀態集,后續元胞由其鄰域元胞的狀態確定。這里所說的領域元胞,是指當前元胞的前一個元胞(記作元胞A)以及元胞A左右兩個元胞。也就是說,鄰域元胞總共包含三個元胞。給定初始層的狀態,基於一定規則,我們可以不斷更新下一層元胞的狀態。通俗的講,元胞自動機就是基於一定規則的“繁衍機器”。
最簡單的例子
這里,我們選取的元胞狀態只有兩種,分別為 0 和 1。每一層由 64 個元胞組成,若元胞狀態為 1,那么控制台將打印星號(*);如果元胞狀態為 0,那么控制台將打印連字符(-)。也就是說,每一行由 64 個混合星號與連字符的圖案組成。
那么,我們如何確定每一行的狀態呢?
首先,我們要對第一行進行初始化操作。我們設置第 31 個元胞的狀態為 1、其余 63 個元胞的狀態為 0.
狀態更新規則:若當前元胞的前一個元胞的狀態為 1,或者前一個元胞的左右兩邊的元胞的狀態有且只有一個值為 1, 那么該元胞的狀態就為 1。反之,元胞的狀態設為 0。對於第一列和最后一列,我們只需分別考慮右元胞和左元胞即可。對於中間部分的元胞來說,若其領域元胞的狀態為[0,1,0]、[0,0,1]、[1,0,0]、[1,1,0]等狀態時,當前元胞的狀態就為 1。
代碼
""" 元胞自動機 Python 實現 """ import numpy as np import matplotlib.pyplot as plt class GameOfLife(object): def __init__(self, cells_shape): """ Parameters ---------- cells_shape : 一個元組,表示畫布的大小。 Examples -------- 建立一個高20,寬30的畫布 game = GameOfLife((20, 30)) """ # 矩陣的四周不參與運算 self.cells = np.zeros(cells_shape) real_width = cells_shape[0] - 2 real_height = cells_shape[1] - 2 self.cells[1:-1, 1:-1] = np.random.randint(2, size=(real_width, real_height)) self.timer = 0 self.mask = np.ones(9) self.mask[4] = 0 def update_state(self): """更新一次狀態""" buf = np.zeros(self.cells.shape) cells = self.cells for i in range(1, cells.shape[0] - 1): for j in range(1, cells.shape[0] - 1): # 計算該細胞周圍的存活細胞數 neighbor = cells[i-1:i+2, j-1:j+2].reshape((-1, )) neighbor_num = np.convolve(self.mask, neighbor, 'valid')[0] if neighbor_num == 3: buf[i, j] = 1 elif neighbor_num == 2: buf[i, j] = cells[i, j] else: buf[i, j] = 0 self.cells = buf self.timer += 1 def plot_state(self): """畫出當前的狀態""" plt.title('Iter :{}'.format(self.timer)) plt.imshow(self.cells) plt.show() def update_and_plot(self, n_iter): """更新狀態並畫圖 Parameters ---------- n_iter : 更新的輪數 """ plt.ion() for _ in range(n_iter): plt.title('Iter :{}'.format(self.timer)) plt.imshow(self.cells) self.update_state() plt.pause(0.2) plt.ioff() if __name__ == '__main__': game = GameOfLife(cells_shape=(60, 60)) game.update_and_plot(200)