简体   繁体   中英

I've been making conway's game of life in python, why doesn't it work?

So there must be something wrong with the code which detects wether it should be alive or not in Cell.update(), but the glider i hardcoded in is not working as intended. The first and second generations work as intended, but on the third it dies out. Anyone know what the problem is? I know the code is a bit messy, but I'm quite new to python so it is expected. Thanks in advance!

Here is the code:

import pygame

"""
rules:

1. Any live cell with two or three live neighbours survives.
2. Any dead cell with three live neighbours becomes a live cell.
3. All other live cells die in the next generation. Similarly, all other dead cells stay dead.

number cells on screen = 32x18
cell size = 30x30
"""

# variables
WIDTH = 960
HEIGHT = 540
TITLE = "Conway's Game Of Life"

GRID_COLOUR = (200, 200, 200)
BG_COLOUR = (255, 255, 255)

grid = [[False] * 32] * 18
cells = []

live_queue = []
die_queue = []

# window
wn = pygame.display.set_mode((WIDTH, HEIGHT), vsync=1)
pygame.display.set_caption(TITLE)


# classes
class Cell:
    def __init__(self, x, y, alive, index_x, index_y):
        self.x = x
        self.y = y
        self.alive = alive
        self.indexX = index_x
        self.indexY = index_y

    def die(self):
        self.alive = False

    def live(self):
        self.alive = True

    def get_index(self):
        return self.indexX, self.indexY

    def update(self):
        grid_temp = grid[self.indexY]
        grid_temp.pop(self.indexY)
        grid_temp.insert(self.indexY, self.alive)

        grid.pop(self.indexY)
        grid.insert(self.indexX, grid_temp)

        adjacent_alive = 0
        for i in cells:
            if i.x == self.x - 30 and i.y == self.y and i.alive:
                adjacent_alive += 1
            elif i.x == self.x + 30 and i.y == self.y and i.alive:
                adjacent_alive += 1
            elif i.x == self.x and i.y == self.y - 30 and i.alive:
                adjacent_alive += 1
            elif i.x == self.x and i.y == self.y + 30 and i.alive:
                adjacent_alive += 1
            elif i.x == self.x - 30 and i.y == self.y - 30 and i.alive:
                adjacent_alive += 1
            elif i.x == self.x - 30 and i.y == self.y + 30 and i.alive:
                adjacent_alive += 1
            elif i.x == self.x + 30 and i.y == self.y - 30 and i.alive:
                adjacent_alive += 1
            elif i.x == self.x + 30 and i.y == self.y + 30 and i.alive:
                adjacent_alive += 1

        if self.alive:
            if adjacent_alive < 2:
                return False
            elif adjacent_alive > 3:
                return False
            else:
                return True
        if not self.alive:
            if adjacent_alive == 3:
                return True
            else:
                return False

    def render(self):
        if self.alive:
            pygame.draw.rect(wn, (0, 0, 0), (self.x, self.y, 30, 30))


# functions
def render_grid():
    for y in range(0, HEIGHT, 30):
        pygame.draw.line(wn, GRID_COLOUR, (0, y), (WIDTH, y))

    for x in range(0, WIDTH, 30):
        pygame.draw.line(wn, GRID_COLOUR, (x, 0), (x, HEIGHT))


def parse_to_x_y(x, y):
    return x * 30, y * 30


def parse_to_index(x, y):
    return int(x / 30), int(y / 30)


indexX = 0
indexY = 0
x_pos = 0
y_pos = 0
for y_ in range(18):
    for x_ in range(32):
        cells.append(Cell(x_pos, y_pos, False, indexX, indexY))
        indexX += 1
        x_pos += 30
    y_pos += 30
    x_pos = 0
    indexY += 1
cells[2].live()
cells[35].live()
cells[65].live()
cells[66].live()
cells[67].live()

# main loop
fps = 1
clock = pygame.time.Clock()
while True:
    # start_time = time.time()

    wn.fill(BG_COLOUR)

    for item in cells:
        item.render()
    render_grid()

    # events loop
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            quit()

    for item in cells:
        if item.update():
            live_queue.append(item)
        else:
            die_queue.append(item)
    for i in live_queue:
        i.live()
    for i in die_queue:
        i.die()
    pygame.display.update()
    clock.tick(fps)
    # end_time = time.time()
    # print(round(1 / (end_time - start_time)), "fps")

The problem is that you don't reset your queues in the main loop.

So add this before adding to the queues:

live_queue = []   # <----
die_queue = []    # <----
for item in cells:
    if item.update():
        live_queue.append(item)
    else:
        die_queue.append(item)

Some other remarks

You never use grid or grid_temp in a useful way. Even the operations you make on them are strange. Any way, you can just remove all references to them.

You never use the indexX or indexY attributes, nor the method around it, nor the corresponding arguments to the constructor. All that can go.

You should avoid scanning all the cells just to find the (up to) 8 neighbors of one cell: this has a bad impact on performance.

I agree with commenter Rabbid76, in that you need to update the entire grid at once, not cell by cell. This is usually done by using two separate grids , an "previous state" grid and a "new state grid". Loop through each position in the "new state" grid and calculate its number of live neighbors using the "previous state" grid. After the entire "new state" grid is calculated, you can copy to "new state" grid to the "old state" grid.

Another fatal flaw in your algorithm is grid = [[False] * 32] * 18 . This will not work as expected in Python . With this code, each row is a reference to the same array. For instance, the expression grid[0] is grid[1] will evaluate to True . If you set a certain cell in the grid to true, the entire column will be set to true. You can fix this via the code:

grid=[]
for r in range(18):
    row=[]
    for c in range(32):
        row.append(False)
    grid.append(row)

Though it isn't directly related to the bug, I suggest a bit of a redesign of your algorithm. It is not really needed to encapsulate each cell in a class; doing so creates a redundancy between the grid and list of cells. This also leads you to identify cells by their pixel position (hence the ix == self.x - 30 clause), which can easily lead to bugs. I suggest checking adjacent indices in the grid variable instead. Try looking into https://www.geeksforgeeks.org/conways-game-life-python-implementation/ for some inspiration.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM