C 中棋盘更新功能的生命游戏问题
Game of Life problem with board update function in C
我在 C 语言中实现 Game of Life 时需要帮助。Whosebug 上的其他帖子让我相信我的问题与悬挂指针有关,但在修改我的程序以使用全局 2D 数组作为游戏网格之后我没有将它传递给 return 新二维数组的函数,而是意识到这是我的 update
函数的问题。
我已经尝试对一些简单的模式进行硬编码,包括滑翔机和振荡器,但网格无法正确更新。每次程序 运行 时,模式确实以相同的方式更新,所以我不认为这是未初始化内存导致问题的问题。我也知道没有包含大于 1
的值的单元格。所以,问题一定出在我更新网格的机制上。
谁能帮我找出问题所在?我没有发现我的代码有任何问题,我相信我已经正确编写了规则。
这是我的 neighbors
和 update
函数,以及相关的变量和常量声明。
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
int grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int dx, dy, dstx, dsty;
int n = 0;
for (dy = -1; dy <= 1; ++dy) {
for (dx = -1; dx <= 1; ++dx) {
dsty = y + dy;
dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X)
n += !!grid[dsty][dstx]; /* use !! so that non-zero values eval to 1 */
}
}
/* (n > 0) ? printf("Point (%d,%d) has %d neighbors!\n", x, y, n) : 0; */
return n;
}
void update(void) {
int new[MAX_Y][MAX_X];
memset(new, 0, sizeof(int) * MAX_Y * MAX_X);
int i, j, n;
for (i = 0; i < MAX_Y; ++i) {
for (j = 0; j < MAX_X; ++j) {
n = neighbors(i, j);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
if (grid[i][j] && (n == 2 || n == 3))
new[i][j] = 1;
else if (!grid[i][j] && n == 3)
new[i][j] = 1;
else
new[i][j] = 0;
}
}
memcpy(grid, new, sizeof grid);
}
在您的 neighbors
函数中,您需要仔细考虑 dx
和 dy
均为零的循环迭代。康威的生命游戏不认为一个细胞是自己的邻居,所以你需要避免计算它。
您还会因使用字母 i
和 j
而感到困惑。您允许 j
一直到 MAX_X
,但是您在调用 neighbors
时使用 j
作为 y
坐标,所以这将导致溢出和不正确的计算。 (从更简单的 10x10 网格开始有时可以避免此类错误。)
您应该调整 neighbors()
函数以忽略单元格本身。
这是修改后的版本:
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
unsigned char grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int n = -!!grid[y][x];
for (int dy = -1; dy <= 1; ++dy) {
for (int dx = -1; dx <= 1; ++dx) {
int dsty = y + dy;
int dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X && grid[dsty][dstx])
n++;
}
}
return n;
}
void update(void) {
int new[MAX_Y][MAX_X] = { 0 };
for (int y = 0; y < MAX_Y; ++y) {
for (int x = 0; x < MAX_X; ++x) {
int n = neighbors(y, x);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
new[y][x] = (grid[y][x] && n == 2) || n == 3;
}
}
memcpy(grid, new, sizeof grid);
}
neighbors()
函数可以通过更少的测试来简化:
int neighbors(int x, int y) {
int n = -(grid[y][x] != 0);
int x1 = x - (x > 0);
int x2 = x + (x < MAX_X - 1);
int y1 = y - (y > 0);
int y2 = y + (y < MAX_Y - 1);
for (y = y1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
n += grid[y][x] != 0;
}
}
return n;
}
我在 C 语言中实现 Game of Life 时需要帮助。Whosebug 上的其他帖子让我相信我的问题与悬挂指针有关,但在修改我的程序以使用全局 2D 数组作为游戏网格之后我没有将它传递给 return 新二维数组的函数,而是意识到这是我的 update
函数的问题。
我已经尝试对一些简单的模式进行硬编码,包括滑翔机和振荡器,但网格无法正确更新。每次程序 运行 时,模式确实以相同的方式更新,所以我不认为这是未初始化内存导致问题的问题。我也知道没有包含大于 1
的值的单元格。所以,问题一定出在我更新网格的机制上。
谁能帮我找出问题所在?我没有发现我的代码有任何问题,我相信我已经正确编写了规则。
这是我的 neighbors
和 update
函数,以及相关的变量和常量声明。
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
int grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int dx, dy, dstx, dsty;
int n = 0;
for (dy = -1; dy <= 1; ++dy) {
for (dx = -1; dx <= 1; ++dx) {
dsty = y + dy;
dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X)
n += !!grid[dsty][dstx]; /* use !! so that non-zero values eval to 1 */
}
}
/* (n > 0) ? printf("Point (%d,%d) has %d neighbors!\n", x, y, n) : 0; */
return n;
}
void update(void) {
int new[MAX_Y][MAX_X];
memset(new, 0, sizeof(int) * MAX_Y * MAX_X);
int i, j, n;
for (i = 0; i < MAX_Y; ++i) {
for (j = 0; j < MAX_X; ++j) {
n = neighbors(i, j);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
if (grid[i][j] && (n == 2 || n == 3))
new[i][j] = 1;
else if (!grid[i][j] && n == 3)
new[i][j] = 1;
else
new[i][j] = 0;
}
}
memcpy(grid, new, sizeof grid);
}
在您的 neighbors
函数中,您需要仔细考虑 dx
和 dy
均为零的循环迭代。康威的生命游戏不认为一个细胞是自己的邻居,所以你需要避免计算它。
您还会因使用字母 i
和 j
而感到困惑。您允许 j
一直到 MAX_X
,但是您在调用 neighbors
时使用 j
作为 y
坐标,所以这将导致溢出和不正确的计算。 (从更简单的 10x10 网格开始有时可以避免此类错误。)
您应该调整 neighbors()
函数以忽略单元格本身。
这是修改后的版本:
#define MAX_Y 10 /* height */
#define MAX_X 30 /* width */
unsigned char grid[MAX_Y][MAX_X];
int neighbors(int x, int y) {
int n = -!!grid[y][x];
for (int dy = -1; dy <= 1; ++dy) {
for (int dx = -1; dx <= 1; ++dx) {
int dsty = y + dy;
int dstx = x + dx;
if (dsty >= 0 && dsty < MAX_Y && dstx >= 0 && dstx < MAX_X && grid[dsty][dstx])
n++;
}
}
return n;
}
void update(void) {
int new[MAX_Y][MAX_X] = { 0 };
for (int y = 0; y < MAX_Y; ++y) {
for (int x = 0; x < MAX_X; ++x) {
int n = neighbors(y, x);
/* alive, 2 or 3 neighbors -> alive!
* dead, 3 neighbors -> alive!
* anything else -> dead :(
*/
new[y][x] = (grid[y][x] && n == 2) || n == 3;
}
}
memcpy(grid, new, sizeof grid);
}
neighbors()
函数可以通过更少的测试来简化:
int neighbors(int x, int y) {
int n = -(grid[y][x] != 0);
int x1 = x - (x > 0);
int x2 = x + (x < MAX_X - 1);
int y1 = y - (y > 0);
int y2 = y + (y < MAX_Y - 1);
for (y = y1; y <= y2; y++) {
for (x = x1; x <= x2; x++) {
n += grid[y][x] != 0;
}
}
return n;
}