C 中棋盘更新功能的生命游戏问题

Game of Life problem with board update function in C

我在 C 语言中实现 Game of Life 时需要帮助。Whosebug 上的其他帖子让我相信我的问题与悬挂指针有关,但在修改我的程序以使用全局 2D 数组作为游戏网格之后我没有将它传递给 return 新二维数组的函数,而是意识到这是我的 update 函数的问题。

我已经尝试对一些简单的模式进行硬编码,包括滑翔机和振荡器,但网格无法正确更新。每次程序 运行 时,模式确实以相同的方式更新,所以我不认为这是未初始化内存导致问题的问题。我也知道没有包含大于 1 的值的单元格。所以,问题一定出在我更新网格的机制上。

谁能帮我找出问题所在?我没有发现我的代码有任何问题,我相信我已经正确编写了规则。

这是我的 neighborsupdate 函数,以及相关的变量和常量声明。

#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 函数中,您需要仔细考虑 dxdy 均为零的循环迭代。康威的生命游戏不认为一个细胞是自己的邻居,所以你需要避免计算它。

您还会因使用字母 ij 而感到困惑。您允许 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;
}