康威生命游戏奇怪的结果

标签 c

作为家庭作业,我必须重现 Conway 的 Game of Life 项目。

不幸的是,我得到了奇怪的结果,我想是因为 C 语言对我来说是新的,我最近更关注 php。

首先我给出项目的规范:

 * The Game of Life
 * http://en.wikipedia.org/wiki/Conway's_Game_of_Life
 *
 * Key requirements :
 * - Limit the size of the world to 10x10 cells
 * - The world (grid) must be a struct composed by cells
 * - A cell must be a struct
 * - Each cell is in one of two possible states : Live or Dead
 * - Any live cell with fewer than two live neighbours dies, as if caused by under-population
 * - Any live cell with two or three live neighbours lives on to the next generation
 * - Any live cell with more than three live neighbours dies, as if by overcrowding
 * - Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction
 * - Between each generation, ask if it's necessary to restart the next generation or to leave the game
 * - Having dedicated function displayWorld() to display a representation of this world
 * - Having dedicated function newGeneration() to generate next step of the world
 * - In the function above, implement conditions based on cell's neighbors to define if each cell is alive or dead
 * - Alive cells are represented by a "+"
 * - Dead cells are represented by a "-"
 * - New borned cells are represented by a "0"
 */

要详细说明我得到的奇怪结果:

  • 我有来自 loadInitData 函数的硬编码值,但有时它会在我* 从未 * 指定的随机位置显示 0 丢失...
  • 很快,康威生命游戏很快结束,所有活细胞都消失了

我确信我自己养成了一些坏习惯,我准备好听取更有经验的开发人员的意见,他们可以指出我遗漏了什么或做得不好。

我很接近结果(我很确定!)所以感谢您提供的任何帮助。

这是我的作业项目的代码。

#include <stdio.h>
#define NEW '0'
#define LIVE '+'
#define DEAD '-'
#define xSize 10
#define ySize 10

typedef struct {
    char status;
} Cell;

typedef struct {
    int sizeX;
    int sizeY;
    Cell cell[xSize][ySize];
} World;

void displayWorld(World grid) {
    int x, y;
    for (y = 0; y < grid.sizeY; y++) {
        for (x = 0; x < grid.sizeX; x++) {
            if (grid.cell[y][x].status == NEW) {
                printf("0");
            } else if (grid.cell[y][x].status == LIVE) {
                printf("+");
            } else {
                printf("-");
            }
        }
        printf("\n");
    }
    printf("\n");
}

int getNeighborValue(World grid, int row, int col) {
    if (row < 0 || row >= grid.sizeY
            || col < 0 || col >= grid.sizeX
            || grid.cell[row][col].status != LIVE )
    {
        return 0;
    } else {
        return 1;
    }
}

int getNeighborCount(World grid, int row, int col) {
    int neighbor = 0;

    neighbor += getNeighborValue(grid, row - 1, col - 1);
    neighbor += getNeighborValue(grid, row - 1, col);
    neighbor += getNeighborValue(grid, row - 1, col + 1);
    neighbor += getNeighborValue(grid, row, col - 1);
    neighbor += getNeighborValue(grid, row, col + 1);
    neighbor += getNeighborValue(grid, row + 1, col - 1);
    neighbor += getNeighborValue(grid, row + 1, col);
    neighbor += getNeighborValue(grid, row + 1, col + 1);

    return neighbor;
}

World newGeneration(World grid) {
    int neighbor, x, y;

    for (y = 0; y < grid.sizeY; y++) {
        for (x = 0; x < grid.sizeX; x++) {
            neighbor = getNeighborCount(grid, y, x);

            if (grid.cell[y][x].status == NEW || grid.cell[y][x].status == LIVE) {
                if (neighbor > 3) {
                    grid.cell[y][x].status = DEAD;
                } else if (neighbor == 2 || neighbor == 3) {
                    grid.cell[y][x].status = LIVE;
                } else {
                    grid.cell[y][x].status = DEAD;
                }
            } else {
                if (neighbor == 3) {
                    grid.cell[y][x].status = NEW;
                }
            }
        }
    }

    return grid;
}

void clearWorld(World grid) {
    int x, y;
    for (y = 0; y < grid.sizeY; y++) {
        for (x = 0; x < grid.sizeX; x++) {
            Cell cell;
            cell.status = DEAD;
            grid.cell[y][x] = cell;
        }
    }
}

