Conway's Game of Life

Started by
3 comments, last by Lactose 9 years ago

Hello,
I've been attempting to recreate Conway's Game of Life using Python and Pygame. It's sort of working, but I think there's an issue with the logic of checking whether or not a cell lives or dies. I have it seeded to a common start pattern, but the cells only change once and then they stay as is.

I followed the 4 "rules" of the game located here.


Would appreciate anyone more familiar with Python and/or The Game of Life to have a look at this and provide any suggestions.
Thanks!


__author__ = 'me myself and I'
import pygame, sys
from pygame.locals import *

pygame.init()

FPS = 30

WIDTH = 120
HEIGHT = 120
CELL_WIDTH = 5
CELL_HEIGHT = 5

WHITE = (255, 255, 255)
BLACK = (0,0,0)



fpsClock = pygame.time.Clock()

DISPLAYSURF = pygame.display.set_mode((600, 600), 0, 32)

board = []
for r in range(0, WIDTH-1):
  board.append([])
  for c in range(0, HEIGHT-1):
    board[r].append('o')

def debug_board():
  for row in board:
    print row
    print "\n"

def init_board(board):
  board[55][55] = 'x'
  board[56][55] = 'x'
  board[57][55] = 'x'

  board[56][53] = 'x'

  board[51][55] = 'x'
  board[51][54] = 'x'
  board[50][54] = 'x'

def draw_board(board):
  for y, row in enumerate(board):
    for x, col in enumerate(board[y]):
      if board[x][y] == 'x':
        pygame.draw.rect(DISPLAYSURF, BLACK, ((CELL_WIDTH*x),(CELL_HEIGHT*y),CELL_WIDTH,CELL_HEIGHT))

#don't worry about edges for now
def get_live_neighbors(x, y, board):
  try:
    if x >= 1 and y >= 1 and x < (WIDTH - 2) and y < (HEIGHT - 2):
      live = 0
      if board[x-1][y] == 'x':
        live += 1
      if board[x+1][y] == 'x':
        live += 1
      if board[x][y+1] == 'x':
        live += 1
      if board[x][y-1] == 'x':
        live += 1
      if board[x+1][y+1] == 'x':
        live += 1
      if board[x-1][y-1] == 'x':
        live += 1
      if board[x+1][y-1] == 'x':
        live += 1
      if board[x-1][y+1] == 'x':
        live += 1
      return live
  except IndexError:
    print x
    print y

def check_neighbors(board):
  for y, row in enumerate(board):
    for x, col in enumerate(board[y]):
      #live cell fewer than 2 neighbors dies
      if board[x][y] == 'x' and get_live_neighbors(x,y,board) < 2:
        board[x][y] = 'o'
        continue

      #live cell 2 or 3 live neigbors lives on
      elif board[x][y] == 'x' and (get_live_neighbors(x,y,board) == 2 or get_live_neighbors(x,y,board) == 3):
        board[x][y] = 'x'
        continue

      #live cell with more than three live neighbors dies
      elif board[x][y] == 'x' and get_live_neighbors(x,y,board) > 3:
        board[x][y] = 'o'
        continue

      #dead cell with exactly 3 live neighbors becomes live
      elif board[x][y] == 'o' and get_live_neighbors(x,y,board) == 3:
        board[x][y] = 'x'
        continue

pygame.display.set_caption('Hello World!')
DISPLAYSURF.fill(WHITE)
init_board(board)


while True: # main game loop


  for event in pygame.event.get():
    if event.type == QUIT:
      pygame.quit()
      sys.exit()
    elif event.type == KEYDOWN:
      if event.key == K_ESCAPE:
        pygame.quit()
        sys.exit()

  draw_board(board)
  check_neighbors(board)


  pygame.time.delay(1000)


  pygame.display.update()
  fpsClock.tick(FPS)

Advertisement

This is an instance of a really large class of logic errors that can be surprisingly hard to debug. The problem is that you're modifying the board in-place, so when you go to check the neighbours of the (0, 0) cell, you're going to be changing that cell based on whether it lives or dies, but then you move on to the (1, 0) cell, which has (0, 0) as a neighbour, but the (0, 0) cell is now the "new cell" since you just changed it, but the game of life algorithm is based on each cell at time T+1 depending on their neighbours at time T... and this is the bug that you are observing, see?

Basically you want to make a copy of the board and put your changes in there, and then replace the old board with the new one once every cell has been checked.

PS: for what it's worth, I had the exact same bug years ago back when I was starting to program, when I first played around with cellular automata... took me a whole week to figure it out!!

“If I understand the standard right it is legal and safe to do this but the resulting value could be anything.”

Glad I'm not alone in my struggle! I will try what you suggested (copying and replacing the board) and see what happens. Thanks a bunch.

If you're going to create a copy of the board as it is, maybe it's better to just make a second copy of the board do a double buffer trick. Instead of copying the board each time, just keep a pointer to the current board. On each cycle, you read from the current board and save results into the "offscreen" board. When you're done, you just do

temp = current_board

current_board = next_board

next_board = temp // EDIT: Thanks Lactose!

and redraw the current board to the screen.

Yo dawg, don't even trip.


temp = current_board
current_board = next_board
current_board = temp

temp = current_board
current_board = next_board
next_board = temp

Hello to all my stalkers.

This topic is closed to new replies.

Advertisement