Search code examples
pythonnumpymatplotlibanimationconways-game-of-life

Game of Life in Python: problem with matplotlib animation


My matplotlib animation function is not running. Any suggestions are much appreciated. As result, there should be an animation running from current to new generation (using the new_state function).

"state" is the current array which is a random array. That is passed into the new_state function and should be displayed as an animation.

'''
The code should generate John Conway's Game of Life, resulting in an animation that represents a transition from current
state to new state. This update of generations are based on the rules found here https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life.

'''
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

'''This function creates an array of elements of zeros, with a specified width and height.'''
def dead_state(height, width):
    array = np.zeros((height,width), dtype=int)
    return array


'''This function generates an array with random elements of ones and zeroes, with a specified width and height.'''
def random_state(width, height):
    array = np.random.randint(0, high=2, size=(width, height), dtype=int)
    return array


'''This function plots the array.'''
def plot(array):
    plt.imshow(array)
    plt.show()


def new_state(array):
    array_padded = np.pad(array, 1)
    updated_array=array.copy()
    for x in range(1, array.shape[0]+1):
        for y in range(1, array.shape[1]+1):
            cell = array[x-1][y-1]
            neighbours = (array_padded[x-1][y-1], array_padded[x][y-1], array_padded[x+1][y-1],
                          array_padded[x+1][y], array_padded[x+1][y+1], array_padded[x][y+1],
                          array_padded[x-1][y+1], array_padded[x-1][y])
            neighbours_count = sum(neighbours)
            if cell == 1:
                if neighbours_count == 0 or neighbours_count == 1 or neighbours_count > 3:
                    updated_array[x-1,y-1]=0
                elif neighbours_count == 2 or neighbours_count == 3:
                    updated_array[x-1,y-1]=1
            elif cell == 0:
                if neighbours_count == 3:
                    updated_array[x-1,y-1]=1
    return updated_array


state = random_state(20,20)


im = plt.imshow(state)
plt.show()


def animate(frame):
    im.set_data(new_state(state))
    return im


"""Running the code below should generate the animation"""

fig = plt.figure()
animation.FuncAnimation(fig, animate, frames=200, interval=50)
plt.show()

Solution

  • I'm no matplotlib expert, but I'd guess this is closer to what you wanted:

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.animation as animation
    
    def dead_state(height, width):
        array = np.zeros((height,width), dtype=int)
        return array
    
    def random_state(width, height):
        array = np.random.randint(0, high=2, size=(width, height), dtype=int)
        return array
    
    def new_state(array):
        array_padded = np.pad(array, 1)
        updated_array=array.copy()
        for x in range(1, array.shape[0] + 1):
            for y in range(1, array.shape[1] + 1):
                cell = array[x - 1][y - 1]
                neighbours = (array_padded[x - 1][y - 1], array_padded[x][y - 1],
                              array_padded[x + 1][y - 1], array_padded[x + 1][y],
                              array_padded[x + 1][y + 1], array_padded[x][y + 1],
                              array_padded[x - 1][y + 1], array_padded[x - 1][y])
                neighbours_count = sum(neighbours)
                if cell == 1:
                    if 0 <= neighbours_count <= 1 or neighbours_count > 3:
                        updated_array[x - 1,y - 1] = 0
                    else:
                        updated_array[x - 1,y - 1] = 1
                elif cell == 0:
                    if neighbours_count == 3:
                        updated_array[x - 1,y - 1] = 1
        return updated_array
    
    state = random_state(20,20)
    def animate(frame):
        global state
        state = new_state(state)
        plt.imshow(state)
    
    fig = plt.figure()
    anim = animation.FuncAnimation(fig, animate, frames=200, interval=50)
    plt.show()
    anim()