? ? ? ?康威生命游戏(Conway life game)没有游戏玩家各方之间的竞争,也谈不上输赢,可以把它归类为仿真游戏。事实上,也是因为它模拟和显示的图像看起来颇似生命的出生和繁衍过程而得名为"生命游戏"。在游戏进行中,杂乱无序的细胞会逐渐演化出各种精致、有形的结构;这些结构往往有很好的对称性,而且每一代都在变化形状。一些形状一经锁定就不会逐代变化。有时,一些已经成形的结构会因为一些无序细胞的"入侵"而被破坏。但是形状和秩序经常能从杂乱中产生出来。
? ? ? ?康威生命游戏是一个二维网格游戏,这个网格中每个方格居住着一个活着或死了的细胞。一个细胞在下一个时刻的生死取决于相邻8个方格中活着或死了的细胞的数量。如果相邻方格活着的细胞数量过多,这个细胞会因为资源匮乏而在下一个时刻死去;相反,如果周围活细胞过少,这个细胞会因为孤单而死去。在游戏初始阶段,玩家可以设定周围活细胞(邻居)的数目和位置。如果邻居细胞数目设定过高,网格中大部分细胞会因为找不到资源而死去,直到整个>网格都没有生命;如果邻居细胞数目设定过低,世界中又会因为生命稀少而得不到繁衍。实际中,邻居细胞数目一般选取2或者3;这样整个生命世界才不至于太过荒凉或拥挤,而是一种动态平衡。游戏规则是:当一个方格周围有两个或3个活细胞时,方格中的活细胞在下一个时刻继续存活;即使这个时刻方格中没有活细胞,在下一个时刻也会"诞生"活细胞。在这个游戏中,还可以设定一些更加复杂的规则,例如当前方格的状态不仅由父一代决定,而且还考虑到祖父一代的情况。
? ? ? ?每个方格中都可放置一个生命细胞,每个生命细胞只有两种状态:
? ? ? ?"生"或"死"。用黑色方格表示该细胞为"生",空格(白色)表示该细胞为"死"。或者说方格网中黑色部分表示某个时候某种"生命"的分布图。生命游戏想要模拟的是:随着时间的流逝,这个分布图将如何一代一代地变化。
用Python中的tkinter库还原康威生命游戏:? ? ? ?
首先新建一个Python文件,命名为model,做为模型:
import random #随机模块加载
height=100 #初始化模型大小
width=100
grid_model=[0]*height #定义模型
next_grid_model=[0]*height
for i in range(height):
grid_model[i]=[0]*width
next_grid_model[i]=[0]*width
def randomize(grid,width,height): #定义一个随机细胞的函数
for i in range(0,height):
for j in range(0,width):
grid[i][j]=random.randint(0,1)
randomize(grid_model,width,height) #默认生成随机细胞
def next_gen(): #定义一个计算下一代细胞的函数
global grid_model,next_grid_model
for i in range(0,height):
for j in range(0,width):
cell=0
count=count_neighbours(grid_model,i,j)
if grid_model[i][j]==0:
if count==3:
cell=1
elif grid_model[i][j]==1:
if count==2 or count==3:
cell=1
next_grid_model[i][j]=cell
temp=grid_model
grid_model=next_grid_model
next_grid_model=temp
def count_neighbours(grid,row,col): #定义一个数周围细胞数的函数
count=0
if row-1>=0:
count = count + grid[row-1][col]
if (row-1>=0) and (col-1>=0):
count = count + grid[row-1][col-1]
if (row-1>=0) and (col+1<width):
count = count + grid[row-1][col+1]
if col-1 >=0:
count = count + grid[row][col-1]
if col+1 < width:
count = count + grid[row][col+1]
if row+1<height:
count = count + grid[row+1][col]
if (row+1<height) and (col-1>=0):
count = count + grid[row+1][col-1]
if (row+1<height) and (col+1<width):
count = count + grid[row+1][col+1]
return count
glider_pattern=[[0,0,0,0,0],
[0,0,1,0,0],
[0,0,0,1,0], #滑翔机模型
[0,1,1,1,0],
[0,0,0,0,0]]
glider_gun_pattern[
[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,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,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,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],
[0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0],
[0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,0,0,0,0,1,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,1,0,0,0,0,0,1,0,0,0,0,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,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,1,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]]
def load_pattern(pattern, x_offset=0,y_offset=0): #定义加载模型函数
global grid_model
for i in range(0,height):
for j in range(0,width):
grid_model[i][j]=0
j=y_offset
for row in pattern:
i=x_offset
for value in row:
grid_model[i][j]=value
i = i + 1
j = j + 1
if __name__=='__main__':
next_gen()
然后再新建一个文件命名为view,用于播放细胞状态。两个文件要在同一个文件夹里:
from tkinter import * #导入tkinter模块
import model #导入model文件
cell_size=5
is_running=False
def start_handler(event): #控制开始按钮的状态
global is_running,start_button
if is_running:
is_running=False
start_button.configure(text='开始')
else:
is_running=True
start_button.configure(text='暂停')
update()
def draw_cell(row,col,color): #定义画细胞的函数
global grid_view,cell_size
if color=='black':
outline='grey'
else:
outline='white'
grid_view.create_rectangle(row*cell_size,
col*cell_size,
row*cell_size+cell_size,
(col+1)*cell_size,
fill=color,outline=outline)
def update(): #更新
global root,grid_view
grid_view.delete(ALL)
model.next_gen()
for i in range(0,model.height):
for j in range(0,model.width):
if model.grid_model[i][j]==1:
draw_cell(i,j,'black')
if(is_running):
root.after(100,update)
def option_handler(event): #控制选项按钮状态
global choice
selection=choice.get()
if selection=='滑翔机':
model.load_pattern(model.glider_pattern,10,10)
elif selection=='滑翔机枪':
model.load_pattern(model.glider_gun_pattern,10,10)
elif selection=='随机':
model.randomize(model.grid_model,model.width,model.height)
update()
def clear_handler(event): #定义清除按钮
global is_running,start_button
is_running=False
start_button.configure(text='开始')
for i in range(0,model.height):
for j in range(0,model.width):
model.grid_model[i][j]=0
update()
def grid_handler(event):
global cell_size,grid_view
x=int(event.x/cell_size)
y=int(event.y/cell_size)
if(model.grid_model[x][y]==1):
model.grid_model[x][y]=0
draw_cell(x,y,'white')
else:
model.grid_model[x][y]=1
draw_cell(x,y,'black')
#主程序
root=Tk()
root.title('康威生命游戏')
grid_view=Canvas(root,width=model.width*cell_size,
height=model.height*cell_size,
bg='white')
start_button=Button(root,text='开始',width=12)
clear_button=Button(root,text='清除',width=12)
grid_view.grid(row=0,columnspan=3)
grid_view.bind('<Button-1>',grid_handler)
start_button.grid(row=1,column=0,sticky=W,padx=20,pady=20)
start_button.bind('<Button-1>',start_handler)
choice=StringVar(root)
choice.set('选择模式')
option=OptionMenu(root,choice,'滑翔机','滑翔机枪','随机',command=option_handler)
option.config(width=20)
option.grid(row=1,column=1,padx=20)
clear_button.grid(row=1,column=2,sticky=E,padx=20,pady=20)
clear_button.bind('<Button-1>',clear_handler)
for i in range(0,model.height):
for j in range(0,model.width):
if model.grid_model[i][j]==1:
draw_cell(i,j,'black')
root.mainloop()
注意运行时打开的是view文件。?
源代码链接:百度网盘