Thread: Game of life. Help

  1. #1
    Registered User
    Join Date
    Feb 2014
    Location
    NY
    Posts
    56

    Game of life. Help

    I just started working with C in my programing class. We have an assignment to create Conways game of life. I have very little knowledge of C from the class so far. I have no idea on how to implement the rules into code.

    How do I compare the values of an array based on other values in the array? How would I change or keep the value then store it in a new array?

    The professor has barley gone over arrays. The only thing we learned so far is declaring an array and how it is stored in memory.

    Rules:

    1. If two or three of the four cells above, below, or to the left or right of an occupied cell are also occupied, the the cell remains occupied; otherwise, the organism in the cell dies from loneliness.
    2. If all four of an occupied cell's neighbors are occupied, the organism dies from overcrowding.
    3. An empty cell becomes occupied by an organism if exactly three of its adjacent cells are occupied.


    This is what I have so far.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    char r,c;
    int main (void) {
       FILE *fp;          // three lines to define the data file
       const char *fn;
       fn="testData5.dat";
     
       //char lineIn[30];
    
       fp=fopen(fn,"r");          // open file for input
    
    char gameofLife[25] [25];  //array for game board original pattern
    char gameofLife1[25] [25];  //array for current pattern
    char gameofLife2[25] [25];  //array for revised pattern
    int i,j,count,it;
    
    count=fread(&gameofLife[0][0], sizeof(char), 25*25, fp); //Wrties file into gameofLife array 
                                                     //with a size of 24*24 charatcters
    char *h = &gameofLife1[0][0]; //Assign pointer h to gameofLife1 array
    char *r = &gameofLife2[0][0]; //Assign pointer r to gameofLife2 array 
    char *g = &gameofLife[0][0]; //Assign pointer g to gameofLife array
        if(*h!=*r){
            printf("change = Yes\n");
                }
        else{
            printf("change = No\n");
            }
    
          
            for(i=0;i<count;++i)        //for loop displays data stored in array
              printf("%c", *g++);        //displayes gameofLife array
    
    
    
    
                    
    
       fclose(fp); // close file
            return 0;
    }
    Last edited by 3DT; 02-19-2014 at 11:25 AM.

  2. #2
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    First things first: code that is clear and readable, and easy to reason about (i.e. figure out what it's doing) is of utmost importance. Especially when you're a newbie. In that light:

    • Don't use global variables. Read this link. Instead, declare variables in the appropriate functions and pass them to other functions as parameters when needed.
    • Use properly formatted and indented code. Read this.
    • Don't use magic numbers. #define some constants.
    • Comments should only be used when the code is not "self documenting". Don't comment the obvious lines, it clutters up your file. Use comments to explain confusing sections of code, or why you chose to do things a particular way, that might not seem like the obvious way of doing things. Of course, this doesn't apply if your professor requires you to comment every line.
    • Never write code unless you already know how to solve the problem. If you can't solve the program with paper and pencil, then you can't program a computer to do it.


    All that may seem trivial and irrelevant. In a sense it is, you can still write correct code without it. It's just much, much harder.

    Regarding a process to follow:

    1. Make sure you understand the problem and all the requirements: what is it asking of you? what data/input will you get and in what format? what must you do with that data? what output are you expected to produce?
    2. Solve the problem with paper and pencil. As noted above, you must know how to do it before you can program a computer to do it.
    3. Pay careful attention to every little step you take to solve the problem, and use those steps to produce pseudo code.
    4. Turn that pseudo code into real code. Work in small chunks, 5-10 lines at a time. Compile (at maximum warning level), and fix all errors and warnings.
    5. Test your code to make sure it works. Fix any bugs. No moving on until all the code so far works perfectly
    6. Repeat steps 4 and 5 until done with the program.


    A few specifics about the code you have now:
    1. You need to check the return value of your file functions. Read the documentation for fopen and fread (and all the functions you use -- search the web). If fopen fails, your program should terminate, you can't start the game with no input data. Same with fread. If you read partial or no data, you can't continue.
    2. fread is usually used for binary data. You didn't specify, so can you verify if that is the format of your file?

    As for the general solution, there is a great Wikipedia article on Conway's game of life with several examples, and lots of other resources on the web. Some graph paper and a few small examples (5x5 or 10x10) will come in handy.

    Two hints:
    1. You will need to count the neighbors of any given cell, so that is an important thing to learn to do with arrays. Again, use graph paper.
    2. The "easy" solution will use 2 arrays, one for the current state of the game, and one to hold the "next" state, as you calculate it.

  3. #3
    Registered User
    Join Date
    Feb 2014
    Location
    NY
    Posts
    56
    What do I have that should be a constant?

    I need three arrays because the final iteration is compared to the first.

    I have no idea how I would count the cells. I know where they would be located but how do it use the data from the array.

    If I was on gameofLife[10][4] I would need to compare it to gameofLife[9][4],gameofLife[10][3],gameofLife[10][5], and gameofLife[11][4].

    I dont understand how to do this with code. I can do it on paper.

    The data input file looks like this: * = alive, _ = dead
    Code:
    ----**-*-*--***-*--****-*
    -**-**-****-***-**-**-*-*
    ***-**-*-*-****----******
    **--**-***--***-*******-*
    -**-**-*-*--***-*--****-*
    -***-*-****-***-*--****-*
    ---***-*-*-****-*--****-*
    ***-**-*-*-****-**-****-*
    ***-**-****-***-*-*****-*
    ***-**-****-***-*-**--*-*
    ----**-*-*-****-*--****-*
    -**-**-***--***-**-****-*
    -*--**-*-*--*****--****-*
    **--**-*-*--***-**-****-*
    --****-*-*-*-***-**--**-*
    -*-***-*-*--***-*--****-*
    -**-**-*-*-****-*-*****-*
    --***-*-***-***-*--****-*
    -***-*****--*****--****-*
    **-***-*-*-****-*--****-*
    -*--**-****-*****-*****-*
    -*--**-***--***-**-****-*
    -**-**-*-*--***-**-****-*
    ***-**-*-**-*****--****-*
    --***-*-*--***-**--****-*
    Fixed fopen: That was provided by the professor, we havent covered files yet.
    Code:
       fp=fopen(fn,"r");          // open file for input
         if (fp==NULL) {
            fputs ("File error",stderr);
                         }
    Last edited by 3DT; 02-19-2014 at 01:42 PM.

  4. #4
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by 3DT View Post
    What do I have that should be a constant?
    Any magic number. Any time you use an actual number throughout your code. 24 is a good example. So do something like:
    Code:
    #define GAME_ROWS 24
    #define GAME_COLS 24
    ...
    char currentBoard[GAME_ROWS][GAME_COLS];
    ...
    for (i = 0; i < GAME_ROWS; i++) {
        for (j = 0; j < GAME_COLS; j++) {
            currentBoard[i][j]  // do something with currentBoard[i][j]
        }
    }
    That way you can change your game board size easily, by changing just 2 lines of code (the #defines). This allows for easier testing of a small board, for which you can make your own input files.

    Quote Originally Posted by 3DT View Post
    I need three arrays because the final iteration is compared to the first.
    Ahh, okay. So make 3 arrays. Give them sensible names like initialBoard, currentBoard and nextBoard. Read into initialBoard and copy that into currentBoard.

    Quote Originally Posted by 3DT View Post
    I have no idea how I would count the cells. I know where they would be located but how do it use the data from the array.

    If I was on gameofLife[10][4] I would need to compare it to gameofLife[9][4],gameofLife[10][3],gameofLife[10][5], and gameofLife[11][4].

    I dont understand how to do this with code. I can do it on paper.
    Sounds like you get the idea, but maybe just worded it poorly. You don't want to compare it to the neighbors, you need to count how many of the neighboring cells are occupied. So, for each round of the game, you must go through each cell in currentBoard. You will have a nested loop like I wrote above, accessing currentBoard[i][j] and it's neighbors. Using your example, i would be 10 and j would be 4. How would you systematically turn 10 into 9? How about 4 into 5? What mathematical operations would you use to access the neighboring elements? Note that you can put complex expressions in an array index, like currentBoard[i * 42 - 319][(j + 17) * 22], just make sure you never go outside the array bounds. So find the expressions for the indexes of the 4 neighbors, and count up the occupied cells, and set the corresponding cell in nextBoard (i.e. nextBoard[i][j]) to the right value.

    I fear giving you any more hints in this area might rob you of the problem solving aspect of this problem, which is the fun part.
    Quote Originally Posted by 3DT View Post
    The data input file looks like this: * = alive, _ = dead
    Code:
    ----**-*-*--***-*--****-*
    -**-**-****-***-**-**-*-*
    <snipped for brevity>
    ***-**-*-**-*****--****-*
    --***-*-*--***-**--****-*
    That looks like it's more in a text format since there appear to be new lines after each row of the board. Your fread function would not read the whole file since it would read the new lines and count that as a spot in the board. I suggest using fgets to read a line (a 1-d char array), then copying that data into the appropriate row of your board.
    Quote Originally Posted by 3DT View Post
    Fixed fopen: That was provided by the professor, we havent covered files yet.
    Code:
       fp=fopen(fn,"r");          // open file for input
         if (fp==NULL) {
            fputs ("File error",stderr);
                         }
    Close. You correctly print an error, but you let the program continue. Try adding a return 1; after you print an error, so your program exits before trying to read from an unopened file (which can cause undefined behavior meaning anything can happen though likely it will manifest as a program crash). Also, I prefer the perror() function for printing errors. It uses the value of errno to print a more useful message that explains (to a degree) why it failed.

    Note, this program would benefit from functions, if you've learned to write them yet. At the least, one to read in the initial board (and close the file when done), one to print out the board, and one to update the board to the next.

  5. #5
    Registered User
    Join Date
    Feb 2014
    Location
    NY
    Posts
    56
    I've spent countless hours on this and still not much progress. Whats wrong with this? It doesn't do anything. Output stays the same.
    Code:
    for(int i=0;i<rows; i++){                        
        for(int j=0;j<collums;j++){
                t='*';
                u='_';
            if (gameR[i][j] == gameC[i][j-1]){
                    x=x+1;
                }
            if (gameR[i][j] == gameC[i][j+1]){
                    x=x+1;
                }
            if (gameR[i][j] == gameC[i+1][j]){
                    x=x+1;
                }
            if (gameR[i][j] == gameC[i-1][j]){
                    x=x+1;
                }
            if (x==4){
                gameR[i][j]=u;
                    }
            if (x==3){
                gameR[i][j]=t;
                    }
            if (x==2){
                gameR[i][j]=t;
                    }
            if (x==1){
                gameR[i][j]=u;
                    }
            if (x==0){
                gameR[i][j]=u;
                    }
            }
        }

  6. #6
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    You aren't initialising x on each loop.

    I might be wrong because it's been a while but don't diagonally adjacent squares also count?

    I have a feeling that using the gameR matrix is probably causing the wrong behaviour too but it's too difficult to tell without seeing the rest of your code. Either way you can replace those comparisons by only using your gameC matrix (I'm assuming from context that gameC is the previous generation).

    Also you need to make provisions for when you are at the edges of your matrix. For example on the very first iteration of your loop you will enounter if (gameR[0][0] == gameC[0][-1] ){ which is a bad array index.

    It seems unnecessary to initalise t and u in each loop. To be honest it seems unnecessary to initialise these at all. I would make '_' and '*' preprocessor macros (e.g #define EMPTY '_').

    Your code for assigning the character to the matrix square can be greatly simplified. You only need one case for when it is not emtpy ( when x is either 2 or 3 ) and another for when it is empty (all other cases).

  7. #7
    Registered User
    Join Date
    Feb 2014
    Location
    NY
    Posts
    56
    Quote Originally Posted by DeadPlanet View Post
    You aren't initialising x on each loop.
    Can you elaborate on this?

    Quote Originally Posted by DeadPlanet View Post
    You aren't initialising x on each loop.

    Also you need to make provisions for when you are at the edges of your matrix.
    How?

  8. #8
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    @3DT:
    Why do you insist on using poorly named variables. Trying to save a few keystrokes by using x, u and t instead of num_neighbors, EMPTY_CELL and OCCUPIED_CELL (note capitalized because they're constants) helps nobody, least of all us, who you are relying on to get through this program.

    What are gameR and gameC? It's not clear what the letters stand for, or which is the current state (possibly C) and which is the next state (there's no N). Just spell out the two game boards in full, so you and us are clear on what you're trying to do.

    Also, as DeadPlanet suggested, using gameR (or maybe gameC) in those if statements is incorrect. You only want to look at neighbors of the current board state to see if they're occupied (not if they match some arbitrary state from the next board state). Write some pseudo code to describe what you're doing -- this is a key step between the rules you listed in your first post, and a working solution -- translating that to code will be fairly simple. Something like:
    Code:
    for each square
        num_neighbors = 0
        if the cell above the this cell in the current board is occupied
            num_neighbors++;
        if the cell below...
    
        // now we have counted all the neighboring cells, decide whether this cell will be
        // occupied or empty in the next board state
        if this cell in the current board is occupied and num_neighbors is...
            this cell in the next board is ...
        else
            this cell in the next board is ...
        if this cell in the current board is empty and num_neighbors is...
    
        // we filled in the next board state, copy next board to current board and print if necessary
    @DeadPlanet:
    Per post #1, diagonal squares don't count in this version.

  9. #9
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    Let's say that x starts out with the value of 0 before your loop even runs. After your first loop assume that you found three adjacent squares were occupied (assuming the array indexing issue was solved), x would now be 3. x == 3 would evaluate to true and the appropriate if-branch would execute. There's no problem there.
    Now what value does x contain when your innermost loop executes the next iteration?

    Depends if it is an assignment or not. If it is an assignment then your assignment sheet or your lecturer/tutor/teacher should say. Otherwise there are three approaches I can think of:

    1. Make a buffer of dead cells all around the array. They cannot be occupied. This will result in an inaccurate simulation but will be fit for simple purposes.

    2. Wrap around. Any access that goes past the end of the array will wrap around to the beginning of the array. Say I have
    Code:
    array[3] = { 10, 11, 12 };
    ] and I'm trying to achieve something similar to what you are. Then when I access array[3] (note that valid indexes here are 0-2) I would want to actually be indexing array[0]. This can be achieved with the modulus operator (%). Note that special care will be needed to extend this to two dimensions and for numbers that go past the left.

    3. Dynamically allocate memory or use a more advance data structure (I think Bill Gosper invented the de facto standard GoL data structure, don't remember what it's called though. that info might be a bit old too. I should read Hackers again, good book) to simulate an 'infinite' grid. This is probably too advanced for you so I wouldn't worry about this one.

    The double post happened because of the 'code must be in code tags' rule. That's your fault, Cboard, not mine.
    Last edited by DeadPlanet; 02-23-2014 at 03:01 AM.

  10. #10
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    Let's say that x starts out with the value of 0 before your loop even runs. After your first loop assume that you found three adjacent squares were occupied (assuming the array indexing issue was solved), x would now be 3. x == 3 would evaluate to true and the appropriate if-branch would execute. There's no problem there.
    Now what value does x contain when your innermost loop executes the next iteration?

    Depends if it is an assignment or not. If it is an assignment then your assignment sheet or your lecturer/tutor/teacher should say. Otherwise there are three approaches I can think of:

    1. Make a buffer of dead cells all around the array. They cannot be occupied. This will result in an inaccurate simulation but will be fit for simple purposes.

    2. Wrap around. Any access that goes past the end of the array will wrap around to the beginning of the array. Say I have
    Code:
    array[3] = { 10, 11, 12 };
    ] and I'm trying to achieve something similar to what you are. Then when I access array[3] (note that valid indexes here are 0-2) I would want to actually be indexing array[0]. This can be achieved with the modulus operator (%). Note that special care will be needed to extend this to two dimensions and for numbers that go past the left.

    3. Dynamically allocate memory or use a more advance data structure (I think Bill Gosper invented the de facto standard GoL data structure, don't remember what it's called though. that info might be a bit old too. I should read Hackers again, good book) to simulate an 'infinite' grid. This is probably too advanced for you so I wouldn't worry about this one.

  11. #11
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by 3DT View Post
    Can you elaborate on this?
    When you get back to the top of the loop (line 3 of the code in post #5) the second, third, fourth, time, etc, what is the value of x?
    Quote Originally Posted by 3DT View Post
    How?
    DeadPlanet already pointed out that you should beware of negative array indexes. Time for you to put your thinking cap on. What programming construct could you use to check a variable and do something based on it's value? Note that, just like you need to check if your array indexes would be less than 0, you also need to check if the are too big, lest they go off the other end of the arrays.

  12. #12
    Registered User
    Join Date
    Feb 2014
    Location
    NY
    Posts
    56
    I still dont know how to make provisions for outside of the array. Everything I tried gave me random characters.

    Anyways I have it functioning and the now grid changes. The only thing I would like to do is display the output like this.
    Code:
    Iteration 1, change = YES
    ____**_*_*__***_*__****_*     ____**__*___***____****__
    _**_**_****_***_**_**_*_*     _**_**_**__**_*_*__**_***
    ***_**_*_*_****____******     *_*_**_*_**___*____*_*_**
    _**_**_*_*__***_*__****_*     _*****_*_*__*_*_*__*__*_*
    _***_*_****_***_*__****_*     _***_*_**__**_*_*__*__*_*
    ___***_*_*_****_*__****_*     __****_*****__*_*__*__*_*
    ____**_*_*_****_*__****_*     ____**_*_**___*_*__****_*
    _**_**_***__***_**_****_*     _*__**_***__*_***__*__*_*
    _*__**_*_*__*****__****_*     _*__**_***__*__***_*__*_*
    **__**_*_*__***_**_****_*     _*__**_*_*__*_*_*****_*_*
    __****_*_*_*_***_**__**_*     _*_*_*_*_*___*___*_****_*
    _*_***_*_*__***_*__****_*     ___*_*_*_*_**_**__***_*_*
    _**_**_*_*_****_*_*****_*     _**_***_***___*_*_____*_*
    __***_*_***_***_*__****_*     _****___*__**_***__*__*_*
    _***_*****__*****__****_*     _***_*****__*__**__*__*_*
    **_***_*_*_****_*__****_*     _*******_**___*_*__*__*_*
    _*__**_****_*****_*****_*     _*__**_**__**__***____*_*
    _*__**_***__***_**_****_*     _*__**_***__*_******__*_*
    _**_**_*_*__***_**_****_*     _**_**_***__*_****_*__*_*
    __***_*_*__***_**__****_*     __****_*____*****__****__
    So how can I print my two arrays side by side like this?

  13. #13
    Registered User
    Join Date
    Jan 2009
    Location
    Australia
    Posts
    375
    Have a go at it and post your code. If you can print one matrix then printing two matrices shouldn't be that much of a jump.

  14. #14
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,909
    Quote Originally Posted by 3DT View Post
    I still dont know how to make provisions for outside of the array. Everything I tried gave me random characters.
    Describe in English or pseudo code what you think these "provisions" are. If you can't do that, you have no business touching the keyboard. You need to stop trying to solve this by taking random stabs at coding a solution. You might as well get a room full of monkeys at let them write your program.

    So tell me (in a bit more detail than "don't go outside the array") what it is you are trying to do, and I can help you do it. You will likely find that if you spend the time to write this out, you will end up "seeing" the code you need to write.
    Quote Originally Posted by 3DT View Post
    So how can I print my two arrays side by side like this?
    What makes you think you have to print all of one array before printing all of the other? C prints line-by-line, so you need to think about printing one line at a time, not one variable/array at a time. If that line contains data from more that one array, then so be it.

  15. #15
    Registered User
    Join Date
    Feb 2014
    Location
    NY
    Posts
    56
    Quote Originally Posted by anduril462 View Post
    What makes you think you have to print all of one array before printing all of the other? C prints line-by-line, so you need to think about printing one line at a time, not one variable/array at a time. If that line contains data from more that one array, then so be it.
    I know how to print them next to each other. I want to separate the two arrays by a space.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. the game of life
    By ben432 in forum C Programming
    Replies: 1
    Last Post: 06-13-2011, 10:23 AM
  2. Game of Life... Turned my life to HELL!
    By yigster in forum C Programming
    Replies: 1
    Last Post: 05-21-2009, 06:29 PM
  3. Game of Life
    By puk284 in forum C# Programming
    Replies: 2
    Last Post: 11-17-2008, 03:53 AM
  4. Game Of Life
    By din1983 in forum C Programming
    Replies: 20
    Last Post: 10-11-2005, 10:36 PM
  5. Game of life
    By JoshR in forum C++ Programming
    Replies: 30
    Last Post: 04-03-2005, 02:17 PM