生命游戏simulate函数调用后终端冻结,求排查代码问题
问题排查:无限循环与生命游戏逻辑修正
首先,导致终端冻结、陷入无限循环的直接原因是你内层的两个for循环增量写错了:
看这段代码:
for(int x = -1; x < 2; x + 2) //iterates through -1 and 1, the spaces next to the cell { for(int y = -1; y < 2; y + 2)
这里的x + 2和y + 2只是做了加法运算,但没有把结果赋值回变量本身。也就是说,x会一直保持初始值-1,永远满足x < 2的循环条件,循环永远不会终止,自然导致程序卡死。
你需要把增量改成赋值操作,也就是x += 2和y += 2,这样才能让x从-1跳到1,然后退出循环:
for(int x = -1; x < 2; x += 2) { for(int y = -1; y < 2; y += 2)
不过这里还要提醒你:当前的邻居统计逻辑有问题——你只遍历了对角的4个邻居((-1,-1), (-1,1), (1,-1), (1,1)),漏掉了上下左右四个邻居((-1,0), (0,-1), (0,1), (1,0)),这不符合生命游戏的规则(每个细胞的邻居是周围8个相邻细胞)。
正确的邻居遍历应该是遍历x从-1到1,y从-1到1,然后排除细胞自身(也就是x == 0 && y == 0的情况),这样才能统计完整的8个邻居。修正后的邻居统计代码应该是这样:
int neighbors = 0; for(int x = -1; x <= 1; ++x) { for(int y = -1; y <= 1; ++y) { // 跳过细胞自己 if(x == 0 && y == 0) continue; // 检查边界 int nr = r + x; int nc = c + y; if(nr >= 0 && nr < rows && nc >=0 && nc < columns) { if(myGrid[nr][nc] == 1) { ++neighbors; } } } }
另外还有一个关键问题:你在遍历网格的时候直接修改了原网格,这会导致后续细胞的邻居统计使用的是已经更新后的状态,而不是初始的当前状态,这会完全打乱生命游戏的规则。
正确的做法是先创建一个临时网格,存储所有细胞的下一个状态,遍历完成后再把临时网格的值复制回原网格。比如:
void Grids::simulate(int** myGrid, int rows, int columns) { // 创建临时网格存储下一个状态 int** nextGrid = new int*[rows]; for(int r = 0; r < rows; ++r) { nextGrid[r] = new int[columns]; } for (int r = 0; r < rows; ++r) { for(int c = 0; c < columns; ++c) { int neighbors = 0; // 统计8个邻居 for(int x = -1; x <= 1; ++x) { for(int y = -1; y <= 1; ++y) { if(x == 0 && y == 0) continue; int nr = r + x; int nc = c + y; if(nr >= 0 && nr < rows && nc >=0 && nc < columns) { if(myGrid[nr][nc] == 1) { ++neighbors; } } } } // 根据规则设置下一个状态 if(myGrid[r][c] == 1) { if(neighbors < 2 || neighbors > 3) { nextGrid[r][c] = 0; } else { nextGrid[r][c] = 1; } } else { if(neighbors == 3) { nextGrid[r][c] = 1; } else { nextGrid[r][c] = 0; } } } } // 将临时网格的值复制回原网格 for(int r = 0; r < rows; ++r) { for(int c = 0; c < columns; ++c) { myGrid[r][c] = nextGrid[r][c]; delete[] nextGrid[r]; } } delete[] nextGrid; }
这样修改后,不仅解决了无限循环的问题,也修正了邻居统计和状态更新的逻辑错误,符合生命游戏的规则。
内容的提问来源于stack exchange,提问作者vinny_c
相关产品推荐
相关产品推荐

