I'm trying to build the famous "Game of Life" of Conway using Python and its library "pygame".
This is the Wikipedia page of the simulation: https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
Code: https://pastebin.com/kKGvshVK
(I post it also at the end of the question because the site told me i must put some code)
I created a long code that should do the following things in order:
checkAlive
that check wheter a cell from a list of cells is alive;neighbour
that gives in output the number of neighbours (using the Moore neighbourhood theory), using checkAlive
inside of it;Now, some technical things. I created the functions that determined the number of neighbours because I didn't understand (for sure) a simple algorithm (The moore algorithm) that should help me made this game. So the things is, i made this function from scratch and it is very long, and at the beginning of it there are multiple exception i made in order to consider when the cell which will be analyzed to determine the number of neighbours it's placed on the border of the screen or on a corner, etc. So please excuse me if this code it's a little messy.
Now, the problem is, I think I've succeded at initialize the cells, but, the cell s doesn't update, also there is no error. I think that inside the main loop it's happening something that blocks the flow, because the print function that should print "Algorithm succesful" doesn't show up, so there is a bug that I didn't understand. That's all, thank you for any answer!
#Conway Game of Life
import pygame
import random
#PYGAME INITIALIZATION
success, failure = pygame.init()
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height)) #Init the screen
time = pygame.time.Clock() #Time from startup
FPS = 5
#Screen Area = 480000 px (width * height)
#Area of a cell = 100px --> 4800 Cell
BLACK = (0, 0, 0)#Live cell
WHITE = (255, 255, 255)#dead cell
class Cell:
""" x: x coordinate
y: y coordinate
size: width and height (same)
alive: int (boolean, 0 o 1), to track the status of a cell (live or dead), at the startup is random
"""
def __init__(self, x, y, alive):
self.x = x
self.y = y
self.size = 10 #it's a square
self.alive = alive
if self.alive == 1:
self.color = BLACK
elif self.alive == 0:
self.color = WHITE
#Function needed in the next function ------------------------------------------------
def checkAlive(cell, cellArray, curr_x, curr_y, counter):
""" Check wheter the current cell near the original cell is alive. If it is alive it adds 1 to the counter
cell: instance of the original cell
cellArray: cell list with all the initialized cells
curr_x: x coordinate of the cell which will be examined
curr_y: y coordinate of the cell which will be examined
counter: variable that is updated whenever a cell near to original has the "alive" attribute == 1
"""
for current_cell in cellArray:
if (current_cell.x == curr_x and current_cell.y == curr_y):
if (current_cell.alive == 1):
counter += 1
#Function to find the neighbours of a cell ---------------------------------------------------
def neighbour(cells, cell):
"""Give as output the number of neighbours of a cell (only neighbours with the alive attribute = 1)
cells: List containing all the instances of the initialized cells
cell: The single instance of cell which will be examined to determine the number of live neighbours
return: number of live neighbours
"""
num_neighbours = 0 #Number of near live cells(Moore neighbourhood)
x = cell.x
y = cell.y
#List of exceptions before the main algorithm
#Upper-left corner (x = 0, y = 0) !*!*!*!*!*!*!*!*!**!*!*!*!*!*!*!*
if (x == 0 and y == 0):
#Cell on the right -----------
current_x = 1
current_y = 0
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below current ----------------------------------------
current_x = 1
current_y = 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below original cell
current_x = 0
current_y = 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Return the number of neighbours
return num_neighbours
#Upper-right corner (x = window, y = 0)!*!*!*!*!**!*!*!*!*!*!*!*!*!*!*!*!*!*!**!*!*!*!*!*!*!*!
elif (x == screen_width - cell.size and y == 0):
#Cell below -------------------------------------
current_x = screen_width - cell.size
current_y = 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the left of current -----------------------------------
current_x -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the left of original
current_y = 0
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Return the number of neighbours
return num_neighbours
#Lower-left corner (x = 0, y = window) !*!*!*!**!*!!*!**!*!!**!*!*!*!*!*
elif(x == 0 and y == (screen_height - cell.size)):
#Cell over original ----------------------
current_x = 0
current_y = (screen_height - cell.size) - 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the right of current ------------------------------------------
current_x += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below current ---------------------------------------------
current_y += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Return the number of neighbours
return num_neighbours
#Lower right corner !*!*!*!*!*!!*!*!*!*!*!*!**!!*!*!*
elif (x == (screen_width - cell.size) and y == (screen_height - cell.size)):
#Cell to the left of original ------------------------------------------------
current_x = (screen_width - cell.size) - 1
current_y = screen_height - cell.size
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell on top of current -------------------------------------------------------
current_y -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the right of current
current_x += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Return the number of neighbours
return num_neighbours
#If the cell is in the first row (y = 0) (2 corners excluded) !*!*!*!*!*!!*!!*!*!*!*!
elif (y == 0 and (x != 0 and x != (screen_width - cell.size))):
#Cell to the right of original
current_x = x + 1
current_y = 0
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below current
current_y += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below original
current_x = x
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the left of current
current_x -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the left of original
current_y -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Return the number of neighbours
return num_neighbours
#If the cell is in the last row (y = screen_height) 2 corners excluded !*!*!*!*!*!*!*!!*!*
elif (y == (screen_height - cell.size) and (x != 0 and x != (screen_width - cell.size))):
#Cell to the left of original
current_x = x - 1
current_y = y
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell on top of current
current_y -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the right of current
current_x += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the right of current
current_x += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below current
current_y += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Return the number of neighbours
return num_neighbours
#If the cell is in the first column (2 corners excluded) !*!*!*!*!*!*!*!*!*!*!*!*
elif (x == 0 and (y != 0 and y != (screen_height - cell.size))):
#Cell on top of original
current_x = x
current_y = y - 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the right of current
current_x += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below current
current_y += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below current
current_y += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the left of current
current_x -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
return num_neighbours
#If the cell is in the last column (x = screen width) !*!*!*!*!*!*!*!!**!!*
elif (x == (screen_width - cell.size) and (y != 0 and y != (screen_height - cell.size))):
#Cell below original
current_x = x
current_y = y + 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the left of current
current_x -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell on top of current
current_y -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell on top of current
current_y -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the right of current
current_x += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
return num_neighbours
#GENERAL RULE
else:
#8 Neighbours
#Cell on top of original
current_x = x
current_y = y - 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the right of original
current_x += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below current
current_y += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell below current
current_y += 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the left of current
current_x -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell to the left of current
current_x -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell on top of current
current_y -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
#Cell on top of current
current_y -= 1
checkAlive(cell, cells, current_x, current_y, num_neighbours)
return num_neighbours
#CELL INITIALIZATION
cell_array = []
#Useful variable in the for loop
x = 0
y = 0
init = False #Become true when Initialization is completed
#Initialization
while not init:
is_alive = random.choices([0,1], weights = (95, 5), k=1)[0]#Randomly spawn cells with probability (Dead 95%, Alive 5 %)
cell = Cell(x, y, is_alive)#Single object
x += cell.size
cell_array.append(cell)
if x == screen_width: #End of a row
x = 0
y += cell.size
if y == screen_height:#Last row
init = True
#DRAWING CELLS
for cl in cell_array:
pygame.draw.rect(screen, cl.color, pygame.Rect(cl.x, cl.y, cl.size, cl.size))#Draw any single cell
pygame.display.flip() #To update the screen
#Debug
print("Initialization Completed.")
done = False #Check whether the program should run
#Main loop
while not done:
#FPS
time.tick(FPS)
#EVENT HANDLER
for event in pygame.event.get():
if event.type == pygame.QUIT: #Exit button
print("Quitting.")
done = True
#SIMULATION --------------------------------------------------------------------
#Run the algorithm of the game and update the screen (Moore algorithm)
for cell in cell_array:
if neighbour(cell_array, cell) in (2, 3): #2 or 3 live neighbours (survive)
cell.alive = 1
elif neighbour(cell_array, cell) < 2: #Few than 2 live neighbours (dies)
cell.alive = 0
elif neighbour(cell_array, cell) > 3: #More than 3 live neighbours (dies)
cell.alive = 0
elif ((cell.alive == 0) and (neighbour(cell_array, cell) == 3)): #Dead cell with 3 live neigh (live)
cell.alive == 1
#Debug
print("Algorithm succesful.")
#DRAWING CELLS
for cl in cell_array:
pygame.draw.rect(screen, cl.color, pygame.Rect(cl.x, cl.y, cl.size, cl.size))
#Debug
print("Cell loaded to the screen")
pygame.display.flip() #To update the screen
There are a lot of bugs here. You should check step by step whether those functions are working. Few examples:
checkAlive
method should probably check something and return whether the current cell near the original cell is alive as you wrote. It doesn't return anything. Instead it changes the value of the counter
which is not returnedcounter
variable is the same in the checkAlive
function as in the neighbour
function the variable num_neighbours
- nope, they are different primitives.alive
property - you don't set the color to the proper one, so the alive
status changes, but the color doesn't change. You should create a setter for alive where you set the color.When you finish changing those issues, you might pass the code and we'll think what else is wrong.