Python實(shí)現(xiàn)生命游戲的示例代碼(tkinter版)
生命游戲(Game of Life)
由劍橋大學(xué)約翰·何頓·康威設(shè)計(jì)的計(jì)算機(jī)程序。美國(guó)趣味數(shù)學(xué)大師馬丁·加德納(Martin Gardner,1914-2010)通過(guò)《科學(xué)美國(guó)人》雜志,將康威的生命游戲介紹給學(xué)術(shù)界之外的廣大瀆者,一時(shí)吸引了各行各業(yè)一大批人的興趣,這時(shí)細(xì)胞自動(dòng)機(jī)課題才吸引了科學(xué)家的注意。
游戲概述
用一個(gè)二維表格表示“生存空間”,空間的每個(gè)方格中都可放置一個(gè)生命細(xì)胞,每個(gè)生命細(xì)胞只有兩種狀態(tài):“生”或“死”。用綠色方格表示該細(xì)胞為“生”,空格(白色)表示該細(xì)胞為“死”。或者說(shuō)方格網(wǎng)中綠色部分表示某個(gè)時(shí)候某種“生命”的分布圖。生命游戲想要模擬的是:隨著時(shí)間的流逝,這個(gè)分布圖將如何一代一代地變化。死亡太沉重,我想稱它為“湮滅”狀態(tài)。
生存定律
生存空間的每個(gè)方格都存在一個(gè)細(xì)胞,它的周邊緊鄰的8個(gè)方格上的稱為鄰居細(xì)胞。
(1)當(dāng)前細(xì)胞為湮滅狀態(tài)時(shí),當(dāng)周?chē)校硞€(gè)存活細(xì)胞時(shí),則迭代后該細(xì)胞變成存活狀態(tài)(模擬繁殖)。
(2)當(dāng)前細(xì)胞為存活狀態(tài)時(shí),當(dāng)周?chē)泥従蛹?xì)胞少于2個(gè)存活時(shí),該細(xì)胞變成湮滅狀態(tài)(數(shù)量稀少)。
(3)當(dāng)前細(xì)胞為存活狀態(tài)時(shí),當(dāng)周?chē)校硞€(gè)以上的存活細(xì)胞時(shí),該細(xì)胞變成湮滅狀態(tài)(數(shù)量過(guò)多)。
(4)當(dāng)前細(xì)胞為存活狀態(tài)時(shí),當(dāng)周?chē)校矀€(gè)或3個(gè)存活細(xì)胞時(shí),該細(xì)胞保持原樣。
簡(jiǎn)單來(lái)說(shuō),活細(xì)胞Cell看作是‘1’,死Cell看作‘0’,8個(gè)鄰居的累加和Sum決定了下一輪的狀態(tài):
“繁殖”:死Cell=0,若Sum=3,則Cell=1。
“稀少”:活Cell=1,若Sum<2,則Cell=0。
“過(guò)多”:活Cell=1,若Sum>3,則Cell=0。
“正常”:活Cell=1,若Sum=2或3,則Cell=1。
生存空間中生命的繁殖和湮滅,如下圖所示:

圖形結(jié)構(gòu)
在游戲進(jìn)行中,雜亂無(wú)序的細(xì)胞會(huì)逐漸演化出各種精致、有形的圖形結(jié)構(gòu);這些結(jié)構(gòu)往往有很好的對(duì)稱性,而且每一代都在變化形狀。一些形狀一經(jīng)鎖定就不會(huì)逐代變化。有時(shí),一些已經(jīng)成形的結(jié)構(gòu)會(huì)因?yàn)橐恍o(wú)序細(xì)胞的“入侵”而被破壞。但是形狀和秩序經(jīng)常能從雜亂中產(chǎn)生出來(lái)。
通常會(huì)有以下四種狀態(tài):
不動(dòng)點(diǎn)(fixed points):變化終結(jié)于恒定圖像
交替態(tài)(alternation):圖像出現(xiàn)周期性變化
隨機(jī)態(tài)(randomness):圖像變化近乎隨機(jī)
復(fù)雜態(tài)(complexity):圖像存在某種復(fù)雜規(guī)律
常見(jiàn)的不動(dòng)結(jié)構(gòu):

