我在python一直在制作康威的人生游戏,为什么它不起作用?
I've been making conway's game of life in python, why doesn't it work?
所以在 Cell.update() 中检测它是否应该活着的代码一定有问题,但我硬编码的滑翔机没有按预期工作。第一代和第二代按预期工作,但在第三代就消失了。有人知道问题出在哪里吗?我知道代码有点乱,但我对 python 很陌生,所以这是意料之中的。提前致谢!
代码如下:
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")
问题是您没有在主循环中重置队列。
所以在添加到队列之前添加:
live_queue = [] # <----
die_queue = [] # <----
for item in cells:
if item.update():
live_queue.append(item)
else:
die_queue.append(item)
其他一些说明
您永远不会以有用的方式使用 grid
或 grid_temp
。甚至您对它们所做的操作也很奇怪。无论如何,您可以删除所有对它们的引用。
您永远不会使用 indexX
或 indexY
属性,也不会使用它周围的方法,也不会使用构造函数的相应参数。能去的都去。
您应该避免扫描 所有 个单元格只是为了找到一个单元格的(最多)8 个邻居:这对性能有不良影响。
我同意评论者 Rabbid76 的观点,因为 你需要一次更新整个网格,而不是逐个单元地更新。 这通常通过使用 two 来完成单独的网格,一个“先前状态”网格和一个“新状态网格”。循环遍历“新状态”网格中的每个位置,并使用“先前状态”网格计算其存活邻居的数量。整个“新状态”网格计算完成后,可以将“新状态”网格复制到“旧状态”网格。
你算法的另一个致命缺陷是grid = [[False] * 32] * 18
。 这在 Python 中不会像预期的那样工作。使用此代码,每一行都是对同一数组的引用。例如,表达式 grid[0] is grid[1]
的计算结果将是 True
。如果将网格中的某个单元格设置为 true,则整个列都将设置为 true。您可以通过以下代码解决此问题:
grid=[]
for r in range(18):
row=[]
for c in range(32):
row.append(False)
grid.append(row)
虽然它与错误没有直接关系,但我建议对您的算法进行一些重新设计。并不是真的需要将每个单元封装在一个 class 中;这样做会在网格和单元格列表之间创建冗余。这也会导致您通过像素位置来识别单元格(因此 i.x == self.x - 30
子句),这很容易导致错误。我建议改为检查网格变量中的相邻索引。尝试查看 https://www.geeksforgeeks.org/conways-game-life-python-implementation/ 以获取一些灵感。
所以在 Cell.update() 中检测它是否应该活着的代码一定有问题,但我硬编码的滑翔机没有按预期工作。第一代和第二代按预期工作,但在第三代就消失了。有人知道问题出在哪里吗?我知道代码有点乱,但我对 python 很陌生,所以这是意料之中的。提前致谢!
代码如下:
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")
问题是您没有在主循环中重置队列。
所以在添加到队列之前添加:
live_queue = [] # <----
die_queue = [] # <----
for item in cells:
if item.update():
live_queue.append(item)
else:
die_queue.append(item)
其他一些说明
您永远不会以有用的方式使用 grid
或 grid_temp
。甚至您对它们所做的操作也很奇怪。无论如何,您可以删除所有对它们的引用。
您永远不会使用 indexX
或 indexY
属性,也不会使用它周围的方法,也不会使用构造函数的相应参数。能去的都去。
您应该避免扫描 所有 个单元格只是为了找到一个单元格的(最多)8 个邻居:这对性能有不良影响。
我同意评论者 Rabbid76 的观点,因为 你需要一次更新整个网格,而不是逐个单元地更新。 这通常通过使用 two 来完成单独的网格,一个“先前状态”网格和一个“新状态网格”。循环遍历“新状态”网格中的每个位置,并使用“先前状态”网格计算其存活邻居的数量。整个“新状态”网格计算完成后,可以将“新状态”网格复制到“旧状态”网格。
你算法的另一个致命缺陷是grid = [[False] * 32] * 18
。 这在 Python 中不会像预期的那样工作。使用此代码,每一行都是对同一数组的引用。例如,表达式 grid[0] is grid[1]
的计算结果将是 True
。如果将网格中的某个单元格设置为 true,则整个列都将设置为 true。您可以通过以下代码解决此问题:
grid=[]
for r in range(18):
row=[]
for c in range(32):
row.append(False)
grid.append(row)
虽然它与错误没有直接关系,但我建议对您的算法进行一些重新设计。并不是真的需要将每个单元封装在一个 class 中;这样做会在网格和单元格列表之间创建冗余。这也会导致您通过像素位置来识别单元格(因此 i.x == self.x - 30
子句),这很容易导致错误。我建议改为检查网格变量中的相邻索引。尝试查看 https://www.geeksforgeeks.org/conways-game-life-python-implementation/ 以获取一些灵感。