You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Conway生命游戏滑翔机运行几代后失效,请求问题排查

Conway's生命游戏滑翔机失效问题排查

问题描述

未参考教程,用Python结合Pygame实现了Conway's生命游戏。程序整体看似正常,但滑翔机(Glider)运行几代后就会失效。尝试过相关帖子的解决方案无效,希望定位问题。预期滑翔机能正常运作,实际几代后失效。

代码实现

main.py

from utils import *
from grid import Grid

running = True
t = Grid(30)

while running:
    pygame.display.set_caption(f'Conways Game of Life <Gen {t.generations}>')
    clock.tick(200)
    screen.fill(background_colour)

    if not t.started:
        t.EditMode()
    else:
        t.Update()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    pygame.display.flip()

grid.py

import cell
from utils import *

class Grid:
    def __init__(self, size):
        self.cells = []
        self.cellSize = size
        self.generations = 0
        self.tick = 1
        self.started = False
        self.GenerateGrid()
    
    def GenerateGrid(self):
        x, y = 0, 0

        while y < screen.get_height():
            while x < screen.get_width():
                c = cell.Cell(self, (x,y), self.cellSize)
                self.cells.append(c)
                x+=self.cellSize
            x = 0
            y+=self.cellSize

    def EditMode(self):
        self.Draw()
        if self.started:
            return
        
        for cell in self.cells:
            if pygame.mouse.get_pressed()[0]:
                if cell.rect.collidepoint(pygame.mouse.get_pos()):
                    cell.state = 1
            if pygame.mouse.get_pressed()[2]:
                if cell.rect.collidepoint(pygame.mouse.get_pos()):
                    cell.state = 0

        keys = pygame.key.get_pressed()
        if keys[pygame.K_RETURN]:
            self.started = True

    def Draw(self):
        for cell in self.cells:
            cell.Draw()

    def Update(self):
        self.Draw()
        self.tick -= 0.05

        if self.tick < 0:
            for cell in self.cells:
                cell.UpdateState()
            
            for cell in self.cells:
                cell.state = cell.nextState
            self.tick = 1
            self.generations+=1

cell.py

from utils import *

class Cell: 
    def __init__(self, grid, position:tuple, size):
        self.grid = grid
        self.size = size
        self.position = pygame.Vector2(position[0], position[1])
        self.rect = pygame.Rect(self.position.x, self.position.y, self.size, self.size)
        self.state = 0
        self.nextState = self.state

    def Draw(self):
        pygame.draw.rect(screen, (0,0,0), self.rect)

        if self.state == 0:
            pygame.draw.rect(screen, (23,23,23), (self.position.x+4, self.position.y+4, self.size-4, self.size-4))
        else:
            pygame.draw.rect(screen, (255,255,255), (self.position.x+4, self.position.y+4, self.size-4, self.size-4))
    
    def UpdateState(self):
        rect = pygame.Rect(self.position.x-self.size, self.position.y-self.size, self.size*3, self.size*3)
        pygame.draw.rect(screen, (0,0,0), rect)
        targetCells = []
        
        for c in self.grid.cells:
            if rect.colliderect(c.rect):
                targetCells.append(c)

        livingAmt = 0
        for c in targetCells:
            if c.rect.x == self.rect.x and c.rect.y == self.rect.y:
                continue
            
            if c.state == 1:
                livingAmt+=1

        if self.state == 1:
            if livingAmt > 3 or livingAmt <2:
                self.nextState = 0
        if self.state ==0:
            if livingAmt == 3:
                self.nextState =1

utils.py

import pygame

background_colour = (23, 23, 23)
screen = pygame.display.set_mode((900, 900))
clock = pygame.time.Clock()

running = True

问题根源

1. 状态转换逻辑不完整(核心原因)

在cell.py的UpdateState方法中,仅处理了存活细胞死亡和死亡细胞复活的情况,未处理:

  • 存活细胞邻居数为2/3时,应保持存活(未设置self.nextState = 1)
  • 死亡细胞邻居数不为3时,应保持死亡(未设置self.nextState = 0)

这导致nextState会保留上一轮的旧值,错误地改变细胞状态,直接导致滑翔机的细胞无故死亡,最终失效。

