/***************** CONWAY'S GAMES OF LIFE VERSION 2 ******************* Features user defined grid size and variable number of starting microbes. This is my second rewrite of Conway's Game of Life including all the suggestions that Erin made. Changes are... o More functions (For easier reading) o Included 'else if' statements o Proper declaration of functions involving arrays o Some checking of user input o General neatening of code **********************************************************************/ /* Some includes */ #include /* Define some constants */ #define aliveChar '*' #define deadChar ' ' #define borderCharTop '-' #define borderCharSide '|' #define maxGridWidth 50 #define maxGridHeight 25 #define minGridSize 8 #define minPop 4 main() { /* Declare some vars. */ int gridHeight, gridWidth, startPop, maxPop, genCount; char grid[maxGridHeight][maxGridWidth]; /* Prototype some funtions. */ int getInt(int, int); int getYN(); void printOut(char[][], int, int); void initGrid(char[][], int, int, int); void evolveGrid(char[][], int, int); /* Get various variables from User */ printf("Enter width of grid including border (%d-%d): ",minGridSize,maxGridWidth); gridWidth = getInt(maxGridWidth,minGridSize); printf("Enter height of grid including border (%d-%d): ",minGridSize,maxGridHeight); gridHeight = getInt(maxGridHeight,minGridSize); maxPop = (int) ((gridHeight-2) * (gridWidth-2)) / 2; /* max is 1/2 grid size */ printf("Enter starting population (%d-%d): ",minPop, maxPop); startPop = getInt(maxPop,minPop); /* Initialise the grid */ initGrid(grid, gridHeight, gridWidth, startPop); /* Main drive of program. Gives prompt to continue. */ genCount = 1; do { printf("\n"); printOut(grid, gridHeight, gridWidth); /* Output grid */ printf("\nGeneration: %d\n", genCount); evolveGrid(grid, gridHeight, gridWidth); /* Update grid */ genCount++; /* Increment for next pass */ printf("Go again? (y/n): "); } while (getYN()); } /* End of main */ /**************************** initGrid() ***************************** Initialises grid with random alive cells as specified in params. ********************************************************************/ void initGrid(char grid[maxGridHeight][maxGridWidth], int gridHeight, int gridWidth, int startPop) { /* Declare local vars. */ int i, j, k, aliveIndex; /* Initialise grid with dead cells */ for (i=0; i < gridHeight; i++) { for (j=0; j < gridWidth; j++) { grid[i][j] = deadChar; } } /* SCATTER THE LIVING CELLS */ /* This drove me crazy thinking how to do this. This is the third * solution I came up with! */ for (i=0; i < startPop; i++) { /* Generate number between 1 and no. of dead cells in valid squares */ srandom(time(0)); /* Below is: Grid squares - alive cells - 1 square border */ aliveIndex = random() % ((gridHeight-2) * (gridWidth-2) - i); /* Increment so it is not a zero based no. This is necessary for the * loop below to work correctly */ aliveIndex++; /* Make the "aliveIndex'th" dead cell encountered alive */ for (j=1; j < (gridHeight-1); j++) { for (k=1; k < (gridWidth-1); k++) { if (grid[j][k] == deadChar) { aliveIndex--; } if (!aliveIndex) { grid[j][k] = aliveChar; goto NEXTCELL; } } } NEXTCELL: } } /************************** evolveGrid() ***************************** Updates the grid for another generation ********************************************************************/ void evolveGrid(char grid[maxGridHeight][maxGridWidth], int gridHeight, int gridWidth) { /* Declare some local vars. */ int i, j, k, l, neighbours; char buff[maxGridHeight][maxGridWidth]; for (i=1; i < (gridHeight-1); i++) { for (j=1; j < (gridWidth-1); j++) { /* Start loop to iterate over neighbours */ neighbours=0; for (k=i-1; k < (i+2); k++) { for (l=j-1; l < (j+2); l++) { if (grid[k][l] == aliveChar) { neighbours++; } } } /* Remove one if itself is alive */ if (grid[i][j] == aliveChar) { neighbours--; } /* THE CONWAY RULES */ /* Birth */ if (grid[i][j] == deadChar && neighbours == 3) { buff[i][j] = aliveChar; /* Death */ } else if (grid[i][j] == aliveChar && (neighbours < 2 || neighbours > 3)) { buff[i][j] = deadChar; /* Survival */ } else if (grid[i][j] == aliveChar) { buff[i][j] = aliveChar; /* Dormant */ } else { buff[i][j] = deadChar; } } } /* Copy buff into grid */ for (i=1; i < (gridHeight-1); i++) { for (j=1; j < (gridWidth-1); j++) { grid[i][j] = buff[i][j]; } } } /******************************* getInt() **************************** Retrieves an integer from STDIN ********************************************************************/ int getInt(int max, int min) { int valid, num; char usrInput[5]; do { scanf("%s",usrInput); num = atoi(usrInput); if ((num >= min) && (num <= max)) { valid = 1; } else { valid = 0; printf("Valid range is %d-%d, please re-enter: ",min,max); } } while (!valid); return(num); } /************************* printOut() ******************************** Prints an array passed in param to STDOUT ********************************************************************/ void printOut(char grid[maxGridHeight][maxGridWidth], int gridHeight, int gridWidth) { int i, j; for (i=0; i < gridHeight; i++) { for (j=0; j < gridWidth; j++) { /* Makes sure there is a space to the side of grid at top */ if ((i==0 || i==(gridHeight-1)) && j==0) { printf(" %c",borderCharTop); } else if (i==0 || i==(gridHeight-1)) { printf("%c%c",borderCharTop,borderCharTop); } else if (j==0 || j==(gridWidth-1)) { printf(" %c",borderCharSide); } else { printf(" %c", grid[i][j]); } } printf("\n"); } } /**************************** getYN() ******************************** Returns 1 if yes, 0 if no. NEEDS WORK. ********************************************************************/ int getYN() { int ret; char ans; do { scanf("%1s",&ans); /* %c doesn't work here, Why? */ if (ans == 'y' || ans == 'Y') { ret = 1; } else if (ans == 'n' || ans == 'N') { ret = 0; } else { printf("Please just enter 'y' or 'n': "); ret = 2; } } while (ret == 2); return(ret); }