Conway的《人生游戏》的Python实现

时间:2019-02-06 22:04:05

标签: python conways-game-of-life

出于学习目的,我开始创建Conway的《人生游戏》的实现。我使用numpy来存储大数组,处理死细胞和活细胞,然后遵循Conway的规则来创建细胞生命机制。为了管理网格和图形,我使用了pygame模块。 经过多次审查,并以多种方式重写了代码,我无法找出问题出在哪里,所以我决定问您。例如,我尝试制作滑翔机(如代码所示),但他在3个循环周期后死亡。谢谢您的帮助和提示。你能帮我找出为什么细胞不繁殖吗?提前致谢。 代码:

import pygame
import numpy as np

BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
N = 195
WIDTH = 10
HEIGHT = 10

grid = np.zeros(shape=(N, N), dtype=np.int32)
glider = np.array([[0, 0, 1],
                       [1, 0, 1],
                       [0, 1, 1]])
grid[3:6, 3:6] = glider

pygame.init()

WINDOW_SIZE = [980, 980]
screen = pygame.display.set_mode(WINDOW_SIZE)

pygame.display.set_caption("GAME OF LIFE")

done = False

clock = pygame.time.Clock()

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
    for row in range(N):
        for column in range(N):
            color = BLACK
            if grid[row][column] == 1:
                color = GREEN
            pygame.draw.rect(screen, color,
                             [WIDTH * column,
                              HEIGHT * row,
                              WIDTH,
                              HEIGHT])

    newGrid = grid.copy()
    for i in range(N):
        for j in range(N):
            total = grid[(i-1) % N:(i+1) % N, (j-1) % N:(j+1) % N].sum() - grid[i, j]
            if grid[i, j] == 1:
                if(total < 2) or (total > 3):
                    newGrid[i, j] = 0
                else:
                    if total == 3:
                        newGrid[i, j] = 1
    grid = newGrid

    clock.tick(60)
    pygame.display.flip()

pygame.quit()

2 个答案:

答案 0 :(得分:2)

我认为您在实现Conway's rules的方式中存在一些细微的错误。 有关详细信息,请参见代码中的评论:

for i in range(N):
    for j in range(N):
        # I changed the range of the extent of the sum, note +2 rather than +1 !
        total = grid[(i-1) % N:(i+2) % N, (j-1) % N:(j+2) % N].sum() - grid[i, j]
        if grid[i, j] == 1:
            if(total < 2) or (total > 3):
                newGrid[i, j] = 0
            # allow for survival in case of total = 2 or 3 (this could be dropped though)
            else:
                newGrid[i, j] = 1
        # allow for reproduction if cell is empty
        else:
            if total == 3:
                newGrid[i, j] = 1

通过这些修改,滑翔机应该滑行:)

答案 1 :(得分:0)

也许newGrid循环中的else子句过度缩进了?因为到目前为止,网格仅从1变为0,从不从0变为1。这可能是由于数组切片:[(i-1)%n:(i + 1)%n]。有2个问题:

  1. 这仅计入(i + 1)%n之前的索引,因此不包括(i + 1)%n。
  2. 它并没有像您期望的那样环绕,例如[9:1]不会从9变为10到0,而是在1之前停止。它只是返回空列表。

这是个把戏

a.take(range(-1,2),mode='wrap', axis=0).take(range(-1,2),mode='wrap',axis=1)

来自该帖子Wrap slice around edges of a 2D array in numpy。我已使用此技巧修改了以下代码。

import pygame
import numpy as np

BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
N = 195
WIDTH = 10
HEIGHT = 10

grid = np.zeros(shape=(N, N), dtype=np.int32)
glider = np.array([[0, 0, 1],
                       [1, 0, 1],
                       [0, 1, 1]])
grid[3:6, 3:6] = glider

pygame.init()

WINDOW_SIZE = [980, 980]
screen = pygame.display.set_mode(WINDOW_SIZE)

pygame.display.set_caption("GAME OF LIFE")

done = False

clock = pygame.time.Clock()

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
    for row in range(N):
        for column in range(N):
            color = BLACK
            if grid[row][column] == 1:
                color = GREEN
            pygame.draw.rect(screen, color,
                             [WIDTH * column,
                              HEIGHT * row,
                              WIDTH,
                              HEIGHT])

    newGrid = grid.copy()
    for i in range(N):
        for j in range(N):
            total = grid.take(range(i-1,i+2),mode='wrap', axis=0).take(range(j-1,j+2),mode='wrap',axis=1).sum() - grid[i, j]
            if grid[i, j] == 1:
                if(total < 2) or (total > 3):
                    newGrid[i, j] = 0
            else:
                if total == 3:
                    newGrid[i, j] = 1
    grid = newGrid

    clock.tick(60)
    pygame.display.flip()

pygame.quit()