C 生命游戏问题

C Game of life issues

我正在尝试用 C 编写生活游戏代码。我已经坐了 7 个小时想知道如何解决它。我已经走了很远,但有些东西使代码无法正常工作。我相信我在结构中的 next 和 current 变量之间做错了。如果邻居还活着或已经死了,计算起来可能是错误的。无论如何,我将不胜感激!

void checkField(const int rows, const int cols, cell field[rows][cols]) {
    int neighborCount;

    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
                neighborCount = getNeighborCount(rows, cols, r, c, field);
                nextGeneration(rows, cols, r, c, neighborCount, field);
        }
    }
}

int getNeighborCount(const int rows, const int cols, 
    int r, int c, cell field[rows][cols]) {

    int neighborCount = 0;

    neighborCount += checkNeighbors(rows, cols, r - 1, c - 1, field);
    neighborCount += checkNeighbors(rows, cols, r - 1, c, field);
    neighborCount += checkNeighbors(rows, cols, r - 1, c + 1, field);
    neighborCount += checkNeighbors(rows, cols, r, c - 1, field);
    neighborCount += checkNeighbors(rows, cols, r, c + 1, field);
    neighborCount += checkNeighbors(rows, cols, r + 1, c - 1, field);
    neighborCount += checkNeighbors(rows, cols, r + 1, c, field);
    neighborCount += checkNeighbors(rows, cols, r + 1, c + 1, field);

    return neighborCount;
}


int checkNeighbors(const int rows, const int cols, 
    int r, int c, cell field[rows][cols]) {

    int neighborAlive;

    if (r < 0 || r > rows || c < 0 || c > cols || field[r][c].current != ALIVE){
        return neighborAlive = 0;
    }
    else {
        return neighborAlive = 1;
    }
}

void nextGeneration(const int rows, const int cols, 
    int r, int c, int neighborCount, 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;
        }
    }

    if (neighborCount < 2){
        field[r][c].current = DEAD;
        field[r][c].next = DEAD;
    }

    if (neighborCount == 2 || neighborCount == 3) {
        field[r][c].current = ALIVE;
        field[r][c].next = ALIVE;

    }

    if ((field[r][c].current == DEAD) && neighborCount == 3) {
        field[r][c].current = ALIVE;
        field[r][c].next = ALIVE;
    }

    if (neighborCount >= 4) {
        field[r][c].current = DEAD;
        field[r][c].next = DEAD;
    }
}
int checkNeighbors(const int rows, const int cols, 
    int r, int c, cell field[rows][cols]) {
    int neighborAlive;

    if (r < 0 || r > rows || c < 0 || c > cols || field[r][c].current != ALIVE){
        return neighborAlive = 0;
    }
    else {
        return neighborAlive = 1;
    }
}

假设rows是7。这意味着有七行。但是此代码将访问八行:零、一、二、三、四、五、六和七。这不可能是对的。

void loadCustom(const int rows, const int cols, cell field[rows][cols]) {

  printf("Give custom format string: ");
  do {
    int r, c;
    scanf("%d,%d", &r, &c);
    field[r][c].current = ALIVE;
  } while (getchar() != '\n');
}

scanf returns value 尝试在错误输入后修复 sig seg 错误,我想更好地注释代码并使用 valgrind。内存管理不好,所以你要用完数组我认为有问题尝试手动检查

现在 checkNeighbors() 函数中的条件正在运行,您在从一代更新到下一代的过程中遇到了一些问题。在函数nextGeneration()中,不需要清除单元格数组,因为反正你即将覆盖下一代。在这个函数的每个测试中,你都有,例如:

if (neighborCount < 2){
    field[r][c].current = DEAD;
    field[r][c].next = DEAD;
}

但你只需要field[r][c].next = DEAD;。这是您的新 nextGeneration() 函数:

void nextGeneration(const int rows, const int cols, 
    int r, int c, int neighborCount, cell field[rows][cols]) {

    if (neighborCount < 2)
        field[r][c].next = DEAD;

    if (neighborCount == 2 || neighborCount == 3) 
        field[r][c].next = ALIVE;

    if ((field[r][c].current == DEAD) && neighborCount == 3)
        field[r][c].next = ALIVE;

    if (neighborCount >= 4)
        field[r][c].next = DEAD;
}

然后,在checkField()函数的最后,需要将下一代复制到当前这一代。这是您的新 checkField() 函数:

void checkField(const int rows, const int cols, cell field[rows][cols]) {

    int neighborCount;
    int r, c;

    for (r = 0; r < rows; r++) {
        for (c = 0; c < cols; c++) {
                neighborCount = getNeighborCount(rows, cols, r, c, field);
                nextGeneration(rows, cols, r, c, neighborCount, field);
        }
    }
    /* Now, copy next generation into current */
    for (r = 0; r < rows; r++)
        for (c = 0; c < cols; c++)
            field[r][c].current = field[r][c].next;
}

通过这些更改,您的代码对我有用,但我认为您的规则可能存在问题。我尝试了滑翔机,但它的行为并不像我预期的那样。这是第二代网格的样子:

. . X . . . . . . . . . . . . . . . . . 
X . X X . . . . . . . . . . . . . . . . 
. X X X . . . . . . . . . . . . . . . . 
X X X . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . 

剧透警告:

这是一个更新后的 nextGeneration() 函数,其规则正确地实现了 Conway 的生命游戏。您的原始规则是仅与 2 个邻居一起再生死细胞。

void nextGeneration(const int rows, const int cols, 
    int r, int c, int neighborCount, cell field[rows][cols]) {

    if (field[r][c].current == ALIVE) {
        if ((neighborCount < 2) || (neighborCount > 3)){
            field[r][c].next = DEAD;
        } else {
            field[r][c].next = ALIVE;
        }
    } else {
        if (neighborCount == 3) {
            field[r][c].next = ALIVE;
        } else {
            field[r][c].next = DEAD;
        }
    }
}

更新:

完成上述所有操作后,我现在了解到您正试图在当前和下一代之间来回翻转显示。这使更新逻辑变得复杂,因为您也必须在这里进行代际交替。底线是这段代码比它需要的更复杂。你可以按照你想要的方式实现它,但仍然有许多更新问题导致问题,并且 main() 中的主循环无法在几代之间交替。您可以保留我建议的更改,并删除对 printCurrentFieldprintNextField 的所有引用。这使您可以简化函数 printField().