如何简洁检查二维列表中细胞邻居数,实现边缘循环边界
元胞自动机循环边界邻居计数的简洁实现
问题描述
编写元胞自动机时,细胞存活(值为1)的概率随邻居数量增加而提升,但检查棋盘边缘或角落细胞的邻居数时会报错——比如无法访问最右侧细胞右侧的细胞状态。希望实现循环边界(即最右侧的右侧对应最左侧,最底部的底部对应最顶部),但不想通过大量位置判断来实现(这会让amt()函数代码量激增约9倍,过于冗余),需要更简洁的实现方式。
解决方案
核心思路是用取模运算处理循环边界:对偏移后的行列索引取棋盘的尺寸模,自动将超出边界的索引映射到对面的有效索引,无需任何位置判断。具体步骤:
- 定义所有8个邻居的行列偏移量列表
- 遍历每个偏移量,计算邻居的行列索引(
(col + dc) % csize、(row + dr) % rsize) - 统计所有存活邻居的数量
这种方式代码简洁,且能完美处理边缘、角落的循环边界问题。
修改后的完整代码
from random import randint board = [] csize = 69 rsize = 69 # 初始化棋盘 for col in range(csize): board.append([]) for row in range(rsize): board[col].append(1 if col == 0 else 0) def ranize(): for col in range(csize): for row in range(rsize): board[col][row] = randint(0, 1) def check(): for col in range(csize): for row in range(rsize): if board[col][row] == 1: return True return False def show(): loc = "\n" for col in range(csize): for row in range(rsize): if board[col][row] == 1: loc += "@ " else: loc += f"{amt(col, row)} " loc += "\n" print(loc, end="\r") def amt(col, row): neighbor_count = 0 # 定义8个邻居的行列偏移量 offsets = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] for dc, dr in offsets: # 取模运算实现循环边界 neighbor_col = (col + dc) % csize neighbor_row = (row + dr) % rsize if board[neighbor_col][neighbor_row] == 1: neighbor_count += 1 return neighbor_count def onestep(): if not check(): input("所有细胞已死亡,按回车键随机初始化棋盘: ") ranize() # 先创建新棋盘存储状态,避免遍历中覆盖原状态导致错误 new_board = [[0 for _ in range(rsize)] for _ in range(csize)] for col in range(csize): for row in range(rsize): neighbors = amt(col, row) ranum = randint(0, 8) if board[col][row] == 1: new_board[col][row] = 0 if (8 - neighbors) > ranum else 1 else: new_board[col][row] = 1 if neighbors > ranum else 0 # 更新全局棋盘 global board board = new_board while True: show() onestep()
额外说明
原代码的onestep()函数存在逻辑问题:直接在遍历过程中修改board会导致后续细胞的邻居计数基于已修改的状态,而非初始状态。修改后的代码先创建new_board存储新状态,遍历完成后再替换原棋盘,保证每一步的状态更新基于上一步的完整棋盘。
内容的提问来源于stack exchange,提问作者aecy four
相关产品推荐
相关产品推荐

