PyGame中的康威生命游戏

3

我阅读了Conway's Game of Life的相关内容,并尝试使用PyGame实现它。

我试图将其面向对象化。它的工作方式是,我有一个细胞实例列表,然后检查它们周围有多少邻居,然后根据它们的邻居保持活着或死亡。然后该过程重复。

问题在于,当我使用一些已知的起始模式进行测试时(例如,在下面的代码中(CELL_MAP)),它的工作方式并不正确。

我一遍遍地阅读代码,但我真的不知道我错过了什么。我在下面发布了整个代码,但如果有人能指点我方向,我将不胜感激。

提前感谢!

import pygame

class Cell:
    def __init__(self, live, xcor, ycor):
        self.alive = live
        self.x = xcor
        self.y = ycor
        self.neighbours = 0

def checkNeighbours(self, cellList):
    for cell in cellList:
        #left
        if cell.x == self.x-1 and cell.y == self.y and cell.alive == True:
            self.neighbours += 1        
        #right
        elif cell.x == self.x+1 and cell.y == self.y and cell.alive == True:
            self.neighbours += 1 
        #upleft
        elif cell.x == self.x-1 and cell.y == self.y-1 and cell.alive == True:
            self.neighbours += 1     
        #up
        elif cell.x == self.x and cell.y == self.y-1 and cell.alive == True:
            self.neighbours += 1 
        #upright
        elif cell.x == self.x+1 and cell.y == self.y-1 and cell.alive == True:
            self.neighbours += 1     
        #downleft
        elif cell.x == self.x-1 and cell.y == self.y+1 and cell.alive == True:
            self.neighbours += 1     
        #down
        elif cell.x == self.x and cell.y == self.y+1 and cell.alive == True:
            self.neighbours += 1 
        #downright
        elif cell.x == self.x+1 and cell.y == self.y+1 and cell.alive == True:
            self.neighbours += 1 

def breed(self):
    if self.alive == False and self.neighbours == 3:
        #dead cell ressurects if neighbours equals 3
        self.alive = True
    elif self.alive and self.neighbours < 2:
        #die from loneliness
        self.alive = False
    elif self.alive and self.neighbours == 2:
        #stay alive
        pass
    elif self.alive and self.neighbours == 3:
        #stay alive
        pass
    elif self.alive and self.neighbours > 3:
        #die from overpopulation
        self.alive = False

def render(self, display):
    if self.alive:
        pygame.draw.rect(display, (0,0,0), [self.x*10, self.y*10, 10, 10])
    elif self.alive == False:
        pygame.draw.rect(display, (0,0,255), [self.x*10, self.y*10, 10, 10])




WID = 33
HEI = 20            
CELL_MAP = [[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,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,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,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,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,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,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,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,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,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,0,0,0,0,0,1,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,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,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,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]]

CELL_LIST = []

xc = -1
yc = -1
for yList in CELL_MAP:
    yc += 1
    for x in yList:
        xc += 1
        if x == 0:
            #create dead cell
            newCell = Cell(False, xc, yc)
            CELL_LIST.append(newCell)
        elif x == 1:
            #create alive cell
            newCell = Cell(True, xc, yc)
            CELL_LIST.append(newCell)
    xc = -1



#pygame init

pygame.init()
(width, height) = (WID*10, HEI*10)

pygame.display.set_caption('Game of Life')

screen = pygame.display.set_mode((width, height))

#game loop

def gameLoop():
    gameLoop = True 

    while gameLoop:
        #check for exit
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                gameLoop = False
                pygame.quit()               

        #render cells
        for cell in CELL_LIST:
            cell.render(screen)    

        #check neighbours
        for cell in CELL_LIST:
            cell.checkNeighbours(CELL_LIST)

        pygame.display.flip()

        #breed
        for cell in CELL_LIST:
            cell.breed()

        pygame.time.wait(5)

    quit()

if __name__ == "__main__":
    gameLoop()

尝试将 cell.render(screen) cell.checkNeighbours(CELL_LIST) cell.breed() 放在同一个 for 循环中。这样看起来更好吗? - rassar
1个回答

4
我没有安装pygame,所以无法运行您的代码。不过引起错误的bug是,在确定细胞在下一代中是否存活后,您没有将其邻居计数重置为零。因此,在每个代中,每个细胞的新邻居计数都会被加到先前累积的邻居计数中。您应该在.breed方法中进行这种重置。
以下是该方法的更简洁版本:
def breed(self):
    self.alive = self.neighbours == 3 or self.alive and self.neighbours == 2
    self.neighbours = 0

我对你的代码有几个评论。

你的checkNeighbours方法非常低效:对于每个单元格,它扫描整个网格以查找单元格的邻居!一个简单的替代方案是将单元格存储在2D列表中,这样您可以快速定位单元格的邻居。


这是一种比你当前代码更紧凑的构建CELL_LIST的方法:

CELL_LIST = []
for y, row in enumerate(CELL_MAP):
    for x, v in enumerate(row):
        CELL_LIST.append(Cell(v == 1, x, y))

以下是列表推导式的相同内容:

CELL_LIST = [Cell(bool(v), x, y)
    for y, row in enumerate(CELL_MAP)
        for x, v in enumerate(row)
]

但正如我之前所说,将CELL_LIST变成一个二维列表可能是个好主意:

cell_list = [[Cell(bool(v), x, y) for x, v in enumerate(row)]
    for y, row in enumerate(CELL_MAP)]

你的CELL_MAP不是一个方便的方法来将生命游戏图案放入你的程序中,但我想它对于测试目的来说还可以。看一下我本月早些时候写的这个答案,里面提供了一个替代方法。

最终,你应该让你的程序能够读取许多生命游戏程序都使用的常见RLE格式

你可能还想看看我写的另一个相当高效的版本,它使用了Numpy:numpy_life.py。像我链接的另一个版本一样,在Linux终端中显示输出,但这两个版本都很容易适应pygame或其他GUI框架。


非常感谢,我知道它一定是如此简单的事情。并且感谢您对代码的评论,这确实有助于提高我的编码风格。 - sorh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接