Search code examples
pythonspyderpython-3.8conways-game-of-life

ATBS Conway's Game of Life code doesnt seem right


I just started learning python with the help of automatetheboringstuff.com i'm in Chapter 4 right now, trying to understand the Conway's Game of Life code. I understand the game rules but the codes result looks wrong to me and i'm not sure if the code is actually wrong or i didn't understand the rules.

An example (imgur picture) why i think its wrong. The red dot shows a dead cell which has 3 living neighbours which means it should be alive in the next step but it stays empty(dead). Yellow dot shows the same problem. Green has 1 living neighbour and it stay alive but it should not.

# Conway's Game of Life
import random, time, copy
WIDTH = 60
HEIGHT = 20

# Create a list of list for the cells:
nextCells = []
for x in range(WIDTH):
    column = [] # Create a new column.
    for y in range(HEIGHT):
        if random.randint(0, 1) == 0:
            column.append('#') # Add a living cell.
        else:
            column.append(' ') # Add a dead cell.
    nextCells.append(column) # nextCells is a list of column lists.

while True: # Main program loop.
    print('\n\n\n\n\n') # Separate each step with newlines.
    currentCells = copy.deepcopy(nextCells)

    # Print currentCells on the screen:
    for y in range(HEIGHT):
        for x in range(WIDTH):
            print(currentCells[x][y], end='') # Print the # or space.
        print() # Print a newline at the end of the row.

    # Calculate the next step's cells based on current step's cells:
    for x in range(WIDTH):
        for y in range(HEIGHT):
            # Get neighboring coordinates:
            # `% WIDTH` ensures leftCoord is always between 0 and WIDTH - 1
            leftCoord  = (x - 1) % WIDTH
            rightCoord = (x + 1) % WIDTH
            aboveCoord = (y - 1) % HEIGHT
            belowCoord = (y + 1) % HEIGHT

            # Count number of living neighbors:
            numNeighbors = 0
            if currentCells[leftCoord][aboveCoord] == '#':
                numNeighbors += 1 # Top-left neighbor is alive.
            if currentCells[x][aboveCoord] == '#':
                numNeighbors += 1 # Top neighbor is alive.
            if currentCells[rightCoord][aboveCoord] == '#':
                numNeighbors += 1 # Top-right neighbor is alive.
            if currentCells[leftCoord][y] == '#':
                numNeighbors += 1 # Left neighbor is alive.
            if currentCells[rightCoord][y] == '#':
                numNeighbors += 1 # Right neighbor is alive.
            if currentCells[leftCoord][belowCoord] == '#':
                numNeighbors += 1 # Bottom-left neighbor is alive.
            if currentCells[x][belowCoord] == '#':
                numNeighbors += 1 # Bottom neighbor is alive.
            if currentCells[rightCoord][belowCoord] == '#':
                numNeighbors += 1 # Bottom-right neighbor is alive.

            # Set cell based on Conway's Game of Life rules:
            if currentCells[x][y] == '#' and (numNeighbors == 2 or
numNeighbors == 3):
                # Living cells with 2 or 3 neighbors stay alive:
                nextCells[x][y] = '#'
            elif currentCells[x][y] == ' ' and numNeighbors == 3:
                # Dead cells with 3 neighbors become alive:
                nextCells[x][y] = '#'
            else:
                # Everything else dies or stays dead:
                nextCells[x][y] = ' '
    time.sleep(1) # Add a 1-second pause to reduce flickering.

Solution

  • It looks to me as if this implementation wraps the grid around from top to bottom and from side to side. Cells in the top row therefore have neighbours in the bottom row (and vice versa), and cells in the leftmost column have neighbours in the rightmost column (and vice versa). So:

    • The red cell doesn't come to life because it has five living neighbours: three of them are the cells you've already identified, and the other two are above it and above-and-to-the-left. Both of these two other have wrapped around to the bottom row.

    • Similarly, the yellow cell has a fourth neighbour, diagonally down and to the left of it. This has wrapped around to the rightmost column.

    • The green cell that stays alive has two neighbours, one to its right and one above it (wrapping around again).

    Ultimately, if you're going to write an implementation of Conway's Game Of Life on a finite grid you need to decide what happens at the edges of the grid. It seems the author of this code chose to have the grid wrap around.