两种生命游戏(Game of Life)实现结果迥异的原因排查
为什么两个生命游戏版本运行结果不同?
我来帮你分析一下核心原因——问题出在版本2的逻辑漏洞上,尤其是生命游戏规则里最容易被忽略的细节,加上初始化的遗漏,导致结果完全偏离预期。
首先先明确两个版本的设计差异:
- 版本1用单个
state字段记录细胞状态,先一次性计算所有细胞的邻居数,再统一更新状态 - 版本2拆分出
current(当前状态)和next(下一状态)字段,先计算所有细胞的next状态,再统一同步到current——这个设计其实更规范,避免更新时影响邻居计算,但代码里漏了关键逻辑。
核心问题1:版本2未处理「邻居数为2」的规则
回忆生命游戏的核心规则:
- 存活细胞:
- 邻居数<2 → 死亡
- 邻居数=2或3 → 保持存活
- 邻居数>3 → 死亡
- 死亡细胞:
- 邻居数=3 → 复活
看版本1的updateField:
void updateField(const int rows, const int cols, cell field[rows][cols]) { getNeighbours(rows, cols, field); for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { if(field[r][c].neighbours == 3) { field[r][c].state = ALIVE; } else if(field[r][c].neighbours <= 1) { field[r][c].state = DEAD; } else if(field[r][c].neighbours >= 4) { field[r][c].state = DEAD; } // 重点:当邻居数为2时,没有修改state,自动保持原状态,符合规则! } } }
再看版本2的updateField:
void updateField(const int rows, const int cols, cell field[rows][cols]) { getNeighbours(rows, cols, field); for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { if(field[r][c].neighbours == 3) { field[r][c].next = ALIVE; } else if(field[r][c].neighbours <= 1) { field[r][c].next = DEAD; } else if(field[r][c].neighbours >= 4) { field[r][c].next = DEAD; } // 致命漏洞:邻居数为2时,next字段完全没赋值! } } // 同步next到current的代码 ... }
当邻居数为2时,next字段没有被设置值,会保留内存里的垃圾值(或者上一轮循环的残留值),同步到current后状态完全错误。
核心问题2:版本2未初始化next字段
版本2的initField只初始化了current字段,next字段完全没处理:
void initField(const int rows, const int cols, cell field[rows][cols]) { for (int r = 0 ; r < rows ; r++) { for (int c = 0 ; c < cols ; c++) { field[r][c].current = DEAD; // 缺失:field[r][c].next = DEAD; } } // 初始化活细胞时,也没同步设置next field[0][1].current = ALIVE; // 缺失:field[0][1].next = ALIVE; ... }
这会导致第一次运行时next是随机的垃圾值,进一步加剧状态混乱。
修复版本2的步骤
1. 完善initField,初始化next字段
void initField(const int rows, const int cols, cell field[rows][cols]) { for (int r = 0 ; r < rows ; r++) { for (int c = 0 ; c < cols ; c++) { field[r][c].current = DEAD; field[r][c].next = DEAD; // 新增:初始化next状态 } } // 初始化活细胞时同步设置next field[0][1].current = ALIVE; field[0][1].next = ALIVE; field[1][2].current = ALIVE; field[1][2].next = ALIVE; field[2][0].current = ALIVE; field[2][0].next = ALIVE; field[2][1].current = ALIVE; field[2][1].next = ALIVE; field[2][2].current = ALIVE; field[2][2].next = ALIVE; }
2. 补全updateField中邻居数为2的逻辑
当邻居数为2时,next应该等于current的状态(保持原状态):
void updateField(const int rows, const int cols, cell field[rows][cols]) { getNeighbours(rows, cols, field); for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { if(field[r][c].neighbours == 3) { field[r][c].next = ALIVE; } else if(field[r][c].neighbours <= 1 || field[r][c].neighbours >=4) { field[r][c].next = DEAD; } else { // 邻居数为2,保持当前状态 field[r][c].next = field[r][c].current; } } } // 同步next到current可以简化成一行 for (int r = 0; r < rows; r++) { for(int c = 0; c < cols; c++) { field[r][c].current = field[r][c].next; } } }
修复这两个问题后,版本2的运行结果就会和版本1完全一致了。
内容的提问来源于stack exchange,提问作者Senethys
相关产品推荐
相关产品推荐

