元胞自动机python代码_Python实现元胞自动机(康威生命游戏)
元胞自動機是很常用的傳播/交通模型,因此寫下這篇文章,以后忘了可以再翻看
元胞自動機元胞自動機又被稱為康威生命游戲,是英國數(shù)學(xué)家約翰·何頓·康威在1970年發(fā)明的細胞自動機。它最初于1970年10月在《科學(xué)美國人》雜志上馬丁·葛登能的“數(shù)學(xué)游戲”專欄出現(xiàn)
元胞自動機是一個零玩家游戲。他包括一個二維矩形世界,這個世界中的每個方格居住著一個活著的或死了的細胞。一個細胞在下一時刻的生死取決于相鄰八個方格中或者的或死了的細胞數(shù)量
規(guī)則
每個細胞有兩種狀態(tài)-存活或死亡,每個細胞與以自身為中心的周圍八格細胞產(chǎn)生互動:細胞過少:當(dāng)周圍低于2個(不包含2個)存活細胞時,本單元活細胞死亡
穩(wěn)定:當(dāng)周圍有2個或3個存活細胞時,本單元細胞保持原樣
人口過剩:當(dāng)周圍有3個以上的存活細胞時,本單元活細胞死亡
繁殖:當(dāng)周圍有3個存活細胞時,本單元細胞存活/活化
初看覺得這就是個模擬細胞繁衍的東西,規(guī)則也很簡單。
隨著游戲的進行,雜亂無序的細胞會逐漸演化出各種精致、有形的結(jié)構(gòu),這些結(jié)構(gòu)往往有很好的對稱性,而且每一代都在變化形狀,一些形狀已經(jīng)鎖定,不會逐代變化。有時,一些已經(jīng)成形的結(jié)構(gòu)會因為一些無序細胞的"入侵"而被破壞。但是形狀和秩序經(jīng)常能從雜亂中產(chǎn)生出來。對于生成的形狀和秩序,我們稱作pattern(模式)
開發(fā)準(zhǔn)備
首先安裝pygamepip install pygame
開發(fā)步驟
我們使用矩陣來記錄我們的游戲世界,其中0表示細胞死亡,1表示細胞存活
感謝The Game of Life in Python這篇博文,一行代碼解決了計算細胞周圍活細胞數(shù)量的問題nbrs_count = sum(np.roll(np.roll(X, i, 0), j, 1)
for i in (-1, 0, 1) for j in (-1, 0, 1)
if (i != 0 or j != 0))
由于我們的游戲世界是上下左右循環(huán)的,所以將矩陣往8個方向進行循環(huán)移位得到8個新矩陣,將8個新矩陣相加就能得到每個細胞周圍的活細胞數(shù)量矩陣了
np.roll操作就是循環(huán)移位操作。np.roll(X, i, 0)中的X代表輸入矩陣,i代表以為的大小,0代表移位的維度,np.roll(X, 1, 0)代表矩陣下移一格,np.roll(X, 1, 2)代表右移一格,if (i != 0 or j != 0)是為了不計算死亡的細胞
通過活細胞數(shù)量矩陣根據(jù)更新規(guī)則更新我們的世界。因為矩陣單位只有兩種狀態(tài),這里我們只考慮存貨態(tài)就可以了。注意到存活的條件是:穩(wěn)定:當(dāng)周圍有2個或3個存活細胞時,本單元細胞保持原樣
繁殖:當(dāng)周圍有3個存活細胞時,本單元細胞存活/活化
即細胞周圍數(shù)量等于3或者本單元細胞存活的同時周圍有2個存活細胞時候,本單元細胞將在下一代存活
翻譯過來就是(nbrs_count == 3) | (X & (nbrs_count == 2))
注意到這種方法雖然便捷,但效率顯然不怎么樣。因為這種做法更新了矩陣的每一個單元,這完全沒有必要,大部分情況下矩陣都是稀疏的,如何改進希望讀者自己嘗試
我們實現(xiàn)生命游戲的操作如下:R鍵:重置世界
回車鍵:進行演化
空格鍵:暫停演化
鼠標(biāo)左鍵:增添一個細胞
鼠標(biāo)右鍵:銷毀一個細胞
下面是用pygame實現(xiàn)的全部代碼# -*- coding: utf-8 -*-
import pygame, sys, time
import numpy as np
from pygame.locals import *
# Matrix width and matrix height
WIDTH = 80
HEIGHT = 40
# A global variable that records mouse button conditions
pygame.button_down = False
# A matrix that records the game world
pygame.world=np.zeros((HEIGHT,WIDTH))
# Create a Cell class to facilitate Cell drawing
class Cell(pygame.sprite.Sprite):
size = 10
def __init__(self, position):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([self.size, self.size])
# Fill in the white
self.image.fill((255,255,255))
# Creates a rectangle with the upper-left corner as the anchor point
self.rect = self.image.get_rect()
self.rect.topleft = position
# Drawing function
def draw():
screen.fill((0,0,0))
for sp_col in range(pygame.world.shape[1]):
for sp_row in range(pygame.world.shape[0]):
if pygame.world[sp_row][sp_col]:
new_cell = Cell((sp_col * Cell.size,sp_row * Cell.size))
screen.blit(new_cell.image,new_cell.rect)
# Update the map according to cell update rules
def next_generation():
nbrs_count = sum(np.roll(np.roll(pygame.world, i, 0), j, 1)
for i in (-1, 0, 1) for j in (-1, 0, 1)
if (i != 0 or j != 0))
pygame.world = (nbrs_count == 3) | ((pygame.world == 1) & (nbrs_count == 2)).astype('int')
# init Map
def init():
pygame.world.fill(0)
draw()
return 'Stop'
# Stop operation
def stop():
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN and event.key == K_RETURN:
return 'Move'
if event.type == KEYDOWN and event.key == K_r:
return 'Reset'
if event.type == MOUSEBUTTONDOWN:
pygame.button_down = True
pygame.button_type = event.button
if event.type == MOUSEBUTTONUP:
pygame.button_down = False
if pygame.button_down:
mouse_x, mouse_y = pygame.mouse.get_pos()
sp_col = int(mouse_x / Cell.size);
sp_row = int(mouse_y / Cell.size);
if pygame.button_type == 1: # The left mouse button
pygame.world[sp_row][sp_col] = 1
elif pygame.button_type == 3: # The right mouse button
pygame.world[sp_row][sp_col] = 0
draw()
return 'Stop'
# Timer, control frame rate
pygame.clock_start = 0
# Evolution operations
def move():
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN and event.key == K_SPACE:
return 'Stop'
if event.type == KEYDOWN and event.key == K_r:
return 'Reset'
if event.type == MOUSEBUTTONDOWN:
pygame.button_down = True
pygame.button_type = event.button
if event.type == MOUSEBUTTONUP:
pygame.button_down = False
if pygame.button_down:
mouse_x, mouse_y = pygame.mouse.get_pos()
sp_col = mouse_x / Cell.size;
sp_row = mouse_y / Cell.size;
if pygame.button_type == 1:
pygame.world[sp_row][sp_col] = 1
elif pygame.button_type == 3:
pygame.world[sp_row][sp_col] = 0
draw()
if time.clock() - pygame.clock_start > 0.02:
next_generation()
draw()
pygame.clock_start = time.clock()
return 'Move'
if __name__ == '__main__':
# init, stop, move
state_actions = {
'Reset': init,
'Stop': stop,
'Move': move
}
state = 'Reset'
pygame.init()
pygame.display.set_caption('Conway\'s Game of Life')
screen = pygame.display.set_mode((WIDTH * Cell.size, HEIGHT * Cell.size))
while True:
state = state_actions[state]()
pygame.display.update()
總結(jié)
以上是生活随笔為你收集整理的元胞自动机python代码_Python实现元胞自动机(康威生命游戏)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 静态代理、动态代理、AOP
- 下一篇: 初级学电脑计算机的入门知识,电脑基础知识