+ 实现康威生命游戏 康威生命游戏介绍
康威生命游戏是一种零玩家游戏,它属于元胞自动机的一种。1970 年,数学家约翰·康威发明了它。生命游戏在一个无限的二维网格上进行,每个格子代表一个细胞,这些细胞有两种状态,即存活或死亡。
细胞的下一个状态由其周围八个邻居细胞的状态来决定。具体规则如下:(康威生命游戏的规则是)
一个存活的细胞周围若有 2 个存活的邻居,该细胞在下一代中会继续存活;一个存活的细胞周围若有 3 个存活的邻居,该细胞在下一代中也会继续存活。
一个死亡的细胞周围有 3 个存活的邻居时,该细胞在下一代会变为存活状态。
在除特定情况外的其他情形里,一个细胞要么一直处于死亡状态,要么会转变为死亡状态。
游戏进行时,细胞群体会历经多代的演化,可能会有以下几种情形:
细胞群体停止了变化,达到了稳定状态。这意味着所有的细胞都遵循规则 1 和规则 2,并且没有细胞死亡或新生。
摆动(振荡)状态:细胞群体存在两种或多种状态,且在这些状态之间循环变化。每过几代,细胞群体就会回到最初的状态。
细胞群体在网格中以整体的方式移动。每过一代,细胞群体的位置会发生改变,然而其形状却保持不变。
处于灭绝状态,原因是所有细胞都已死亡。在这种状态下,倘若没有新细胞被添加进游戏,网格将会一直处于空白状态,因为已经不存在可以复活或新生的细胞了。
细胞群体处于持续变化之中,未呈现出稳定的模式,也未展现出摆动的模式,更未显示出移动的模式。
需要注意的是,康威生命游戏属于确定性游戏。这意味着,只要给定一个初始状态,下一代的状态就能够确定下来,不会依赖于随机因素。也就是说,倘若从相同的初始配置开始,每次运行游戏都会获得相同的结果。所以,上述所描述的所有可能的情况都是可以进行预测的。游戏是确定性的。某些模式可能非常复杂。预测它们的长期行为在实践中可能非常困难。尤其对于大型和复杂的初始配置更是如此。
康威生命游戏的代码
下面给出 + 实现康威生命游戏的代码
关于安装使用可参见
关于安装使用可参见
该游戏操作规则:
按空格键暂停/启动。
左键单击可添加活动单元格,右键单击可删除单元格。
先给出效果图:
代码如下:
import pygame
import numpy as np
# 初始化Pygame
pygame.init()
# 设置窗口大小
width, height = 800, 600
pygame.display.set_mode((width, height)) 这个操作被赋值给了 screen 变量
# 设置颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
# 设置网格大小
rows, cols = 60, 80
cell_size = width // cols
# 创建网格数组
创建一个二维数组 grid,其形状为 (rows, cols),并初始化为全 0,数据类型为 int。即通过 np.zeros((rows, cols), dtype=int) 来实现。
# 初始化一些细胞为存活状态
grid[28, 37] = 1
grid[28, 38] = 1
grid[29, 39] = 1
grid[30, 40] = 1
grid[31, 41] = 1
grid[32, 39] = 1
grid[32, 40] = 1
grid[32, 41] = 1
# 计算细胞的邻居数量
计算邻居数量。需要给定网格 grid,以及行 row 和列 col。通过对网格中特定位置的邻居进行计数来实现。
return sum([
grid 中 (row - 1) 对 rows 取余后的值,以及 (col - 1) 对 cols 取余后的值所对应的元素
grid[(row - 1) % rows, col],
grid 中,行坐标为 (row - 1) 对 rows 取余,列坐标为 (col + 1) 对 cols 取余的位置处的元素
grid[row, (col - 1) % cols],
grid[row, (col + 1) % cols],
grid 中,行坐标为 (row + 1) 对 rows 取余后的值,列坐标为 (col - 1) 对 cols 取余后的值所对应的元素
grid[(row + 1) % rows, col],
grid 中,行坐标为 (row + 1) 对 rows 取余,列坐标为 (col + 1) 对 cols 取余所对应的元素
])
# 游戏循环
running = True
pause = True # 开始时暂停游戏
while running:
screen.fill(WHITE)
# 处理事件
对于每个事件:
if event.type == pygame.QUIT:
running = False
如果事件的类型等于 pygame 的 MOUSEBUTTONDOWN 事件
pygame.mouse 获取到当前鼠标的位置,该位置被分别存储在 col 和 row 变量中。
col = col // cell_size
row = row // cell_size
if event.button == 1: # 左键
grid[row, col] = 1
elif event.button == 3: # 右键
grid[row, col] = 0
如果事件的类型是 pygame.KEYDOWN 。
如果事件的键等于 pygame 中的 K_SPACE 键

