Reputation: 573
for a homework, I have to reproduce Conway's Game of Life project.
Unfortunately, I got weird result, I suppose because C language is new to me, I'm more focus on php recently.
First I give the specs of the project :
* 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"
*/
To give more details on the weird result I get :
I'm sure some bad habits have been used by myself and I'm ready to hear about more experienced developer that could point out what I've missed or did badly.
I'm close to the result (I'm sure of it !) so thanks for any help brought here.
Here is the code of my homework project.
#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;
}
Upvotes: 1
Views: 320
Reputation: 20141
I think, you have a major mis-understanding:
In C: struct
s are passed to functions by value (i.e. by copy, in opposition to arrays which are always passed "by reference" – actually, by it's start address). This is true even in your case where the struct contains an array.
I took some code of your sample to demonstrate this:
#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;
}
The output is:
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 . . .
This shows that modifyWorld()
does change its local copy but not the original world
declared in main()
.
To change this, the 1st parameter had to become a World *world
.
Accordingly, its contents had to be accessed by ->
instead of .
, e.g.
world->cell[y][x].status = status;
This affects your function clearWorld()
exclusively.
Every other function of your sample uses a "functional approach" returning changed local copies as result which is assigned on caller site.
This is not very C-stylish and inefficient but it's working correctly (concerning the storage).
Considering this and what's suggested by the comments about updating of states you should be able to master it.
Upvotes: 1