生命游戏1

import random
class Cell:
"""
细胞类,单个细胞
"""
def __init__(self, ix, iy, is_live):
self.ix = ix
self.iy = iy
self.is_live = is_live
self.neighbour_count = 0
def __str__(self):
return "[{},{},{:5}]".format(self.ix, self.iy, str(self.is_live))
# 计算周围活的邻居的个数,计算机中屏幕左上角的坐标为(0,0)
def calc_neighbour_count(self):
count = 0
pre_x = self.ix - 1 if self.ix > 0 else 0 # 某元胞左邻居的x值
for i in range(pre_x, self.ix+1+1): # 循环的x坐标范围是从某元胞的左邻居到右邻居
pre_y = self.iy - 1 if self.iy > 0 else 0 # 某元胞上邻居的y值
for j in range(pre_y, self.iy+1+1): # 循环的y坐标范围是从某元胞的上邻居到下邻居
# 该元胞是自己,continue,不统计count
if i == self.ix and j == self.iy:
continue
# 该元胞是无效的,continue,不统计count
if self.invalidate(i, j):
continue
# CellGrid.cells[i][j].is_live的结果是布尔值,int(True)为1,int(False)为0
# count统计出的是活的邻居的个数
count += int(CellGrid.cells[i][j].is_live)
self.neighbour_count = count
return count
def invalidate(self, x, y):
if x >= CellGrid.cx or y >= CellGrid.cy: # 元胞x值或y值大于网格范围,无效
return True
if x < 0 or y < 0: # 元胞x值或y值不在网格范围,无效
return True
return False
# 生命游戏规则:
def rule(self):
if self.is_live == True:
if self.neighbour_count > 4 or self.neighbour_count < 2:
self.is_live = False
else:
if self.neighbour_count == 4 or self.neighbour_count == 3:
self.is_live = True
class CellGrid:
"""
细胞网格类,所有细胞都处在一个长cx,宽cy的网格中
"""
cells = []
cx = 0
cy = 0
def __init__(self, cx, cy):
CellGrid.cx = cx
CellGrid.cy = cy
for i in range(cx):
cell_list = []
for j in range(cy):
# random.random() 随机生成的一个实数,它在[0,1)范围内
cell = Cell(i, j, random.random() > 0.9)
cell_list.append(cell) # 在第二层循环把cell放入cell_list,一个cell_list有十个Cell对象
CellGrid.cells.append(cell_list) # 在第一层循环把cell_list放入CellGrid.cells,一共有十个cell_list
# print(cell_list)
# print(CellGrid.cells)
# 循环遍历每个元胞判断它的生命状态
def circulate_rule(self):
for cell_list in CellGrid.cells:
# print("【%s】" % cell_list)
# print(type(cell_list)) # cell_list是一个列表,列表里面装着对象
for item in cell_list:
# print("【%s】" % item)
# print(type(item)) # <class '__main__.Cell'>
# print(item) # [0,1,True ] item看似是列表,其实是Cell类的对象,故不能用索引取值
# print(item[2]) # TypeError: 'Cell' object does not support indexing
item.rule()
# 循环遍历每个元胞计算它的活的邻居数
def circulate_nbcount(self):
for cell_list in CellGrid.cells:
for item in cell_list:
item.calc_neighbour_count()
import pygame
import sys
import time
import matplotlib.pyplot as plt
BG = (20, 20, 20) # 背景色
LIFECOLOR = (31, 97, 189) # 活细胞颜色
LINECOLOR = (52, 53, 46) # 网格色
LINE_WIDTH = 3 # 线的宽度
EDGE_WIDTH = 20 # 网格距离背景框边缘的宽度
START_POSX = 20
START_POSY = 20
class Game:
screen = None
def __init__(self, width, height, cx, cy):
self.width = width
self.height = height
self.cx_rate = int((width - 2*EDGE_WIDTH) / cx) # 一个元胞的宽度
self.cy_rate = int((height - 2*EDGE_WIDTH) / cy) # 一个元胞的高度
# pygame.display.set_mode() 初始化一个准备显示的窗口或屏幕(宽*高)
self.screen = pygame.display.set_mode([width, height])
self.cells = CellGrid(cx, cy)
# 在屏幕上显示出活的生命
def show_life(self):
# pygame.draw.line(Surface, color, start_pos, end_pos, width=1)
for i in range(self.cells.cx + 1):
pygame.draw.line(self.screen, LINECOLOR, (START_POSX, START_POSY + i * self.cy_rate),
(START_POSX + self.cells.cx * self.cx_rate, START_POSY + i * self.cy_rate), LINE_WIDTH) # 画网格横线
pygame.draw.line(self.screen, LINECOLOR, (START_POSX + i * self.cx_rate, START_POSY),
(START_POSX + i * self.cx_rate, START_POSY + self.cells.cx * self.cy_rate), LINE_WIDTH) # 画网格竖线
for cell_list in self.cells.cells:
for item in cell_list:
x = item.ix
y = item.iy
if item.is_live:
"""
pygame.draw.rect(Surface, color, Rect, width=0)
在Surface上绘制矩形,第二个参数是线条(或填充)的颜色,第三个参数Rect的
形式是((x, y), (width, height)),表示的是所绘制矩形的区域,其中第一个
元组(x, y)表示的是该矩形左上角的坐标,第二个元组 (width, height)表示的
是矩形的宽度和高度。width表示线条的粗细,单位为像素;默认值为0,表示填充
矩形内部。
"""
pygame.draw.rect(self.screen, LIFECOLOR,
[START_POSX+x * self.cx_rate+ (LINE_WIDTH - 1),
START_POSY+y * self.cy_rate+ (LINE_WIDTH - 1),
self.cx_rate- LINE_WIDTH, self.cy_rate- LINE_WIDTH])
def main():
pygame.init() # 初始化所有导入的pygame模块
pygame.display.set_caption("Game of Life") # 设置当前窗口的标题栏
game = Game(500, 500, 50, 50)
clock = pygame.time.Clock() # 实例化一个Clock对象
plt.figure()
draw_data = []
while True:
game.screen.fill(BG)
# clock.tick(1) # 每秒循环1次(帧率)
# time.sleep(0.3)
for event in pygame.event.get(): # pygame.event.get() 从队列中获取事件
if event.type == pygame.QUIT:
sys.exit()
# game是Game类的一个实例化对象,game.cells是CellGrid类的一个实例化对象
game.cells.circulate_nbcount() # 先计算邻居存活数
game.cells.circulate_rule() # 再按规则判断自己的生命状态
game.show_life()
pygame.display.flip() # 更新整个待显示的 Surface 对象到屏幕上
# 打印每个元胞
live_num = 0
for i in game.cells.cells:
for j in i:
if(j.is_live):
live_num += 1
print(live_num)
draw_data.append(live_num)
if(len(draw_data) > 200):
draw_data.pop(0)
draw_num = [i for i in range(len(draw_data))]
plt.clf() # 清除之前画的图
plt.plot(draw_num, draw_data)
plt.pause(0.1) # 暂停一秒
if __name__ == "__main__":
main()
生命游戏2

