C++ Conway's Game of Life

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Psittacosis
    AKA Cold Kitten
    • Oct 2012
    • 91

    #1

    C++ Conway's Game of Life

    So, my lab for this week is to code a conway's game of life file and have it generate new generation and things. It's... sort of doing that, but it's not quite doing it right. It doesn't seem to be following any of the general rules for Conway's Game of Life and it's acting awfully odd.

    (For those not familiar with Conway's Game of Life see here)

    Anyway. I wish I could explain my problem better, but if anyone has had any experience with this, that would be great. Code is below

    Code:
      6 #include <iostream>
      7 #include <iomanip>
      8 #include <fstream>
      9 #include <stdlib.h>
     10 #include <unistd.h>
     11 #include <time.h>
     12 #include "ansi.h"
     13
     14 using namespace std;
     15
     16 #define GRID_WIDTH 80
     17 #define GRID_HEIGHT 24
     18 #define DELAY 500000
     19
     20 void initGrid(bool grid[][GRID_WIDTH]);
     21 void initGrid(const char* fileName, bool [][GRID_WIDTH]);
     22 void renderGrid(bool [][GRID_WIDTH]);
     23 void nextGeneration(bool cur[][GRID_WIDTH], bool next[][GRID_WIDTH]);
     24
     25 int main(int argc, char **argv)
     26 {
     27   bool grid1[GRID_HEIGHT][GRID_WIDTH];
     28   bool grid2[GRID_HEIGHT][GRID_WIDTH];
     29   int generation = 1;
     30
     31   //initialize the grid
     32   if(argc==2)
     33   {
     34      initGrid(argv[1], grid1);
     35   }
     36   else
     37   {
     38      initGrid(grid1);
     39   }
     40  
     41   //run the generations, until the user presses ctrl+c
     42   while(true)
     43   {
     44     //show the appropriate grid, and generate the next population
     45     if(generation++ % 2)
     46     {
     47       //odd numbered generation
     48       renderGrid(grid1);
     49       nextGeneration(grid1, grid2);
     50     }
     51     else
     52     {
     53       //even numbered generation
     54       renderGrid(grid2);
     55       nextGeneration(grid2, grid1);
     56     }
     57
     58     //wait awhile before doing it again
     59     usleep(DELAY);
     60   }
     61
     62   return 0;
     63 }
     64
     65 //initialize the grid with random cells
     66 void initGrid(bool grid[][GRID_WIDTH])
     67 {
     68   //get the random number seeded with our present time
     69   srand(time(0));
     70
     71   //loop through each row
     72   for(int y=0; y < GRID_HEIGHT; y++)
     73   {
     74     //loop through each column
     75     for(int x=0; x < GRID_WIDTH; x++)
     76     {
     77       //1/3 of the cells are alive
     78       grid[y][x] = (rand() % 3) == 1;
     79     }
     80   }
     81 }
     82
     83 //initialize the grid from a file
     84 void initGrid(const char* fileName, bool grid[][GRID_WIDTH])
     85 {
     86   ifstream file;
     87   char c;
     88
     89   file.open(fileName);
     90
     91   //we are just going to assume that the file is valid
     92   //this is bad but in the interest of time, its okay
     93   for(int y=0; y < GRID_HEIGHT; y++)
     94   {
     95     for(int x=0; x < GRID_WIDTH; x++)
     96     {
     97       c=file.get();
     98
     99       if(c=='\n')
    100       {
    101         c=file.get();
    102       }
    103
    104       grid[y][x]= c =='*';
    105     }
    106   }
    107
    108   file.close();
    109 }
    110
    111 //render the grid
    112 void renderGrid(bool grid[][GRID_WIDTH])
    113 {
    114   //loop through the grid, rendering as we go
    115   for(int y=0; y < GRID_HEIGHT; y++)
    116   {
    117     for(int x=0; x < GRID_WIDTH; x++)
    118     {
    119       //go to the position
    120       cout << cursorPosition(x+1, y+1);
    121
    122       //print the ' ' or '*'
    123       cout << (grid[y][x] ? '*' : ' ');
    124     }
    125   }
    126 }
    127
    128 //create the next generation. The cur grid generates the next grid
    129 void nextGeneration(bool cur[][GRID_WIDTH], bool next[][GRID_WIDTH])
    130 {
    131
    132   int count;
    133
    134
    135   for(int y=0; y < GRID_HEIGHT; y++)
    136   {
    137     for(int x=0; x < GRID_WIDTH; x++)
    138     {
    139       count = 0;
    140
    141       //checks grid for asteriks
    142       if((cur[y - 1][x]) == '*')
    143       {
    144         count = count + 1;
    145       }
    146       else if((cur[y + 1][x]) == '*')
    147       {
    148         count = count + 1;
    149       }
    150       else if((cur[y - 1][x - 1]) == '*')
    151       {
    152         count = count + 1;
    153       }
    154       else if((cur[y + 1][x + 1]) == '*')
    155       {
    156         count = count + 1;
    157       }
    158       else if((cur[y][x - 1]) == '*')
    159       {
    160         count = count + 1;
    161       }
    162       else if((cur[y][x + 1]) == '*')
    163       {
    164         count = count + 1;
    165       }
    166       else if((cur[y - 1][x + 1]) == '*')
    167       {
    168         count = count + 1;
    169       }
    170       else if((cur[y + 1][x - 1]) == '*')
    171       {
    172         count = count + 1;
    173       }
    174
    175       //less than 2 living neighbors - cell dies: starvation
    176       if((cur[y][x]) == '*' && (count < 2))
    177       {
    178         next[y][x] = ' ';
    179         cout << "h" << "\n";
    180       }
    181       //more than 3 living neighbors - cell dies: overcrowding
    182       else if((cur[y][x]) == '*' && (count > 3))
    183       {
    184         next[y][x] = ' ';
    185         cout << "i" << "\n";
    186       }
    187       //2 or 3 living neighbors - cell stays alive: stability
    188       else if((cur[y][x]) == '*' && count == 2 || count == 3)
    189       {
    190         next[y][x] = '*';
    191         cout << "j" << "\n";
    192       }
    193       //dead cell with exactly 3 neighbors - cell is reborn: reproduction
    194       else if((cur[y][x]) == ' ' && count == 3)
    195       {
    196         next[y][x] = '*';
    197         cout << "j" << "\n";
    198       }
    199
    200     }
    201   }
    202 }
    And for anyone wondering just exactly what my code is doing when I run it, it's doing this
    Last edited by Psittacosis; 01-25-2014, 12:12 PM.
  • Kekeb
    davai
    • Dec 2006
    • 2765

    #2
    Re: C++ Conway's Game of Life

    You're treating your grid like it's an array of characters when it's boolean (true or false, not '*', ' ', or any other character).

    I suspect your confusion might stem from this line of code,
    Code:
    cout << (grid[y][x] ? '*' : ' ');
    which isn't checking to see if the character within the grid is '*' or ' '. The ? operator equates the previous condition and evaluates one of the following expressions depending on the result of the condition (in this case, returning '*' if the grid is true (1) at (y,x) or returning ' ' if the grid is false (0) at (y,x)) The character that's returned by the statement is then passed into cout.

    Be careful about extending beyond the bounds of your arrays.
    Last edited by Kekeb; 01-25-2014, 12:29 PM. Reason: dont know c++

    Comment

    • benguino
      Kawaii Desu Ne?
      • Dec 2007
      • 4186

      #3
      Re: C++ Conway's Game of Life

      Originally posted by Kekeb

      Be careful about extending beyond the bounds of your arrays.
      This is the first thing I noticed myself. One possible easy fix if you don't want to deal with having a lot of "if" constructs to check if you're within your boundaries, is to implement circular boundary conditions and do your operations in mod n (i.e. having "whatever % n" in your code) where n*n is your grid size. In this way, the game will play as if it's a pacman universe (or you can imagine folding up your grid into a torus if you can visualize that :P).
      AMA: http://ask.fm/benguino


      Originally posted by Spenner
      (^)> peck peck says the heels
      Originally posted by Xx{Midnight}xX
      And god made ben, and realized he was doomed to miss. And said it was good.
      Originally posted by Zakvvv666
      awww :< crushing my dreams; was looking foward to you attempting to shoot yourself point blank and missing

      Comment

      • Charu
        Snivy! Dohoho!
        FFR Simfile Author
        • Mar 2006
        • 6161

        #4
        Re: C++ Conway's Game of Life

        Fission wanted to help out in this thread, since he can't, I'm going to do it in his place.

        Originally posted by Fission
        prefer "const int" declaration to #define macros. also prefer cstdlib and ctime to stdlib.h and time.h. what is the purpose of ansi.h? you don't appear to use any of it's functionality.

        you use statements such as "generation++ % 2" but also use "count = count + 1"; you should be consistent.

        "//we are just going to assume that the file is valid
        //this is bad but in the interest of time, its okay"
        i disagree with this being ok in the interest of time. all you have to do is wrap up your open call in an if statement and exit if it's false with some message. it doesn't take much time to do and it's really bad form not to like you said.

        you mentioned c++. that means calls such as file.close() are unnecessary because destructors will take care of closing file handles. i don't know if this is something your instructor wants you to do, but it's worth noting.

        finally, you should use a debugger when something like this happens and step through one statement at a time and find out where your program isn't doing exactly what you expected. that's the general procedure to dealing with issues like this in small programs. in bigger programs you would use breakpoints and do the same thing.


        Originally posted by JohnRedWolf87
        Charu the red-nosed Snivy
        Had a very shiny nose
        And if you ever saw it
        You could even say it glows

        All of the other Snivies
        Used to laugh and call him names
        They never let poor Charu
        Join in any Snivy games

        (Click the arrow to see the rest)


        Originally posted by Vendetta21
        All in all I would say that Charu not only won this game, his play made me reconsider how I play it.

        Comment

        • Psittacosis
          AKA Cold Kitten
          • Oct 2012
          • 91

          #5
          Re: C++ Conway's Game of Life

          Let me explain that a lot of this base file is from my instructor. The #define is from him, assuming that the file is correct is from him (I know it's not difficult to check or anything), etc. He basically gave us the base code and then told us to make it work. I guess I should have clarified that. Same with the libraries.

          Also ansi.h is for cursorPosition, and at some point in time, it will be to modify some of the text. Again, that's something my instructor wants. Wouldn't bother if he wouldn't have told me to.

          EDIT: I also fixed some of the consistency issues after I went back and looked at it.
          Last edited by Psittacosis; 01-25-2014, 05:37 PM.

          Comment

          • TC_Halogen
            Rhythm game specialist.
            FFR Simfile Author
            FFR Music Producer
            • Feb 2008
            • 19376

            #6
            Re: C++ Conway's Game of Life

            Fission has asked me to post this on his behalf:

            Originally posted by Fission
            using #define works, it's just not best practice since it's not type checked and simply does text substitution. there is nothing wrong with the headers but you should prefer the ones prefixed with "c" rather than the ones postfixed with ".h". you don't have to do these things, i just recommend it so you are writing more idiomatic c++ rather than a mix of c and c++.

            my bad about sursorPosition. i didn't look at the code you included carefully enough. it makes sense now though.

            Comment

            • Psittacosis
              AKA Cold Kitten
              • Oct 2012
              • 91

              #7
              Re: C++ Conway's Game of Life

              If I'm coding the entire file myself, I do tend to use actual c++ libraries over c. Again, instructor's base file. Same with using const int over #define.

              Thanks for the suggestions though.

              Comment

              • igotrhythm
                Fractals!
                • Sep 2004
                • 6535

                #8
                Re: C++ Conway's Game of Life

                Originally posted by reuben_tate
                This is the first thing I noticed myself. One possible easy fix if you don't want to deal with having a lot of "if" constructs to check if you're within your boundaries, is to implement circular boundary conditions and do your operations in mod n (i.e. having "whatever % n" in your code) where n*n is your grid size. In this way, the game will play as if it's a pacman universe (or you can imagine folding up your grid into a torus if you can visualize that :P).
                Just say that the grid will wrap around like in Asteroids. No reason to break people's brains with the idea of a torus.

                Edit: Ooh, CK, check this out. http://en.wikipedia.org/wiki/Conway'...ife#Algorithms
                Last edited by igotrhythm; 04-24-2014, 02:39 PM.
                Originally posted by thesunfan
                I literally spent 10 minutes in the library looking for the TWG forum on Smogon and couldn't find it what the fuck is this witchcraft IGR

                Comment

                Working...