康威生命游戏(Python+Tkinter)邻居计数问题排查求助
康威生命游戏:邻居计数与状态更新问题修复
问题根源分析
你的代码存在四个核心问题,导致运行效果不符合预期:
- 邻居计数重复/遗漏:
get_neighbours函数重复计算了(x-1, y+1)方向的邻居,同时遗漏了(x+1, y-1)方向的邻居,导致计数结果错误。 - 新状态矩阵未重置:
cells_new在每次迭代后未被重置为全0,上一轮的状态会残留到下一次计算中。 - 固定维度变量不更新:
absvs变量固定为初始值10,当通过滑块调整vs后,矩阵维度和循环范围不匹配,导致逻辑混乱。 - 矩阵引用赋值错误:
cells = cells_new是引用传递,后续修改cells_new会直接影响cells的状态。
修复方案
1. 修正邻居计数函数
重新编写get_neighbours,遍历所有8个可能的邻居方向,每个方向仅判断一次,写法更简洁且避免遗漏:
def get_neighbours(x, y, grid): rows, cols = grid.shape total = 0 # 遍历8个方向的偏移量,跳过自身 for dx in (-1, 0, 1): for dy in (-1, 0, 1): if dx == 0 and dy == 0: continue nx = x + dx ny = y + dy # 判断邻居是否在网格范围内 if 0 <= nx < rows and 0 <= ny < cols: total += grid[nx, ny] return total
2. 修复状态更新逻辑
在recalculate中,每次迭代前重新创建cells_new避免状态残留,使用拷贝赋值而非引用传递:
def recalculate(): global cells rows, cols = cells.shape # 每次迭代重新创建新矩阵 cells_new = np.zeros((rows, cols), dtype=int) for x in range(rows): for y in range(cols): neighbor_count = get_neighbours(x, y, cells) # 应用康威生命游戏规则 if cells[x, y] == 1: cells_new[x, y] = 1 if (neighbor_count == 2 or neighbor_count == 3) else 0 else: cells_new[x, y] = 1 if neighbor_count == 3 else 0 # 使用拷贝赋值,避免引用问题 cells = cells_new.copy() canvas.delete("all") create_stage() redraw_cell()
3. 修复滑块调整逻辑
滑块调整vs时,重新初始化cells矩阵匹配新网格大小,去掉冗余的absvs变量:
def slider_changer(e): global vs, cells canvas.delete("all") vs = w.get() # 重新初始化细胞矩阵 cells = np.zeros((WIDTH//vs, HEIGHT//vs), dtype=int) create_stage() redraw_cell()
4. 修正细胞创建边界判断
create_cell函数中增加边界判断,避免点击超出网格范围导致的错误:
def create_cell(e): global cells tx = e.x // vs ty = e.y // vs rows, cols = cells.shape if 0 <= tx < rows and 0 <= ty < cols: x = tx * vs y = ty * vs canvas.create_rectangle(x, y, x + vs, y + vs, fill="gray") cells[tx, ty] = 1
完整修复代码
import tkinter as tk import numpy as np win = tk.Tk() WIDTH = 500 HEIGHT = 500 vs = 10 cells = np.zeros((WIDTH//vs, HEIGHT//vs), dtype=int) def get_neighbours(x, y, grid): rows, cols = grid.shape total = 0 for dx in (-1, 0, 1): for dy in (-1, 0, 1): if dx == 0 and dy == 0: continue nx = x + dx ny = y + dy if 0 <= nx < rows and 0 <= ny < cols: total += grid[nx, ny] return total def recalculate(): global cells rows, cols = cells.shape cells_new = np.zeros((rows, cols), dtype=int) for x in range(rows): for y in range(cols): neighbor_count = get_neighbours(x, y, cells) if cells[x, y] == 1: cells_new[x, y] = 1 if (neighbor_count == 2 or neighbor_count == 3) else 0 else: cells_new[x, y] = 1 if neighbor_count == 3 else 0 cells = cells_new.copy() canvas.delete("all") create_stage() redraw_cell() def slider_changer(e): global vs, cells canvas.delete("all") vs = w.get() cells = np.zeros((WIDTH//vs, HEIGHT//vs), dtype=int) create_stage() redraw_cell() def create_cell(e): global cells tx = e.x // vs ty = e.y // vs rows, cols = cells.shape if 0 <= tx < rows and 0 <= ty < cols: x = tx * vs y = ty * vs canvas.create_rectangle(x, y, x + vs, y + vs, fill="gray") cells[tx, ty] = 1 def redraw_cell(): rows, cols = cells.shape for x in range(rows): for y in range(cols): if cells[x, y] == 1: canvas.create_rectangle(x * vs, y * vs, x * vs + vs, y * vs + vs, fill="gray") def create_stage(): for x in range(WIDTH//vs): canvas.create_line(x*vs, 0, x*vs, HEIGHT) for y in range(HEIGHT//vs): canvas.create_line(0, y*vs, WIDTH, y*vs) canvas = tk.Canvas(width=WIDTH, height=HEIGHT, bg="white") canvas.pack() w = tk.Scale(win, from_=10, to=50, orient="horizontal", command=slider_changer, length=500) w.pack() w2 = tk.Button(win, text="PRESS ME!!!", command=recalculate) w2.pack() create_stage() canvas.bind("<Button-1>", create_cell) win.mainloop()
内容的提问来源于stack exchange,提问作者Boggelino
相关产品推荐
相关产品推荐

