Python Forum

Full Version: Game Logic problem with a "The Game of Life" Replication
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello everyone!
This is my first post here, I hope I won't mess up...
I'm currently trying to replicate The game of Life ( https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life ) in Python with Pygame. But when I launched it, it didn't follow the rules. Some cells with no neighbours were still printed, and when I printed their neighbour number it didn't match the printed cells.

Let's hope you will understand my code.
(Some parts of the code are in french, my appologies. But I think it won't be a problem to understand anyway)

First, I created a class:
class Cell:
    def __init__(self, ligne, colonne):
        self.life = False
        self.color = ROUGE
        self.neighbours = 0
        self.ligne = ligne
        self.colonne = colonne
        self.position= pyvecteur.Vecteur(self.colonne*20,self.ligne*20)
In the main code I created a list with every cell in it :

cells=[]

for l in range (0,10):
    for c in range (0,10):
        cells.append(Cell(l,c))
Then, the tricky part where I wanted to count each neighbour around each cell. (This is why there is a parameter "neighbours" in the cell class.)

    for f in range (len(cells)):
        ##Neighbours cells' Initialization to create empty ones when the cell is next to a border
        C1 = Cell(cells[f].ligne - 1, cells[f].colonne - 1)
        C2 = Cell(cells[f].ligne - 1,cells[f].colonne)
        C3 = Cell(cells[f].ligne - 1,cells[f].colonne + 1)
        C4 = Cell(cells[f].ligne,cells[f].colonne - 1)
        C5 = Cell(cells[f].ligne,cells[f].colonne + 1)
        C6 = Cell(cells[f].ligne + 1,cells[f].colonne - 1)
        C7 = Cell(cells[f].ligne + 1,cells[f].colonne)
        C8 = Cell(cells[f].ligne + 1,cells[f].colonne + 1)
        ##Initialization
        cells[f].neighbours = 0
        for e in range (len(cells)): #Scans each cell to see if it is one of the current cell (f) neighbour


            if cells[e].colonne == cells[f].colonne - 1:

                if cells[e].ligne == cells[f].ligne - 1:
                    C1=cells[e]
                if cells[e].ligne == cells[f].ligne:
                    C4=cells[e]
                if cells[e].ligne == cells[f].ligne + 1:
                    C6=cells[e]


            if cells[e].colonne == cells[f].colonne:

                if cells[e].ligne == cells[f].ligne - 1:
                    C2 = cells[e]
                if cells[e].ligne == cells[f].ligne + 1:
                    C7 =cells[e]


            if cells[e].colonne == cells[f].colonne + 1:

                if cells[e].ligne == cells[f].ligne - 1:
                    C3 = cells[e]
                if cells[e].ligne == cells[f].ligne:
                    C5 = cells[e]
                if cells[e].ligne == cells[f].ligne + 1:
                    C8 = cells[e]


        cells[f].count_neighbours(C1,C2,C3,C4,C5,C6,C7,C8) ##registers neighbours' number
I know it's a bit complicated for what it is supposed to do but I didn't figured out any other way to count neighbours. I think it is here that the problem occures. I wanted to count the neighbours first instead of changing the state immediatly because it would have changed the next cell's neighbour number.

Then, when each Cell has their neighbour parameter filled I update their state:
(The rules are, a living cell can only survive if it has 2 or 3 neighbours and a dead cell can become a living cell if it has exactly 3 neighbours)
#In the main code:
    for c in range(len(cells)): ##Update each cell's state
        cells[c].new_state()
#the function:

    def new_state(self):

        if not self.life:
            if self.neighbours == 3:
                self.life = True
            else:
                self.life = False

        if self.life:
            if self.neighbours == 2:
                self.life = True
            if self.neighbours == 3:
                self.life = True

            if self.neighbours >= 4:
                self.life = False
            if self.neighbours <= 1:
                self.life = False
Then I draw every cell (after the Grid pattern background drawing):
    for e in range (len(cells)):
        if cells[e].life:
            cells[e].draw(fenetre)  ##Draws alive cells
Thank you very much for reading my post! I really want to find a solution Huh ... The worst about this problem is that I really don't know where it comes from...


PS: Maybe there are some typing mistakes in the code, I could'nt launch it to check before posting because I have some troubles with my computer and Python Confused . Anyway I didn't really change the code since the last time I tested it and it had worked fine, without "errors" (just my logical problem)
I don't see an obvious errors in the neighbors calculation, but it does seem overly complex. I would store the cells in a data structure where any cell could easily be found by it's coordinates. Either a list of lists, so the two indexes are the coordinate, or a dictionary keyed to tuples of the coordinates. Then, if you know what the coordinate of a cell is, you can find the neighbors easily, because you know their coordinates too. Then find the neighbors ONCE, at the start of the program, and store each cell's neighbors in a list attributes of the cell. Then override the __add__ and __radd__ of the cells to just add their life attribute (you can do this straight up, bool is a sub-class of int). Then, every turn all you have to do is sum(cell.neighbors) to find out how many living neighbors you have.

Also note that when updating the cell's life attribute, you don't need to set it if it is not going to change. This is all you need:

live_neighbors = sum(self.neighbors)
if not self.life and live_neighbors  == 3:
    self.life = True
elif self.life and live_neighbors not in (2, 3):
    self.life = False
This will simplify your code tremendously. Simpler code is less likely to have bugs, and easier to find bugs in.
Thank you very much for your advice!
I will learn how to use dictionaries and lists of lists and try that way.