/* THE GAME OF LIFE Written and produced by Chris C. Keeser on 6/8/04 sitting on my couch listening to music at 12:30 in the morning oh what a good feeling that was. (seriously, it was the most peace I have had all week) */ #include "life.hxx" #define N 100 // N is (desired max number + 1) that my rand() number will create //////////////////////////////////////////// /* NAME: Where_am_i DESCRIPTION: The workhorse of the game of life. Everything is coordinated from here keeps track of the current location in the old_g (here_i_am) and new_g arrays (children) and holds the all important "neighbor tally" PAPRAMETERS: the Old_g array, and the new_g array PRE-CONDITIONS: old_g and new_g must exist POST-CONDITIONS: when this all done, the next generation of life has been calculated RETURN: zilch, its another void function. SIDE EFFECTS: headache, red eyes, and possible sleep deprevation. side effects also occured with tv marathon. */ ///////////////////////////////////////////// void where_am_i(int old_g[MAXR][MAXC], int new_g[MAXR][MAXC]) { int *here_i_am, r =0, c = 0, *children, neighbors; // here_i_am pointer, the location // inside the old_g array. r = ROWS, c = COULUMNS, children pointer, the location // inside the new_g array that corresponds to the same position in the old_g array // neighbors, the tally of the neighbors for the position of here_i_am. int *ptr_neighbors; // I used this so I didn't have to pass anything // back from my other functions (all my functions are return void functions) ptr_neighbors = &neighbors; for(r = 0; r <= (MAXR - 1); r++) // row increment from 0 to 99 { for(c = 0; c <= (MAXC - 1); c++) // column increment from 0 to 99 { neighbors = 0; // initialize neighbors (not really necessary) here_i_am = &old_g[r][c]; // here_i_am givin an adress of the current position in old_g children = &new_g[r][c]; // children givin an adress of the current position in new_g find_neighbors(here_i_am, ptr_neighbors, old_g); // WOA! this is one serious function! // finds all the neighbors around here_i_am and does it by ARRAY WRAPPING!!!! // so the entire array functions like a globe or a planet where there are no edges // or borders. returns the number of neighbors through the neighbor pointer. // add up neighbors to determine life or death find_future_state(here_i_am, neighbors, children); // write next generation to new_g } } copy_planet(new_g, old_g); // copys the new_g to the old_g clean_new_generation(new_g); // cleans the new_g (not really necessary) // copy new array to old array, clean new, display old, start over return; } //////////////////////////////////////////// /* NAME: copy_planet DESCRIPTION: uuuuh, it copies the new array to the old array. PAPRAMETERS: the new array and the old array PRE-CONDITIONS: new and old arrays must exist POST-CONDITIONS: none RETURN: I'm running out of ways to say "nothing" :) its a void function SIDE EFFECTS: a parrallel universe is created when the array is copied and all the good life is stripped out of the new array and put into the old array and as a result the new array is pure evil and must be DESTROYED!!! */ ///////////////////////////////////////////// void copy_planet(int new_g[MAXR][MAXC], int old_g[MAXR][MAXC]) // copies new_g to old_g { int r = 0, c = 0; // r = ROWS, c = COLUMNS for(r = 0; r <= (MAXR - 1); r++) // row increment from 0 to 99 { for(c = 0; c <= (MAXC - 1); c++) // column increment from 0 to 99 { old_g[r][c] = new_g[r][c]; // old_g = new_g } } clean_new_generation(new_g); // clean up the new generation return; } //////////////////////////////////////////// /* NAME: find_neighbors DESCRIPTION: holy mackeral, the most insane function to write. This function gathers the number of neighbors that are alive adjacent to here_I_am. What made this function challenging to write was the fact that I wanted my "World" to exist like a sphere and have no boundaries. therefore life on the edges of the array had a fighting chance to survive. therefore EVERY cell has the possibility of having 8 living neighbors. PAPRAMETERS: int *here_i_am, the pointer to the position in the old_g array that we are trying to find the neighbors for. int *neighbors, the pointer that points to a local variable declared in function where_am_i called neighbors. this allows me to pass the information back to where_am_i without having to return a value. int limit[][] is the adress of the first value in the int array and is used as an edge marker to make it easier to determine if we have passed outside of the array PRE-CONDITIONS: old_g and new_g array must exist and must have passed through where_am_i to create a position to work on. POST-CONDITIONS: the number of neighbors of a particular cell is reported back to where_am_i RETURN: blank empty meaningless VOID SIDE EFFECTS: a much better understanding of pointer arithmetic and arrays in memory */ ///////////////////////////////////////////// void find_neighbors(int *here_i_am, int *neighbors, int limit[MAXR][MAXC]) { int *safety, n; // when I'm all done, I hope I'm at the same safety = here_i_am; // memeory location, safety is my check here_i_am -= MAXC; // top neighbor, MOVING UP ~ 100 if(here_i_am < &limit[0][0]) // check to see If I have extended above array { here_i_am += (MAXR * MAXC); // wrap around to bottom ~ 10,000 } *neighbors += *here_i_am; // add the value to neighbors if it is alive here_i_am -= 1; //top left neighbor, MOVING LEFT for(n = MAXR; n >= -1; n--) // need to check if it went too far left { if(here_i_am == &limit[(n)][(MAXC - 1)]) // if i'm in the last location of another row ~ [(n)][99] { here_i_am += (MAXC); // if it did, wrap around ~ 100 } } *neighbors += *here_i_am; // add the value to neighbors if it is alive here_i_am += MAXC; // left neighbor, MOVING DOWN ~ 100 if(here_i_am > &limit[(MAXR - 1)][(MAXC - 1)]) // check to see if we have gone too low ~ [99][99] { here_i_am -= (MAXR * MAXC); // if we did, wrap around to the top of array ~ 10,000 } *neighbors += *here_i_am; // add the value to neighbors if it is alive here_i_am += MAXC; // bottom left neighbor, MOVING DOWN ~ 100 if(here_i_am > &limit[(MAXR - 1)][(MAXC - 1)]) // If I have extended below array ~ [99][99] { here_i_am -= (MAXR * MAXC); // wrap around to top ~ 10,000 } *neighbors += *here_i_am; // add the value to neighbors if it is alive here_i_am += 1; // bottom neighbor, MOVING RIGHT for(n = -1; n <= MAXR; n++) // need to check if it went too far right ~ 100 { if(here_i_am == &limit[(n)][0]) // if i'm at 0 in the wrong row { here_i_am -= MAXC; // if it did, wrap around ~ 100 } } *neighbors += *here_i_am; // add the value to neighbors if it is alive here_i_am += 1; //bottom right neighbor, MOVING RIGHT for(n = -1; n <= MAXR; n++) // need to check if it went too far right { if(here_i_am == &limit[(n)][0]) // if i'm at 0 in the wrong row { here_i_am -= MAXC; // if it did, wrap around to left of array } } *neighbors += *here_i_am; // add the value to neighbors if it is alive here_i_am -= MAXC; // right neighbor, MOVING UP ~ 100 if(here_i_am < &limit[0][0]) // check to see if we went too high { here_i_am += (MAXR * MAXC); // if we did wrap to bottom of array ~ 10,000 } *neighbors += *here_i_am; // add the value to neighbors if it is alive here_i_am -= MAXC; // top right neighbor, MOVING UP ~ 100 if(here_i_am < &limit[0][0]) // check to see if we went too high { here_i_am += (MAXR * MAXC); // if we did wrap to bottom of array ~ 10,000 } *neighbors += *here_i_am; // add the value to neighbors if it is alive // return to the original cell here_i_am -= 1; //top neighbor, MOVING LEFT for(n = MAXR; n >= -1; n--) // need to check if it went too far left { if(here_i_am == &limit[(n)][(MAXC - 1)]) // in the wrong spot { here_i_am += MAXC; // if it did, wrap around } } here_i_am += MAXC; // ORIGINAL CELL, MOVING DOWN if(here_i_am > &limit[(MAXR - 1)][(MAXC - 1)]) // If I have extended below array { here_i_am -= (MAXR * MAXC); // wrap around to top } if(safety != here_i_am) // error checking statement. if I do not end up in the same //spot that I was started in then I am completely lost... not good { printf("Starting adress of LIMIT[0][0] : %d\n", &limit[0][0]); // alert user of problem printf("ARRAY FAULT!!! \n"); // and give them information that is completely useless and cryptic printf("safety : %d\n", safety); // unless they wrote the program :) printf("here :%d\n", here_i_am); // i love programming } return; } //////////////////////////////////////////// /* NAME: clean_new_generation DESCRIPTION: you rember that evil parrallel universe array I told you about? did you ever see langoliers? no? well its this movie where these people on an airplane go through a portal to a parrallel dimension where these big eating creatures gobble up the "old earth" and... oh, you just want the function description. it resets the new_g array to 0. PAPRAMETERS: the new_g array filled with baddies that need to go bye-bye PRE-CONDITIONS: new_g array must exist and need to be cleaned POST-CONDITIONS: the new_g array is sparkly clean and ready to do it all over again. RETURN: how do you say "nothing" in cantonese? pow-chow'kichingweflorrr *click* ? (its a void) SIDE EFFECTS: horrible movie ratings and another second rate t.v. time-slot filler, oh, i mean all data in new_g is lost if the program is not set up properly. */ ///////////////////////////////////////////// void clean_new_generation(int new_g[MAXR][MAXC]) { int r = 0, c = 0; // r and c, row and column for(r = 0; r <= (MAXR - 1); r++) // yeah, you know this by now I'm sure { for(c = 0; c <= (MAXC - 1); c++) // ditto { new_g[r][c] = 0; // MAKE IT NEW!!!!!! } } return; } //////////////////////////////////////////// /* NAME: generate_random_start DESCRIPTION: this function is cool! it takes a interger percentage and creates an appropriate number of living cells to make that percentage of life. oh and it does it in a completely random way. P.s. the random code is NOT my own, at the time it was (and probably still is) a bit above my head, but it did exactly what I needed it to do. the REALLY cool part is that the random seed is taken from the system clock so that the seed changes every time you run the program. the code that I used is from http://cplus.about.com/library/weekly/aa041403b.htm . it generates two random numbers that are used as coordinates to place life. if life already exists there, then it tries a new location to place life. this way you are garanteed to get the requested percentage of life. and yes, I know that as the percentage goes up that the processor has to try more and more times to find a spot that has no life... but it was a design decision that I made to ENSURE that I met the requirements for the program. PAPRAMETERS: give me an integer precentage and an array to fill. PRE-CONDITIONS: you must have passed a valid command line argument to main, and array old_g must exist. POST-CONDITIONS: the world is ready to do your bidding. RETURN: VOID!!!! SIDE EFFECTS: I have run out of witty things to say. */ ///////////////////////////////////////////// void generate_random_start(int percentage, int old_g[MAXR][MAXC]) { int r = 0, c = 0, n = 0, cells = 0; // r and c. you know those guys, cells is the // number of cells that have to be populated to meet the percentage requirements. srand( (unsigned)time( NULL ) ); //random seed from system clock cells = ((float) MAXR * MAXC) * float (float (percentage) / 100.0); // the equation that gives // me the number of cells required to create the desired percentage of life. while(n <= cells) // while my actual cells that have been made "alive" // is still less than the required amount, keep going { r = (int) MAXR * rand() / (RAND_MAX + 1.0); // my r random coordinate between 0 and 99 c = (int) MAXC * rand() / (RAND_MAX + 1.0); // my c random coordinate between 0 and 99 if(old_g[r][c] != 1) // if cell is dead { old_g[r][c] = 1;// make alive n++; // one down. still have (cells - n) to go } } return; }