Python 生命游戏(tkinter版)

news/2024/11/26 15:44:21/

生命游戏(Game of Life)

由剑桥大学约翰·何顿·康威设计的计算机程序。美国趣味数学大师马丁·加德纳(Martin Gardner,1914-2010)通过《科学美国人》杂志,将康威的生命游戏介绍给学术界之外的广大渎者,一时吸引了各行各业一大批人的兴趣,这时细胞自动机课题才吸引了科学家的注意。

游戏概述

用一个二维表格表示“生存空间”,空间的每个方格中都可放置一个生命细胞,每个生命细胞只有两种状态:“生”或“死”。用绿色方格表示该细胞为“生”,空格(白色)表示该细胞为“死”。或者说方格网中绿色部分表示某个时候某种“生命”的分布图。生命游戏想要模拟的是:随着时间的流逝,这个分布图将如何一代一代地变化。死亡太沉重,我想称它为“湮灭”状态。

生存定律

生存空间的每个方格都存在一个细胞,它的周边紧邻的8个方格上的称为邻居细胞。
(1)当前细胞为湮灭状态时,当周围有3个存活细胞时,则迭代后该细胞变成存活状态(模拟繁殖)。
(2)当前细胞为存活状态时,当周围的邻居细胞少于2个存活时,该细胞变成湮灭状态(数量稀少)。
(3)当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成湮灭状态(数量过多)。
(4)当前细胞为存活状态时,当周围有2个或3个存活细胞时,该细胞保持原样。

简单来说,活细胞Cell看作是‘1’,死Cell看作‘0’,8个邻居的累加和Sum决定了下一轮的状态:

“繁殖”:Cell=0,若Sum=3,则Cell=1。
“稀少”:Cell=1,若Sum<2,则Cell=0。
“过多”:Cell=1,若Sum>3,则Cell=0。
“正常”:Cell=1,若Sum=2或3,则Cell=1。

生存空间中生命的繁殖和湮灭,如下图所示:

图形结构

在游戏进行中,杂乱无序的细胞会逐渐演化出各种精致、有形的图形结构;这些结构往往有很好的对称性,而且每一代都在变化形状。一些形状一经锁定就不会逐代变化。有时,一些已经成形的结构会因为一些无序细胞的“入侵”而被破坏。但是形状和秩序经常能从杂乱中产生出来。

通常会有以下四种状态:

不动点(fixed points):变化终结于恒定图像
交替态(alternation):图像出现周期性变化
随机态(randomness):图像变化近乎随机
复杂态(complexity):图像存在某种复杂规律

常见的不动结构:

周期变化的结构:

逐步趋向湮灭的结构:


由一根10个连续细胞演化出来的周期结构:


动态变化后全部湮灭的结构:


移动的飞船:周期变化且逐渐向右平移

飞船到了边界变成向对角线移动的“滑翔者”,滑翔者到了边界成为不动的方块

更多有趣的图形结构有待发现,用代码来辅助这项工作还是比较方便的.....


代码实现

用tkinter库实现了软件界面,画布、按钮、标签等控件都是配角,全是为表现生命繁殖演化的核心代码类方法 Lifes.reproduce() 作帮手的,源代码lifegame.pyw如下:

from tkinter import messagebox as msgbox
import tkinter as tk
import webbrowser
import randomclass Lifes:def __init__(self, rows=36, cols=36):self.row = rows+2self.col = cols+2self.items = [[0]*self.col for _ in range(self.row)]self.histroy = []self.histroySize = 30self.running = Falseself.runningSpeed = 100def 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]=1def 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]=0else:lifes=0for m in range(i-1,i+2):for n in range(j-1,j+2):if m==i and n==j:continuelifes += self.items[m][n]if self.items[i][j]:if lifes==2 or lifes==3:new[i][j]=1else:new[i][j]=0else:if lifes==3:new[i][j]=1for idx,narray in enumerate(new):self.items[idx] = narraydef is_stable(self):if len(self.histroy)<self.histroySize:return Falsearr = []for i in self.histroy:if i not in arr:arr.append(i)if len(arr)<10:return Truedef add_histroy(self, Items=None):arr = []if Items==None:Items=self.items[:]for item in Items:b = 0for i,n in enumerate(item[::-1]):b += n*2**iarr.append(b)self.histroy.append(arr)def drawCanvas():global tv,recttv = 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 + 40tv.create_rectangle(coord)coord = 40, 40, i*20 + 40, 760tv.create_rectangle(coord)coord = 38, 38, 760, 760tv.create_rectangle(coord,width=2)coord = 39, 39, 760, 760tv.create_rectangle(coord,width=2)coord = 38, 38, 762, 762tv.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 = Falseif sum(sum(Life.items,[])):msgbox.showinfo('Message','生命繁殖与湮灭进入稳定状态!!!')else:msgbox.showinfo('Message','生命全部湮灭,进入死亡状态!!!')win.after(Life.runningSpeed, drawLifes)def StartLife():if sum(sum(Life.items,[])):Life.histroy = []Life.running = Trueelse:msgbox.showinfo('Message','请点击小方块填入生命细胞,或者使用随机功能!')def BreakLife():Life.running = not Life.runningif Life.running:Life.histroy.clear()Life.add_histroy()def RandomLife():Life.rndinit()Life.running = Truedef ClearLife():Life.running = FalseLife.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 btnCommand(i):if   i==0: return StartLifeelif i==1: return BreakLifeelif i==2: return RandomLifeelif i==3: return ClearLifedef 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)//20if 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 = Falseprint(Copyright())win.destroy()def Introduce():txt = '''【生命游戏】\n\n生存定律:(1)当前细胞为湮灭状态时,当周围有3个存活细胞时,则迭代后该细胞变成存活状态(模拟繁殖)。(2)当前细胞为存活状态时,当周围的邻居细胞少于2个存活时,该细胞变成湮灭状态(数量稀少)。(3)当前细胞为存活状态时,当周围有3个以上的存活细胞时,该细胞变成湮灭状态(数量过多)。(4)当前细胞为存活状态时,当周围有2个或3个存活细胞时,该细胞保持原样。'''return txtdef 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,800winPos = 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)tButton = [None]*4bX,bY,dY = 835, 458, 50txt = ['开始','暂停','随机','清空']for i in range(4):tButton[i] = tk.Button(win, text=txt[i], command=btnCommand(i))tButton[i].place(x=bX, y=bY+dY*i, 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"点此访问Hann's CSDN主页!")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