#@photon_123
import tkinter as tk
import tkinter.ttk as ttk
import random
# 定义细胞的状态
DEAD = 0
ALIVE = 1
# 定义细胞的颜色
COLORS = {
DEAD: "white",
ALIVE: "black"
}
pran =0.1 #初始随机概率
speed = 1 #初始演化速度
class GameOfLife:
def __init__(self, width, height, cell_size=20):
self.width = width
self.height = height
self.cell_size = cell_size
self.board = [[DEAD for _ in range(height)] for _ in range(width)]
self.running = True #运行状态标志位
self.onestepp = False #单步演化标志位
####创建GUI界面##############################################################################################################################################################################################################################################
self.root = tk.Tk()
self.root.title("康威生命游戏")
self.canvas = tk.Canvas(self.root, width=width*cell_size, height=height*cell_size)
self.canvas.pack()
self.canvas.bind("<Button-1>", self.handle_click)
self.start_button = tk.Button(self.root, text="开始", fg='white',bg='#4CAF50',font=('黑体',self.cell_size),command=self.start)
self.start_button.place(relheight=0.05,relwidth=0.16,relx=0.02,rely=0.9)
self.pause_button = tk.Button(self.root, text="暂停", fg='white',bg='#FE5E08',font=('黑体',self.cell_size),command=self.pause)
self.pause_button.place(relheight=0.05,relwidth=0.1,relx=0.18,rely=0.9)
self.clear_button = tk.Button(self.root, text="清空", fg='white',bg='#555555',font=('黑体',self.cell_size),command=self.clear)
self.clear_button.place(relheight=0.05,relwidth=0.1,relx=0.28,rely=0.9)
self.random_button = tk.Button(self.root, text="随机",fg='white',bg='#5677FC',font=('黑体',self.cell_size), command=self.random)
self.random_button.place(relheight=0.05,relwidth=0.1,relx=0.38,rely=0.9)
var = tk.StringVar()
ls = ['滑翔机','太空船','高斯帕滑翔机枪','蜂王梭','慨影']
self.combobox = ttk.Combobox(self.root, textvariable=var, values=ls,font=('黑体',self.cell_size))
self.combobox.place(relheight=0.05,relwidth=0.25,relx=0.7,rely=0.9)
self.combobox.bind('<<ComboboxSelected>>',self.anli)
var2 = tk.DoubleVar()
def adjust1(event):
global pran
pran = var2.get()
self.scale = tk.Scale(self.root,from_=0.1,to=1,resolution=0.01,bg='#A9A9A9',orient=tk.HORIZONTAL,length=200,variable=var2)
self.scale.bind('<ButtonRelease-1>',adjust1)
self.scale.place(relx=0.66,rely=0.03)
self.labe1 = tk.Label(self.root,text='随机概率',font=('黑体',15))
self.labe1.place(relx=0.9,rely=0.03)
var3 = tk.IntVar()
def adjust2(event):
global speed
speed = var3.get()
self.scale2 = tk.Scale(self.root,from_=1,to=100,resolution=1,bg='#A9A9A9',orient=tk.HORIZONTAL,length=200,variable=var3)
self.scale2.bind('<ButtonRelease-1>',adjust2)
self.scale2.place(relx=0.66,rely=0.1)
self.labe2 = tk.Label(self.root,text='演化频率',font=('黑体',15))
self.labe2.place(relx=0.9,rely=0.1)
####菜单相关#################################################################################################################################################################################################################################################
def rule():
rulewin = tk.Toplevel(self.root)
rulewin.geometry('700x200')
rulewin.title('游戏规则')
lab = tk.Label(rulewin,text='''1. 每个细胞的状态由该细胞及周围八个细胞上一次的状态所决定;\n
2. 如果一个细胞周围有3个细胞为生,则该细胞由死转生或保持生;\n
3. 如果一个细胞周围有2个细胞为生,则该细胞的生死状态保持不变;\n
4. 在其它情况下,该细胞由生转死或保持死''',fg='black',font=('黑体',15))
lab.pack()
def about():
abowin = tk.Toplevel(self.root)
abowin.geometry('700x200')
abowin.title('关于游戏')
lab2 = tk.Label(abowin,text='''---一个不太聪明的Python小程序---\n
-young 2023.6''',fg='black',font=('黑体',15))
lab2.place(relx=0.25,rely=0.3)
def onestep():
self.onestepp = True
self.running = True
self.evolve()
self.menu = tk.Menu(self.root,relief=tk.SUNKEN)
menufile = tk.Menu(self.menu)
self.menu.add_cascade(label='菜单',menu=menufile)
menufile.add_command(label='游戏规则',command=rule)
menufile.add_command(label='关于',command=about)
menufile.add_command(label='运行一步',command=onestep)
self.root.config(menu=self.menu)
############################################################################################################################################################################################################################################################
def anli(self,event):
#经典案例导入
suoyin = {'滑翔机':1,'太空船':2,'高斯帕滑翔机枪':3,'蜂王梭':4,'慨影':5}
suo = suoyin [self.combobox.get()]
m,n = self.height//2,self.width//2
self.clear()
if suo ==1:
for (p,q) in {(0,1),(0,-1),(-1,-1),(1,-1),(1,0)}:
self.board[m+p][n-q] = ALIVE
self.running = False
elif suo ==2:
for (p,q) in {(-2,0),(-2,1),(-1,0),(-1,1),(-1,2),(0,-1),(0,1),(0,2),(1,-1),(1,0),(1,1),(2,0)}:
self.board[m+p][n-q] = ALIVE
self.running = False
elif suo ==3:
for (p,q) in {(1,5),(1,6),(2,5),(2,6),(11,5),(11,6),(11,7),
(12,4),(12,8),(13,3),(13,9),(14,3),(14,9),(15,6),(16,4),(16,8),
(17,5),(17,6),(17,7),(18,6),(21,3),(21,4),(21,5),(22,3),(22,4),
(22,5),(23,2),(23,6),(25,1),(25,2),(25,6),(25,7),(35,3),(35,4),
(36,3),(36,4)}:
self.board[p][q] = ALIVE
self.running = False
elif suo ==4:
for (p,q) in {(-9,0),(-9,-1),(-8,0),(-8,-1),(-4,0),(-3,-1),(-3,1),
(-2,-2),(-2,2),(-1,-1),(-1,0),(-1,1),(0,-2),(0,-3),(0,2),(0,3),
(11,-1),(11,0),(12,-1),(12,0)}:
self.board[m+p][n-q] = ALIVE
self.running = False
elif suo ==5:
for (p,q) in {(-1,2),(-1,3),(-1,6),(-1,-3),(-1,-4),(-1,-7),(0,1),
(0,2),(0,3),(0,7),(0,-2),(0,-3),(0,-4),(0,-8),
(1,2),(1,3),(1,6),(1,-3),(1,-4),(1,-7)}:
self.board[m+p][n-q] = ALIVE
self.running = False
self.draw_board()
####游戏逻辑相关#############################################################################################################################################################################################################################################
def handle_click(self, event):
# 处理鼠标点击事件,设置细胞状态
x, y = event.x // self.cell_size, event.y // self.cell_size
if self.board[x][y] == DEAD:
self.board[x][y] = ALIVE
else:
self.board[x][y] = DEAD
self.draw_board()
def draw_board(self):
# 绘制游戏界面
self.canvas.delete("all")
for x in range(self.width):
for y in range(self.height):
color = COLORS[self.board[x][y]]
self.canvas.create_rectangle(x*self.cell_size, y*self.cell_size,
(x+1)*self.cell_size, (y+1)*self.cell_size,
fill=color, outline="gray")
def start(self):
# 开始演化
self.running = True
self.evolve()
def pause(self):
# 暂停演化
self.running = False
def clear(self):
# 清空细胞
self.board = [[DEAD for _ in range(self.height)] for _ in range(self.width)]
self.draw_board()
def random(self):
# 随机生成初始细胞
global pran
for i in range(self.height):
for j in range(self.width):
rnd = random.random()
if rnd > 1-pran:
self.board[i][j]=ALIVE
self.draw_board()
def count_neighbors(self, x, y):
# 计算某个细胞周围的活细胞数量
count = 0
for i in range(-1, 2):
for j in range(-1, 2):
if i == 0 and j == 0: #除去自身
continue
if x+i < 0 or x+i >= self.width or y+j < 0 or y+j >= self.height: #边界处理
continue
if self.board[x+i][y+j] == ALIVE:
count += 1
return count
def evolve(self):
# 演化一次
if not self.running:
return
new_board = [[DEAD for _ in range(self.height)] for _ in range(self.width)]
for x in range(self.width):
for y in range(self.height):
count = self.count_neighbors(x, y)
if self.board[x][y] == ALIVE:
if count < 2 or count > 3:
new_board[x][y] = DEAD
else:
new_board[x][y] = ALIVE
else:
if count == 3:
new_board[x][y] = ALIVE
self.board = new_board
self.draw_board()
if not self.onestepp:
global speed
self.root.after(1000//speed, self.evolve)#100ms演化一次
else:
self.onestepp = False
def run(self):
# 运行游戏
self.draw_board()
self.root.mainloop()
############################################################################################################################################################################################################################################################
game = GameOfLife(60,60,15)
game.run()
本文介绍了两种不同的Python实现版本,一个是基于pygame的图形化生命游戏,另一个是使用Tkinter构建的界面,包括滑翔机等经典案例的初始化以及细胞状态的计算和演化。文章详细展示了如何计算细胞的活邻居数和应用生命游戏规则。
5万+






