0

for my own self development project I am creating John Conway's game of life in python but I have come across a problem. My code is compiling with no errors but when executed it is running not as I expect it to run. my code is as follows:

from tkinter import *
from random import *
import time
import copy

PIXEL_SIZE = 10
ROW = 910
COLUMN = 700
#updated_grid = [[]]

def create_grid(r, c):
    grid = []
    for row in range(0, r):
        grid2 = []
        for column in range(0, c):
            grid2.append(randint(0, 1))
        grid.append(grid2)
    return grid


grid = create_grid(ROW, COLUMN)
updated_grid = create_grid(ROW, COLUMN)


def draw_grid():
    for row in range(0, ROW):
        for column in range(0, COLUMN):
            if grid[row][column] == 1:
                x0 = row*PIXEL_SIZE
                y0 = column*PIXEL_SIZE
                x1 = x0+PIXEL_SIZE
                y1 = y0+PIXEL_SIZE
                canvas.create_rectangle(x0, y0, x1, y1, fill='red')


def apply_rules():
    for row in range(1, ROW - 1):
        for column in range(1, COLUMN - 1):
            neighbours_count = 0
            # will count the neighbours for each cell
            neighbours_count += grid[row-1][column-1] # top left
            neighbours_count += grid[row][column-1] # top center
            neighbours_count += grid[row+1][column-1] # top right

            neighbours_count += grid[row-1][column] # middle left
            neighbours_count += grid[row+1][column] # middle right

            neighbours_count += grid[row-1][column+1] # bottom left
            neighbours_count += grid[row][column+1] # bottom center
            neighbours_count += grid[row+1][column+1] # bottom right

            # Game Of Life rules:

            # alive cell rules
            if grid[row][column] == 1:
                if neighbours_count < 2: # rule 1 any live cell with fewer than two live neighbours dies, as if by underpopulation
                    updated_grid[row][column] = 0
                elif neighbours_count == 2 | neighbours_count == 3: # rule 2 any live cell with two or three live neighbours lives on to the next generation
                    updated_grid[row][column] = 1
                elif neighbours_count > 3 & neighbours_count <= 8: # rule 3 any live cell with more than three live neighbours dies, as if by overpopulation
                    updated_grid[row][column] = 0
                else:
                    updated_grid[row][column] = 0
            elif grid[row][column] == 0: # dead cells rule 4 any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction
                if neighbours_count == 3:
                    updated_grid[row][column] = 1
                else:
                    updated_grid[row][column] = 0
    for row in range(0, ROW):
        for column in range(0, COLUMN):
            grid[row][column] = updated_grid[row][column]


def one_cycle():
    apply_rules()
    draw_grid()
    window.after(1, one_cycle)


window = Tk() # creates the window for the game
window.title('Game Of Life Python') # is the game title written on the window
canvas_frame = Frame(window) # creates a frame on the window to hold the canvas
game_title = Frame(window) # creates a frame on the window to display the game title (which will be a label)
start_button = Button(window, text='Start Game', command=one_cycle) # creates a button which will be used to start the game
canvas = Canvas(canvas_frame, width=ROW, height=COLUMN, background='black') # creates the canvas used to the draw the game of life
game_title_label = Label(game_title, text='Game Of Life', font='Helvetica 20 bold', fg='grey') # creates the label for the game title which will be placed in a frame

canvas.grid(row=0, column=0) # places the canvas onto the canvas_frame
canvas_frame.grid(row=1, column=1) # places the canvas_frame onto the window
game_title_label.grid(rowspan=2, column=0) # places the title of the game onto the game_title frame
game_title.grid(row=0, columnspan=2) # places the frame for the game title onto the window
start_button.grid(rowspan=2, column=1) # places the start onto the window

window.mainloop()

From going through the code I can only think that the error is somewhere in appy_rules() method (I may be wrong) but I still cannot figure out why the animation is not being redrawn but it is drawing on top of each other. I am new to python so any help you may be able to will be very much appreciated, thank you again.

user2152012
  • 161
  • 1
  • 4
  • 17
  • Please update your question with an exact description of the problem. `running incorrectly` is not very precise. – quamrana May 15 '20 at 14:55

3 Answers3

2

I see two major things:

You create 100 times the amount of rectangles as you need and thats why it may feel slow. With:

PIXEL_SIZE = 10
ROW = 91          # One tenth of original value
COLUMN = 70       # One tenth of original value

you can create canvas as:

canvas = Canvas(canvas_frame, width=PIXEL_SIZE*ROW,
                height=PIXEL_SIZE*COLUMN, background='black')

and then use ROW & COLUMN as before. Otherwise you will create 910*700 rectangles on canvas for each draw_grid().

Then you don't delete the previous rectangles from canvas when you draw it. Just add a delete statement to the draw_grid():

def draw_grid():
    canvas.delete('all')
    # rest of code...

I haven't checked if your rules work as intended but this should be a start.

figbeam
  • 7,001
  • 2
  • 12
  • 18
  • thanks for the help the animation is redrawing instead of cells being drawn on top of what is already there and it is much faster. But something is still not quite right it appears to be running too fast. – user2152012 May 15 '20 at 18:38
  • 1
    The `after()` function works in milliseconds, so you start a new cycle one millisecond after you have redrawn the grid. Adjust to your liking. – figbeam May 16 '20 at 16:01
1

Sorry, I should have remembered this bit when I fixed your code before. Actually your implementation of the rules are not quite right:

            # Game Of Life rules:

            # alive cell rules
            if grid[row][column] == 1:
                if neighbours_count < 2:
                    updated_grid[row][column] = 0
                elif neighbours_count == 2 or neighbours_count == 3: # rule 2 needs OR
                    updated_grid[row][column] = 1
                elif neighbours_count > 3 and neighbours_count <= 8: # rule 3 needs AND
                    updated_grid[row][column] = 0
                else:
                    updated_grid[row][column] = 0
            else: # dead cells rule 4 (can be done with else:)
                if neighbours_count == 3:
                    updated_grid[row][column] = 1

You have used the binary or (|) and binary and (&) instead of the logical versions.

quamrana
  • 37,849
  • 12
  • 53
  • 71
0

a generally good practice is to put a bunch of test print functions throughout your code so you can see where the code fails by looking at the last string that was printed. these strings are written so as to describe the thing the code just did. try doing this in the spot where you think your code is failing.

David
  • 424
  • 3
  • 16