运行界面

使用简介

在生存空间里点击方格种植细胞(甚至可以画出你要表达的图形),然后点击开始;点下暂停键,则可以任意编辑生命图形,再点开始继续运行;点随机键则由软件随机生成细胞位置;清空键可以在任何时候清空生存空间,进入暂停编辑状态。 

后续改进

Lifes类预留了histroy属性,后续可以增加回退功能;代码缺点是生存空间的行列被我写死了,以后版本中可以改进成任意定义行列数;另一个缺点是对稳定状态的判断比较简单,之后可以增加计算变化周期的功能。

优点就是可以任意编辑你的图形,最后以一张自己的网名画的图作收尾:


前部分介绍性文字来源于百度百科等网络资源 


http://www.ppmy.cn/news/97393.html

相关文章

Linux-0.11 文件系统super.c详解

Linux-0.11 文件系统super.c详解 模块简介 该模块主要包含了对超级块的一些读写操作。 函数详解 lock_super static void lock_super(struct super_block * sb)该函数的作用是锁定bh块。 cli();//关中断while (sb->s_lock)//如果已经被锁定sleep_on(&(sb->s_wai…

日常 - HttpURLConnection 网络请求 TLS 1.2

文章目录 环境前言HTTPS 请求流程服务端支持JDK 验证资源 环境 JDK 8 Hutool 4.5.1 前言 应供应商 DD 的 TLS 版本升级通知&#xff0c;企业版接口升级后 TLS 1.0 及 1.1 版本请求将无法连接&#xff0c;仅支持 TLS 1.2 及以上版本的客户端发起请求。 当前项目使用 Hutool …

协程切换原理与实践 -- 从ucontext api到x86_64汇编

目录 1.协程切换原理理解 2.ucontext实现协程切换 2.1 实现流程 2.2 根据ucontext流程看协程实现 2.3 回答开头提出的问题 3.x86_64汇编实现协程切换 3.1libco x86_64汇编代码分析 3.2.保存程序返回代码地址流程 3.3.恢复程序地址以及上下文 4.实现简单协程框架 1.协程…

python+django协同过滤算法的美食O2O外卖点餐系统vue

当然使用的数据库是mysql。尽管没有面向对象的数据库的作用强大&#xff0c;但是在Python开发上还是比较的灵活和方便的。系统功能主要介绍以下几点&#xff1a; 本外卖点餐系统主要包括二大功能模块&#xff0c;即用户功能模块和管理员功能模块。 &#xff08;1&#xff09;管…

1. Tomcat整体架构及其设计精髓分析

tomcat 1.Tomcat的整体架构1.1 Tomcat介绍1.1.1 Servlet基础回顾 1.2 目录结构1.3 web应用部署的方式1.4 结合Server.xml理解Tomcat架构1.5 架构图 2. Tomcat核心组件详解2.1 Server 组件2.2 Service组件2.3 连接器Connector组件2.3.1 ProtocolHandler 组件2.3.1.1 EndPoint2.3…

Java中常见锁的分类及概念分析

基于线程对同一把锁的获取情况分类 可重入锁 同一个线程可以多次获取锁 每次获取锁&#xff0c;锁的计数器加1&#xff0c;每次释放锁锁的计数器减1 锁的计数器归零&#xff0c;锁完全释放 Java中提供的synchronized&#xff0c;ReentrantLock&#xff0c;ReentrantReadWriteL…

文档处理新探究成果——前沿技术CCIG文档图像智能分析论坛分享

目录 前言 一、文档分析与识别最新研究 二、视觉-语言预训练模型及迁移学习 三、篡改文本图像的生成与检测技术 四、智能文档处理技术在工业界的应用与挑战 总结 前言 图文智能处理前沿技术一直是我所关注的技术&#xff0c;尤其在现在集成多态大模型的基础之上&#xff0…

深入了解平均精度(mAP):通过精确率-召回率曲线评估目标检测性能

平均精度&#xff08;Average Precision&#xff0c;mAP&#xff09;是一种常用的用于评估目标检测模型性能的指标。在目标检测任务中&#xff0c;模型需要识别图像中的不同目标&#xff0c;并返回它们的边界框&#xff08;bounding box&#xff09;和类别。mAP用于综合考虑模型…