Question

I saw Conway's Game of Life and decided to make my own. I have a bool array to represent the world, but the edges (Top and bottom) are acting weird, random cells becomes live.

In this code, it does not print the bottom and top of the world, but this is a bad solution. The world "wraps" at the right and the left, causing even more problems, but that is for another time.

#include <iostream>

const int height = 20;
const int width  = 20;

bool now_world[height][width];
bool then_world[height][width];

void clear_world();
void place_random_live_cells();
void then_world_initialization();
void print_world();
void generation_pass();
void update_worlds();

int main(int argc, const char * argv[])
{
using namespace std;
srand((unsigned)time(NULL));
int timer = 0;
int generation = 0;
clear_world();
place_random_live_cells();
then_world_initialization();
bool running = true;
while (running) {
    if (timer == 50000000) {
        cout << "Generation #" << generation << endl;
        print_world();
        generation_pass();
        update_worlds();
        ++generation;
        timer = 0;
    }
    ++timer;
}//While (running) ends here
return 0;
}

void place_random_live_cells()
{
int percent = 30;
int max_live_cells = ((height * width) / 100) * percent;
int current_live_cells = 0;
while (current_live_cells < max_live_cells) {
    int ycoords = 0 + (rand() % (height + 1));
    int xcoords = 0 + (rand() % (width  + 1));
    if (now_world[ycoords][xcoords] == false) {
        now_world[ycoords][xcoords] = true;
    } else {
        current_live_cells--;
    }
    ++current_live_cells;
}
}

//A generation pass and cells die and some cells come to life
void generation_pass()
{
using namespace std;
int neighbours = 0;
for (int iii = 0; iii < height; iii++) {
    for (int jjj = 0; jjj < width; jjj++) {
        //Count neighbouring cells that are alive
        if (now_world[iii+1][jjj+1] == true) {
            ++neighbours;
        }
        if (now_world[iii+1][jjj  ] == true) {
            ++neighbours;
        }
        if (now_world[iii+1][jjj-1] == true) {
            ++neighbours;
        }
        if (now_world[iii  ][jjj+1] == true) {
            ++neighbours;
        }
        if (now_world[iii  ][jjj-1] == true) {
            ++neighbours;
        }
        if (now_world[iii-1][jjj+1] == true) {
            ++neighbours;
        }
        if (now_world[iii-1][jjj  ] == true) {
            ++neighbours;
        }
        if (now_world[iii-1][jjj-1] == true) {
            ++neighbours;
        }
        //Apply rules to the cells
        //Dead cells with three live neighbours becomes alive
        if (then_world[iii][jjj] == false && neighbours == 3) {
            then_world[iii][jjj] =  true;
        }
        //Alive with fewer than two, they die
        if (then_world[iii][jjj] == true  && neighbours <  2) {
            then_world[iii][jjj] =  false;
        }
        //Alive with 2 or three live neighbours live on unchanged
        if (then_world[iii][jjj] == true  && neighbours == 2) {
            then_world[iii][jjj] =  true;
        }
        if (then_world[iii][jjj] == true  && neighbours == 3) {
            then_world[iii][jjj] =  true;
        }
        //Alive with more than three, they die
        if (then_world[iii][jjj] == true  && neighbours >  3) {
            then_world[iii][jjj] =  false;
        }
        //Dead cells without exactly three live neighbours remain dead
        //Reset neighbour value to zero
        neighbours = false;
    }
}
}

//Make next generation identical to current
//This is only called once
void then_world_initialization()
{
for (int iii = 0; iii < height; iii++) {
    for (int jjj = 0; jjj < width; jjj++) {
        then_world[iii][jjj] = now_world[iii][jjj];
    }
}
}

//Make the next generation be today
//This is called every generation
void update_worlds()
{
for (int iii = 0; iii < height; iii++) {
    for (int jjj = 0; jjj < width; jjj++) {
        now_world[iii][jjj] = then_world[iii][jjj];
    }
}
}

//Set all cells to dead
void clear_world()
{
for (long iii = 0; iii < height; iii++) {
    for (long jjj = 0; jjj < width; jjj++) {
        now_world[iii][jjj]  = false;
        then_world[iii][jjj] = false;
    }
}
}

//Print world
void print_world()
{
using namespace std;
char live = 'X';
char dead = '.';
for (long iii = height; iii > 0; iii--) {
    for (long jjj = width; jjj > 0; jjj--) {
        if (iii != 0 && iii != height) {
            if (now_world[iii][jjj]) {
                cout << live;
            } else {
                cout << dead;
            }
            cout << " ";
        }
    }
    cout << endl;
}
cout << endl;
}
Was it helpful?

Solution

Having done this for a course I taught in the past, the most common issue I always see people having is going outside the bounds of the array they're using.

If you look at the if statements in your nested for loop, I think you'll find some issues. For instance, in this case, what happens when iii equals (height-1) or jjj equals (width-1)?

for (int iii = 0; iii < height; iii++) {
    for (int jjj = 0; jjj < width; jjj++) {
        //Count neighbouring cells that are alive
        if (now_world[iii+1][jjj+1] == true) {
            ++neighbours;

You're going outside the bounds of your array and so your results will be undefined. You may get segfaults, but you may just also get spurious data. C++ doesn't enforce you staying within the bounds of the array you define.

Make sure you also handle cases like this:

if (now_world[iii-1][jjj+1] == true) {
            ++neighbours;
        }

What if iii equals zero?

Hope that helps.

OTHER TIPS

You're trying to access out-of-boundary indexes in your array.

I'm not sure what behaviour you expect, but an easy way is to not calculate updates for cells on the edges.

So in generation_pass the loops should go from 1 till height-1.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top