简体   繁体   English

我一直在用 python 制作康威的生活游戏,为什么它不起作用?

[英]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.因此,在 Cell.update() 中检测它是否应该活着的代码一定有问题,但是我硬编码的滑翔机没有按预期工作。 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.我知道代码有点乱,但我对 python 很陌生,所以这是意料之中的。 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.您永远不会以有用的方式使用gridgrid_temp 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.您永远不会使用indexXindexY属性,也不要使用它周围的方法,也不要使用构造函数的相应参数。 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.您应该避免仅仅为了找到一个单元格的(最多)8 个相邻单元格而扫描所有单元格:这会对性能产生不良影响。

I agree with commenter Rabbid76, in that you need to update the entire grid at once, not cell by cell.我同意评论者 Rabbid76 的观点,因为您需要一次更新整个网格,而不是逐个单元格。 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 .算法中的另一个致命缺陷是grid = [[False] * 32] * 18 This will not work as expected in Python .这在 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 .例如,表达式grid[0] is grid[1]将评估为True If you set a certain cell in the grid to true, the entire column will be set to true.如果将网格中的某个单元格设置为 true,则整列都将设置为 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.这也会引导您通过像素位置识别单元格(因此ix == self.x - 30子句),这很容易导致错误。 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.尝试查看https://www.geeksforgeeks.org/conways-game-life-python-implementation/以获得一些灵感。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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