周期變化的結(jié)構(gòu):

逐步趨向湮滅的結(jié)構(gòu):

由一根10個(gè)連續(xù)細(xì)胞演化出來(lái)的周期結(jié)構(gòu):

動(dòng)態(tài)變化后全部湮滅的結(jié)構(gòu):

移動(dòng)的飛船:周期變化且逐漸向右平移
飛船到了邊界變成向?qū)蔷€移動(dòng)的“滑翔者”,滑翔者到了邊界成為不動(dòng)的方塊。

更多有趣的圖形結(jié)構(gòu)有待發(fā)現(xiàn),用代碼來(lái)輔助這項(xiàng)工作還是比較方便的.....
代碼實(shí)現(xiàn)
用tkinter庫(kù)實(shí)現(xiàn)了軟件界面,畫(huà)布、按鈕、標(biāo)簽等控件都是配角,全是為表現(xiàn)生命繁殖演化的核心代碼類方法 Lifes.reproduce() 作幫手的,源代碼lifegame.pyw如下:
from tkinter import messagebox as msgbox
import tkinter as tk
import webbrowser
import random
class Lifes:
def __init__(self, rows=38, cols=38):
self.row = rows
self.col = cols
self.items = [[0]*self.col for _ in range(self.row)]
self.histroy = []
self.histroySize = 30
self.running = False
self.runningSpeed = 100
def rndinit(self, rate=0.1):
self.histroy = []
for i in range(self.row):
for j in range(self.col):
rnd = random.random()
if rnd > 1-rate:
self.items[i][j]=1
def reproduce(self):
new = [[0]*self.col for _ in range(self.row)]
self.add_histroy()
if len(self.histroy) > self.histroySize:
self.histroy.pop(0)
for i in range(self.row):
for j in range(self.col):
if i*j==0 or i==self.row-1 or j==self.col-1:
new[i][j]=0
else:
lifes=0
for m in range(i-1,i+2):
for n in range(j-1,j+2):
if m==i and n==j:
continue
lifes += self.items[m][n]
if self.items[i][j]:
if lifes==2 or lifes==3:
new[i][j]=1
else:
new[i][j]=0
else:
if lifes==3:
new[i][j]=1
for idx,narray in enumerate(new):
self.items[idx] = narray
def is_stable(self):
if len(self.histroy)<self.histroySize:
return False
arr = []
for i in self.histroy:
if i not in arr:
arr.append(i)
if len(arr)<10:
return True
def add_histroy(self, Items=None):
arr = []
if Items==None:
Items=self.items[:]
for item in Items:
b = 0
for i,n in enumerate(item[::-1]):
b += n*2**i
arr.append(b)
self.histroy.append(arr)
def drawCanvas():
global tv,rect
tv = tk.Canvas(win, width=win.winfo_width(), height=win.winfo_height())
tv.pack(side = "top")
for i in range(36):
coord = 40, 40, 760, i*20 + 40
tv.create_rectangle(coord)
coord = 40, 40, i*20 + 40, 760
tv.create_rectangle(coord)
coord = 38, 38, 760, 760
tv.create_rectangle(coord,width=2)
coord = 39, 39, 760, 760
tv.create_rectangle(coord,width=2)
coord = 38, 38, 762, 762
tv.create_rectangle(coord,width=2)
R,XY = 8,[50+i*20 for i in range(36)]
rect = [[0]*36 for _ in range(36)]
for i,x in enumerate(XY):
for j,y in enumerate(XY):
rect[i][j] = tv.create_rectangle(x-R,y-R,x+R,y+R,tags=('imgButton1'))
tv.itemconfig(rect[i][j],fill='lightgray',outline='lightgray')
tv.tag_bind('imgButton1','<Button-1>',on_Click)
def drawLifes():
R,XY = 8,[50+i*20 for i in range(36)]
if Life.running:
for i,x in enumerate(XY):
for j,y in enumerate(XY):
if Life.items[i+1][j+1]:
tv.itemconfig(rect[i][j],fill='green',outline='green')
else:
tv.itemconfig(rect[i][j],fill='lightgray',outline='lightgray')
tv.update()
Life.reproduce()
if Life.is_stable():
Life.running = False
if sum(sum(Life.items,[])):
msgbox.showinfo('Message','生命繁殖與湮滅進(jìn)入穩(wěn)定狀態(tài)!?。?)
else:
msgbox.showinfo('Message','生命全部湮滅,進(jìn)入死亡狀態(tài)!??!')
win.after(Life.runningSpeed, drawLifes)
def StartLife():
if sum(sum(Life.items,[])):
Life.histroy = []
Life.running = True
else:
msgbox.showinfo('Message','請(qǐng)點(diǎn)擊小方塊填入生命細(xì)胞,或者使用隨機(jī)功能!')
def BreakLife():
Life.running = not Life.running
if Life.running:
Life.histroy.clear()
Life.add_histroy()
def RandomLife():
Life.rndinit()
Life.running = True
def ClearLife():
Life.running = False
Life.histroy = []
Life.items = [[0]*38 for _ in range(38)]
for x in range(36):
for y in range(36):
tv.itemconfig(rect[x][y],fill='lightgray',outline='lightgray')
def on_Enter(event):
tCanvas.itemconfig(tVisit, fill='magenta')
def on_Leave(event):
tCanvas.itemconfig(tVisit, fill='blue')
def on_Release(event):
url = 'https://blog.csdn.net/boysoft2002?type=blog'
webbrowser.open(url, new=0, autoraise=True)
def on_Click(event):
x,y = (event.x-40)//20,(event.y-40)//20
if not Life.running:
if Life.items[x+1][y+1]:
tv.itemconfig(rect[x][y],fill='lightgray',outline='lightgray')
else:
tv.itemconfig(rect[x][y],fill='red',outline='red')
Life.items[x+1][y+1] = not Life.items[x+1][y+1]
def on_Close():
if msgbox.askokcancel("Quit","Do you want to quit?"):
Life.running = False
print(Copyright())
win.destroy()
def Introduce():
txt = '''【生命游戲】\n\n生存定律:
(1)當(dāng)前細(xì)胞為湮滅狀態(tài)時(shí),當(dāng)周?chē)校硞€(gè)存活細(xì)胞時(shí),則迭代后該細(xì)胞變成存活狀態(tài)(模擬繁殖)。
(2)當(dāng)前細(xì)胞為存活狀態(tài)時(shí),當(dāng)周?chē)泥従蛹?xì)胞少于2個(gè)存活時(shí),該細(xì)胞變成湮滅狀態(tài)(數(shù)量稀少)。
(3)當(dāng)前細(xì)胞為存活狀態(tài)時(shí),當(dāng)周?chē)校硞€(gè)以上的存活細(xì)胞時(shí),該細(xì)胞變成湮滅狀態(tài)(數(shù)量過(guò)多)。
(4)當(dāng)前細(xì)胞為存活狀態(tài)時(shí),當(dāng)周?chē)校矀€(gè)或3個(gè)存活細(xì)胞時(shí),該細(xì)胞保持原樣。'''
return txt
def Copyright():
return 'Lifes Game Ver1.0\nWritten by HannYang, 2022/08/01.'
if __name__ == '__main__':
win = tk.Tk()
X,Y = win.maxsize()
W,H = 1024,800
winPos = f'{W}x{H}+{(X-W)//2}+{(Y-H)//2}'
win.geometry(winPos)
win.resizable(False, False)
win.title('生命游戲 Ver1.0')
win.update()
drawCanvas()
Life = Lifes()
drawLifes()
tLabel = tk.Label(win, width=30, height=20, background='lightgray')
tLabel.place(x=780, y=38)
tLabel.config(text='\n\n\n'.join((Introduce(),Copyright())))
tLabel.config(justify=tk.LEFT,anchor="nw",borderwidth=10,wraplength=210)
bX,bY,dY = 835, 458, 50
tButton0 = tk.Button(win, text=u'開(kāi)始', command=StartLife)
tButton0.place(x=bX, y=bY+dY*0 ,width=120,height=40)
tButton1 = tk.Button(win, text=u'暫停', command=BreakLife)
tButton1.place(x=bX, y=bY+dY*1 ,width=120,height=40)
tButton2 = tk.Button(win, text=u'隨機(jī)', command=RandomLife)
tButton2.place(x=bX, y=bY+dY*2 ,width=120,height=40)
tButton3 = tk.Button(win, text=u'清空', command=ClearLife)
tButton3.place(x=bX, y=bY+dY*3 ,width=120,height=40)
tCanvas = tk.Canvas(win, width=200, height=45)
tCanvas.place(x=800,y=716)
tVisit = tCanvas.create_text((88, 22), text=u"點(diǎn)此訪問(wèn)Hann's CSDN主頁(yè)!")
tCanvas.itemconfig(tVisit, fill='blue', tags=('btnText'))
tCanvas.tag_bind('btnText','<Enter>',on_Enter)
tCanvas.tag_bind('btnText','<Leave>',on_Leave)
tCanvas.tag_bind('btnText','<ButtonRelease-1>',on_Release)
win.protocol("WM_DELETE_WINDOW", on_Close)
win.mainloop()編譯命令
D:\> pyinstaller -F lifegame.pyw --noconsole
運(yùn)行界面

使用簡(jiǎn)介
在生存空間里點(diǎn)擊方格種植細(xì)胞(甚至可以畫(huà)出你要表達(dá)的圖形),然后點(diǎn)擊開(kāi)始;點(diǎn)下暫停鍵,則可以任意編輯生命圖形,再點(diǎn)開(kāi)始繼續(xù)運(yùn)行;點(diǎn)隨機(jī)鍵則由軟件隨機(jī)生成細(xì)胞位置;清空鍵可以在任何時(shí)候清空生存空間,進(jìn)入暫停編輯狀態(tài)。
后續(xù)改進(jìn)
Lifes類預(yù)留了histroy屬性,后續(xù)可以增加回退功能;代碼缺點(diǎn)是生存空間的行列被我寫(xiě)死了,以后版本中可以改進(jìn)成任意定義行列數(shù);另一個(gè)缺點(diǎn)是對(duì)穩(wěn)定狀態(tài)的判斷比較簡(jiǎn)單,之后可以增加計(jì)算變化周期的功能。
優(yōu)點(diǎn)就是可以任意編輯你的圖形,最后以一張自己的網(wǎng)名畫(huà)的圖作收尾:

前部分介紹性文字來(lái)源于百度百科等網(wǎng)絡(luò)資源
以上就是Python實(shí)現(xiàn)生命游戲的示例代碼(tkinter版)的詳細(xì)內(nèi)容,更多關(guān)于Python 生命游戲的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Python的Django框架中的模版相關(guān)知識(shí)
這篇文章主要介紹了Python的Django框架中的模版相關(guān)知識(shí),模版的存在大大簡(jiǎn)化了創(chuàng)作頁(yè)面時(shí)HTML的相關(guān)工作,需要的朋友可以參考下2015-07-07
pycharm部署django項(xiàng)目到云服務(wù)器的詳細(xì)流程
今天重點(diǎn)給大家介紹pycharm部署django項(xiàng)目到云服務(wù)器的詳細(xì)流程,首先大家需要先下載python3.8壓縮包,然后通過(guò)一系列命令完成操作,具體實(shí)現(xiàn)方法,跟隨小編一起看看吧2021-06-06
python中Tkinter復(fù)選框Checkbutton是否被選中判斷
這篇文章主要介紹了python中Tkinter復(fù)選框Checkbutton是否被選中判斷方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01
golang/python實(shí)現(xiàn)歸并排序?qū)嵗a
這篇文章主要給大家介紹了關(guān)于golang/python實(shí)現(xiàn)歸并排序的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
分享4個(gè)方便且好用的Python自動(dòng)化腳本
自動(dòng)化測(cè)試是把以人為驅(qū)動(dòng)的測(cè)試行為轉(zhuǎn)化為機(jī)器執(zhí)行的一種過(guò)程,直白的就是為了節(jié)省人力、時(shí)間或硬件資源,提高測(cè)試效率,這篇文章主要給大家分享介紹了3個(gè)方便且好用的Python自動(dòng)化腳本,需要的朋友可以參考下2022-02-02
python中日期和時(shí)間格式化輸出的方法小結(jié)
這篇文章主要介紹了python中日期和時(shí)間格式化輸出的方法,實(shí)例總結(jié)了Python常見(jiàn)的日期與事件操作技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03