World loadInitData(World grid) {
    int x, y, i, n, v;

    printf("Enter the amount of initial organisms: ");
    scanf("%d", &n);

    printf("Would you like organisms randomly generated or defined by you (0: random; 1: you)? ");
    scanf("%d", &v);

    if (v == 1) {
        for (i = 0; i < n; i++) {
            printf("Enter dimensions (x y) where organism %d will live: ", i + 1);
            scanf("%d %d", &x, &y);
            grid.cell[y][x].status = LIVE;
        }
    } else {
        // for (i = 0; i < n; i++) {
        //  x = rand() % grid.sizeX;
        //  y = rand() % grid.sizeY;
        //  grid.cell[y][x].status = LIVE;
        // }

        grid.cell[3][4].status = LIVE;
        grid.cell[3][5].status = LIVE;
        grid.cell[3][6].status = LIVE;
        grid.cell[6][4].status = LIVE;
        grid.cell[6][5].status = LIVE;
        grid.cell[6][6].status = LIVE;
        grid.cell[7][6].status = LIVE;
        grid.cell[8][5].status = LIVE;
    }

    return grid;
}

int main() {
    World grid;
    grid.sizeX = xSize;
    grid.sizeY = ySize;
    char end;
    int generation = 0;
    clearWorld(grid);
    grid = loadInitData(grid);
    displayWorld(grid);
    printf("Generation %d\n", 0);
    printf("Press q to quit or 1 to continue: ");
    scanf(" %c", &end);

    do {
        grid = newGeneration(grid);
        displayWorld(grid);
        printf("Generation %d\n", ++generation);
        printf("Press q to quit or 1 to continue: ");
        scanf(" %c", &end);
    } while (end != 'q') ;

    return 0;
}

最佳答案

我觉得,你的理解有很大的误区:

在 C 中:struct按值 传递给函数(即通过复制,与总是“按引用”——实际上,通过它的起始地址)。即使在结构包含数组的情况下也是如此。

我使用了您示例中的一些代码来证明这一点:

#include <stdio.h>

enum {
  NEW = '0',
  LIVE = '+',
  DEAD = '-'
};

typedef struct {
  char status;
} Cell;

enum { xSize = 3, ySize = 3 };

typedef struct {
  int sizeX, sizeY;
  Cell cell[ySize][xSize];
} World;

void displayWorld(World world)
{
  for (int y = 0; y < ySize; ++y) {
    for (int x = 0; x < xSize; ++x) printf("+-");
    printf("+\n");
    for (int x = 0; x < xSize; ++x) {
      printf("|%c", world.cell[y][x].status);
    }
    printf("|\n");
  }
  for (int x = 0; x < xSize; ++x) printf("+-");
  printf("+\n");
}

void modifyWorld(World world, int x, int y, char status)
{
  world.cell[y][x].status = status;
  printf("Modified:\n");
  displayWorld(world);
}

int main()
{
  World world = {
    xSize, ySize
  };
  /* init world */
  for (int y = 0; y < ySize; ++y) {
    for (int x = 0; x < xSize; ++x) world.cell[y][x].status = NEW;
  }
  /* display world */
  printf("Before call of modifyWorld():\n");
  displayWorld(world);
  /* modify world */
  modifyWorld(world, xSize / 2, ySize / 2, LIVE);
  /* display world */
  printf("After call of modifyWorld():\n");
  displayWorld(world);
  /* done */
  return 0;
}

输出是:

Before call of modifyWorld():
+-+-+-+
|0|0|0|
+-+-+-+
|0|0|0|
+-+-+-+
|0|0|0|
+-+-+-+
Modified:
+-+-+-+
|0|0|0|
+-+-+-+
|0|+|0|
+-+-+-+
|0|0|0|
+-+-+-+
After call of modifyWorld():
+-+-+-+
|0|0|0|
+-+-+-+
|0|0|0|
+-+-+-+
|0|0|0|
+-+-+-+
Drücken Sie eine beliebige Taste . . .

这表明 modifyWorld() 确实更改了它的本地副本,但没有更改 main() 中声明的原始 world

要改变这一点,第一个st 参数必须变成World *world。 因此,它的内容必须通过 -> 而不是 访问。,例如

world->cell[y][x].status = status;

这只会影响您的函数 clearWorld()

您的示例的每个其他功能都使用“功能方法”返回更改的本地副本作为在调用方站点上分配的结果。

这不是很 C 风格且效率低下,但它工作正常(关于存储)。

考虑到这一点以及评论中关于更新状态的建议,您应该能够掌握它。

关于康威生命游戏奇怪的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44422805/

相关文章:

c - 如何修改已传递给 C 函数的指针?

c - 如何处理字符串文字中的转义值(如\nnn、\xnn)?

c - 在 C 中反转字符串

CMake:如何从多个源文件创建一个对象?

c - 一个简单的C程序来分析pcap文件,但它不能读取整个pcap文件

c - golang cgo 检查C函数是否存在

c - 在 Wininet 中使用 SSL

c - C语言中有没有办法检查return后的语句?

c - 当我执行此代码时,我遇到段错误(核心转储)...

将本地时间作为字符串转换为 1970 年 1 月 1 日起的毫秒