0

I am currently adapting electronut's "A simple Python matplotlib implementation of Conway's Game of Life" to run without the use of the numpy module (not for any reason but for my own entertainment and practice). I believe I'm running into this issue as described in other posts regarding problems with implementing Conway's Game of Life. This is the result of my code so far. I believe that my cells are updating before they are supposed to; however, I don't understand how that could be given the fact that I am updating cells on a copied grid and swapping the copied grid in an entirely different function. Any help would be appreciated, at this point I'm more curious as to what is causing this issue than I am frustrated with it. Here's my code:

# 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

1 Answers1

1

The big problem you have is this statement:

newGrid = grid.copy()

list.copy() does not do a deep copy. grid is a list of 100 sublists. When you do that copy, it does create a new list, but that list contains references to the same 100 sublists as the original grid. I suggest you start with an empty newgrid and fill it in. Here's the relevant section of code. I changed your random setup to a slider to prove that it's working.

#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

Note that you don't need global unless you assign a new value to the global, which you don't do here. Even so, you might consider passing grid in as a parameter instead of using a global. Globals are evil.

Tim Roberts
  • 48,973
  • 4
  • 21
  • 30