我正在尝试用C编写生活游戏。我已经坐了7个小时想知道如何解决它。我已经走了很远,但有一些东西使代码不能正常工作。我相信我在结构中的下一个和当前变量之间做错了。如果邻居活着或死了,也许是错误的。无论如何,我将不胜感激任何帮助!
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;
}
}
答案 0 :(得分:3)
既然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()
。
答案 1 :(得分:2)
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.这意味着有七行。但是这段代码将访问八行:零行,一行,两行,三行,四行,五行,六行和七行。这可能是对的。
答案 2 :(得分:0)
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返回值在输入错误后尝试FIX sig seg fault,我想更好地评论代码并使用valgrind。内存管理很糟糕所以你要退出阵列我认为有一个问题试着手动检查它