Conway's Game of Life with Python

2020-05-28 18:57发布

问题:

I took a liking to Conway's Game of Life and began to try and write it in python. At this moment I have yet to write any code for the borders of the program so I am just asking for help with what I have right now. I seem to have trouble when initialization a "blinker" formation. Instead of oscillating like it should, it seems to turn itself into a cube.

#File: gameoflife.py
#Description: This is a basic "life" simulation that follows three distinct rules:
#1.Any live cell with fewer than two live neighbours dies
#2.Any live cell with two or three live neighbours lives
#3.Any live cell with more than three live neighbours dies
#4.Any dead cell with exactly three live neighbours becomes a live cell
#A neighbor is deemed as any cell directly horizantal/vertical/diagonal
#meaning there are 9 neighbors to a cell at any time



from graphics import *
import random
from time import sleep


def initial(D,M,win):    
    #Creates the white board background      
    for i in range (11):
        m = [] # rectangle list
        for j in range (11):
            rec = Rectangle(Point(6 + 4 * i, 6 + 4 * j), Point(10 + 4 * i, 10 + 4 * j))

            D[i][j] = 0
            rec.setFill("white")
            rec.draw(win)    
            m.append(rec)
        M.append(m)


def check(x,y,D):
    #Checks all 9 adjacent neihbors to see if "alive" and checks this number
    #means the cell should stay alive(1), die(0), or if already dead come
    #back alive(2)
    counter = 0

    if D[x+1][y] == 1:
        counter += 1
    if D[x-1][y] == 1:
        counter += 1
    if D[x][y+1] == 1:
        counter += 1
    if D[x][y-1] == 1:
        counter +=1
    if D[x+1][y+1] == 1:
        counter+=1
    if D[x+1][y-1] == 1:
        counter+= 1
    if D[x-1][y-1] == 1:
        counter += 1
    if D[x-1][y+1] == 1:
        counter +=1
    if counter<2 or counter>3:
        return 0
    if counter == 2:
        return 1
    if counter == 3:
        return 2



def main():
    win = GraphWin("Game of Life", 700, 600)
    win. setCoords(0, 0, 70, 60)

    #Initialize two dimesion arrays.
    #D records color of grids, M records rectangles
    D = []
    M = []
    C = []

    #initialize the grids to create all "white"
    for i in range(11):
        d = []
        c = []
        for j in range(11):
            d.append(0)
            c.append(0)
        D.append(d)
        C.append(c)

    initial(D,M,win)
    #Initialzes three "alive" units
    D[5][5],D[4][5] ,D[6][5]= 1,1,1
    C[5][5],C[4][5] ,C[6][5]= 1,1,1
    M[5][5].setFill("Black")
    M[4][5].setFill("Black")
    M[6][5].setFill("Black")

    #Contiually checking
    while True:
        #Purposfully not checking the "Borders" of the array
        for i in range (len(D)-1):
            for j in range(len(D[i])-1):
                #If the cell is alive
                if D[i][j] == 1:
                    #If the cell should die
                    if check(i,j,D) == 0:
                        sleep(1)
                        #Sets a temporary list to white
                        C[i][j] = 0
                        #Fills the cell white
                        M[i][j].setFill("White")
                #if the cell is dead
                if D[i][j] == 0:
                    #If the cell should be revived
                    if check(i,j,D) == 2:
                        sleep(1)
                        #Sets a temporary list to black
                        C[i][j] = 1
                        #Fills the cell black
                        M[i][j].setFill("Black")
        #Sets the main list = to the temporary list                
        D = C


main()

回答1:

You will need to swap D and C, and not just assign C to D. As it stands now, D and C will be referring to the same list after the first iteration.



回答2:

Here is a simple algorithm to do Conway's Game of Life in python using a numpy array of arbitrary 2D size:

import numpy

# this function does all the work
def play_life(a):
    xmax, ymax = a.shape
    b = a.copy() # copy grid & Rule 2
    for x in range(xmax):
        for y in range(ymax):
            n = numpy.sum(a[max(x - 1, 0):min(x + 2, xmax), max(y - 1, 0):min(y + 2, ymax)]) - a[x, y]
            if a[x, y]:
                if n < 2 or n > 3:
                    b[x, y] = 0 # Rule 1 and 3
            elif n == 3:
                b[x, y] = 1 # Rule 4
    return(b)

# replace (5, 5) with the desired dimensions
life = numpy.zeros((5, 5), dtype=numpy.byte)

# place starting conditions here
life[2, 1:4] = 1 # a simple "spinner"

# now let's play
print(life)
for i in range(3):
    life = play_life(life)
    print(life)

This is not very efficient, but will certainly get the job done. Replace print(life) with whatever graphical calls you prefer.