为什么我的 Conway's Game of Life 更新不正确?

问题描述

我目前正在调整 electronut 的“A simple Python matplotlib implementation of Conway's Game of Life”以在不使用 numpy 模块的情况下运行(不是出于任何原因,而是为了我自己的娱乐和练习)。我相信我遇到了 this issue,如其他帖子中描述的有关实施康威生命游戏的问题。 This is the result of my code so far. 我相信我的细胞比它们应该更新的更早;但是,我不明白我正在更新复制的网格上的单元格并在完全不同的函数中交换复制的网格这一事实。任何帮助将不胜感激,在这一点上,我更好奇是什么导致了这个问题,而不是我对此感到沮丧。这是我的代码

# based off of electronut's "A simple Python matplotlib implementation of Conway's Game of Life"
# https://gist.github.com/electronut/5836145

import matplotlib.pyplot as plt 
import matplotlib.animation as animation
import random as rnd

#init biz
cellCount = 100
ALIVE = 255
DEAD = 0

# states in which a cell can exist
states = [ALIVE,DEAD]

#generate initial grid
grid = [[rnd.choice(states) for i in range(cellCount)] for j in range(cellCount)]

#return a new grid for next generation
def nextGen():
    global grid
    newGrid = grid.copy()
    for i in range(cellCount):
        for j in range(cellCount):
            #calculate neighbor total
            total = (grid[(i-1)%cellCount][j] + grid[(i+1)%cellCount][j] + 
                grid[i][(j-1)%cellCount] + grid[i][(j+1)%cellCount] + 
                grid[(i-1)%cellCount][(j-1)%cellCount] + grid[(i+1)%cellCount][(j+1)%cellCount] +
                grid[(i+1)%cellCount][(j-1)%cellCount] + grid[(i-1)%cellCount][(j+1)%cellCount])/255
            if grid[i][j] == ALIVE:
                if (total < 2) or (total > 3):
                    newGrid[i][j] = DEAD
            else:
                if total == 3:
                    newGrid[i][j] = ALIVE
    return newGrid

#update global grid using next gen grid
def update(data):
    global grid
    new = nextGen()
    mat.set_data(new)
    grid = new
    return [new]

#matplotlib magic
fig,ax = plt.subplots()
mat = ax.matshow(grid)
ani = animation.FuncAnimation(fig,update,interval=100,save_count=50)
plt.show()

Game of life rules not working properly

解决方法

你遇到的大问题是这个声明:

newGrid = grid.copy()

list.copy() 不做深拷贝。 grid 是一个包含 100 个子列表的列表。当您进行该复制时,它会创建一个新列表,但该列表包含对与原始网格相同的 100 个子列表的引用。我建议你从一个空的 newgrid 开始并填写它。这是代码的相关部分。我将您的随机设置更改为滑块以证明它有效。

#generate initial grid
#grid = [[rnd.choice(states) for i in range(cellCount)] for j in range(cellCount)]
grid = [[0 for i in range(cellCount)] for j in range(cellCount)]
grid[10][10] = grid[10][11] = grid[10][12] = ALIVE
grid[11][12] = grid[12][11] = ALIVE

#return a new grid for next generation
def nextGen():
    newGrid = []
    for i in range(cellCount):
        newRow = []
        for j in range(cellCount):
            #calculate neighbor total
            total = (grid[(i-1)%cellCount][j] + grid[(i+1)%cellCount][j] +
                grid[i][(j-1)%cellCount] + grid[i][(j+1)%cellCount] +
                grid[(i-1)%cellCount][(j-1)%cellCount] + grid[(i+1)%cellCount][(j+1)%cellCount] +
                grid[(i+1)%cellCount][(j-1)%cellCount] + grid[(i-1)%cellCount][(j+1)%cellCount])//255
            if grid[i][j] == ALIVE:
                if (total < 2) or (total > 3):
                    newRow.append( DEAD )
                else:
                    newRow.append( ALIVE )
            else:
                if total == 3:
                    newRow.append( ALIVE )
                else:
                    newRow.append( DEAD )
        newGrid.append(newRow)
    return newGrid

请注意,除非您为全局分配一个新值,否则您不需要 global,您在此处不这样做。即便如此,您也可以考虑将 grid 作为参数传入,而不是使用全局变量。全局是邪恶的。