2. 多余的调试绘图代码

UpdateState中的pygame.draw.rect(screen, (0,0,0), rect)会在每帧绘制覆盖细胞的黑框,干扰视觉效果,且无实际功能。

3. 边界处理缺失(可选)

当前邻居查找逻辑仅能找到网格内的细胞,若滑翔机飞到边缘,边界外的细胞会被视为不存在(即死亡),导致滑翔机因邻居不足而死亡。若需要滑翔机在边缘环绕移动,需添加边界环绕处理。

修复方案

方案1:修复核心状态转换逻辑

修改cell.py的UpdateState方法,补全所有状态转换情况,并移除调试代码:

def UpdateState(self):
    rect = pygame.Rect(self.position.x-self.size, self.position.y-self.size, self.size*3, self.size*3)
    targetCells = []
    
    for c in self.grid.cells:
        if rect.colliderect(c.rect):
            targetCells.append(c)

    livingAmt = 0
    for c in targetCells:
        if c.rect.x == self.rect.x and c.rect.y == self.rect.y:
            continue
        
        if c.state == 1:
            livingAmt+=1

    # 补全所有状态转换逻辑
    if self.state == 1:
        if livingAmt < 2 or livingAmt > 3:
            self.nextState = 0
        else:
            # 存活细胞满足条件,保持存活
            self.nextState = 1
    else:
        if livingAmt == 3:
            self.nextState = 1
        else:
            # 死亡细胞不满足复活条件,保持死亡
            self.nextState = 0

方案2:添加边界环绕功能(可选)

若希望滑翔机在网格边缘环绕移动,需修改网格存储结构和邻居查找逻辑:

  1. 修改grid.py的Grid类,改用二维列表存储细胞,并记录行列数:
class Grid:
    def __init__(self, size):
        self.cellSize = size
        self.generations = 0
        self.tick = 1
        self.started = False
        # 计算网格行列数
        self.cols = screen.get_width() // size
        self.rows = screen.get_height() // size
        self.GenerateGrid()
    
    def GenerateGrid(self):
        # 用二维列表存储细胞,方便按坐标查找
        self.cells = [[None for _ in range(self.cols)] for _ in range(self.rows)]
        for y in range(self.rows):
            for x in range(self.cols):
                pos_x = x * self.cellSize
                pos_y = y * self.cellSize
                # 传递细胞在网格中的坐标(x,y)
                c = cell.Cell(self, (pos_x, pos_y), self.cellSize, (x, y))
                self.cells[y][x] = c
  1. 修改cell.py的Cell类,添加网格坐标属性,并修改UpdateState方法:
class Cell: 
    def __init__(self, grid, position:tuple, size, grid_pos:tuple):
        self.grid = grid
        self.size = size
        self.position = pygame.Vector2(position[0], position[1])
        self.rect = pygame.Rect(self.position.x, self.position.y, self.size, self.size)
        self.grid_pos = grid_pos  # 记录细胞在网格中的坐标(x,y)
        self.state = 0
        self.nextState = self.state

    # Draw方法保持不变...
    
    def UpdateState(self):
        x, y = self.grid_pos
        rows = self.grid.rows
        cols = self.grid.cols
        # 定义8个方向的邻居相对坐标
        neighbor_dirs = [
            (-1, -1), (0, -1), (1, -1),
            (-1, 0),          (1, 0),
            (-1, 1),  (0, 1), (1, 1)
        ]
        livingAmt = 0
        for dx, dy in neighbor_dirs:
            # 边界环绕:取模运算实现 torus 拓扑
            nx = (x + dx) % cols
            ny = (y + dy) % rows
            neighbor = self.grid.cells[ny][nx]
            if neighbor.state == 1:
                livingAmt += 1
        
        # 补全状态转换逻辑
        if self.state == 1:
            self.nextState = 1 if 2 <= livingAmt <=3 else 0
        else:
            self.nextState = 1 if livingAmt ==3 else 0

验证

修复后,滑翔机的细胞状态会正确遵循生命游戏规则,不会无故死亡;若添加了边界环绕,滑翔机碰到边缘后会从对面重新出现,持续移动。

内容的提问来源于stack exchange,提问作者Kesh S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 11:31:02