按空格键可以使游戏暂停,同时按空格键也可以让游戏开始。
# 绘制网格线
for row in range(rows):
for col in range(cols):
rect 等于 pygame 中的 Rect 类,其左上角的坐标为 col 乘以 cell_size,纵坐标为 row 乘以 cell_size,宽度为 cell_size,高度也为 cell_size
if grid[row, col] == 1:
在屏幕上绘制一个矩形,矩形的颜色是黑色,矩形的位置和大小由 rect 决定。
pygame 用 screen、GRAY、rect 和 1 来绘制网格线,具体是通过 pygame.draw.rect 函数进行绘制的。
# 更新网格
if not pause:
new_grid = grid.copy()
for row in range(rows):
for col in range(cols):
邻居数量 = 计算邻居数量(网格, 行, 列)
如果网格中的[row, col]位置的值为 1 并且其邻居们< 2 or neighbors > 3):
new_grid[row, col] = 0
如果 grid 数组中位于[row, col]位置的元素为 0 并且其相邻元素的数量为 3
new_grid[row, col] = 1
grid = new_grid
pygame.display.flip()
pygame.time.delay(100)
# 退出Pygame
pygame.quit()
代码改进
对这个代码进行修改,以协助这个程序,添加一个功能,即按下 F1 键时能弹出提供游戏帮助信息的对话框。
这里通过创建一个弹出的对话框来展示帮助信息。要注意的是,它和另一个(东西)都有各自的事件循环,在游戏中直接调用可能会引发问题。一种解决办法是采用多线程,把对话框置于一个单独的线程里。
首先,将标准库中的库添加进来。接着,在初始化的部分创建一个变量,这个变量用于存储对话框的状态。
...
=
#接着,创建一个新的函数用于显示对话框:
def ():
= True
as tk
from
root = tk.Tk()
root.() # 隐藏主窗口
.("游戏帮助",
"- 单击鼠标左键放置细胞\n"
"- 单击鼠标右键移除细胞\n"
"- 按空格键开始/暂停游戏\n"
"- 按F1键显示此帮助")
root.()
=
首先,对处理 F1 键按下事件的代码进行修改。接着,让该代码在一个新的线程中运行。最后,通过这样的方式打开对话框。
将
if .type == .:
if .key == .:
= not # 按空格键暂停或开始游戏
部分,改为:
if .type == .:
if .key == .:
= not # 按空格键暂停或开始游戏
如果.key 等于.K_F1,那么就按下 F1 键,并且会弹出提示对话框。
if not :
.(=).()
为照顾新手,下面给出改进后的完整代码:
import pygame
import numpy as np
import threading #
存储对话框状态的变量是 dialog_open ,且其初始值为 False 。
#接着,创建一个新的函数用于显示对话框
def show_help_dialog():
global dialog_open
dialog_open = True
import tkinter as tk
使用 tkinter 库中的 messagebox
root = tk.Tk()
root.withdraw() # 隐藏主窗口
messagebox.showinfo("游戏帮助",
"- 单击鼠标左键放置细胞\n"
"- 单击鼠标右键移除细胞\n"
"- 按空格键开始/暂停游戏\n"
"- 按F1键显示此帮助")
root.destroy()
dialog_open = False
# 初始化Pygame
pygame.init()
# 设置窗口大小
width, height = 800, 600
screen = pygame.display.set_mode((width, height))
# 设置颜色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
# 设置网格大小
rows, cols = 60, 80
cell_size = width // cols
# 创建网格数组
grid = np.zeros((rows, cols), dtype=int)
# 初始化一些细胞为存活状态
grid[28, 37] = 1
grid[28, 38] = 1
grid[29, 39] = 1
grid[30, 40] = 1
grid[31, 41] = 1
grid[32, 39] = 1
grid[32, 40] = 1
grid[32, 41] = 1
# 计算细胞的邻居数量
def count_neighbors(grid, row, col):
return sum([
grid[(row - 1) % rows, (col - 1) % cols],
grid[(row - 1) % rows, col],
grid[(row - 1) % rows, (col + 1) % cols],
grid[row, (col - 1) % cols],
grid[row, (col + 1) % cols],
grid[(row + 1) % rows, (col - 1) % cols],
grid[(row + 1) % rows, col],
grid[(row + 1) % rows, (col + 1) % cols]
])
# 游戏循环
running = True
pause = True # 开始时暂停游戏
while running:
screen.fill(WHITE)
# 处理事件
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
col, row = pygame.mouse.get_pos()
col = col // cell_size
row = row // cell_size
if event.button == 1: # 左键
grid[row, col] = 1
elif event.button == 3: # 右键
grid[row, col] = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
pause = not pause # 按空格键暂停或开始游戏
如果事件的键等于 pygame 库中的 K_F1 键,那么就会弹出提示对话框。
if not dialog_open:
创建一个线程,其目标函数是 show_help_dialog,然后启动该线程。
# 绘制网格线
for row in range(rows):
for col in range(cols):
rect = pygame.Rect(col * cell_size, row * cell_size, cell_size, cell_size)
if grid[row, col] == 1:
pygame.draw.rect(screen, BLACK, rect)
pygame.draw.rect(screen, GRAY, rect, 1) # 绘制网格线
# 更新网格
if not pause:
new_grid = grid.copy()
for row in range(rows):
for col in range(cols):
neighbors = count_neighbors(grid, row, col)
if grid[row, col] == 1 and (neighbors < 2 or neighbors > 3):
new_grid[row, col] = 0
elif grid[row, col] == 0 and neighbors == 3:
new_grid[row, col] = 1
grid = new_grid
pygame.display.flip()
pygame.time.delay(100)
# 退出Pygame
pygame.quit()
版权声明:本文为 “博览广文网” 原创文章,转载请附上原文出处链接及本声明;
工作时间:8:00-18:00
客服电话
0755-88186625
电子邮件
admin@lanyu.com
扫码二维码
获取最新动态