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()
中的主循环无法在几代之间交替。您可以保留我建议的更改,并删除对 printCurrentField
和 printNextField
的所有引用。这使您可以简化函数 printField()
.
我正在尝试用 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()
中的主循环无法在几代之间交替。您可以保留我建议的更改,并删除对 printCurrentField
和 printNextField
的所有引用。这使您可以简化函数 printField()
.