/* * C program for Conway's ``game of life''. * * Input is from command line and a file: * * Command-line arguments are as follows: * either the name of an input file or the keyword "random" and the size * of the board and the seed for random-number generation * number of steps * how often to print results (P means print results every P steps) * * If an input file is specified, it contains a representation of the initial * board configuration: N (size of board) and N*N values (each 0 or 1). */ #include #include #include #include "timer.h" /* * Data structure for board: * * "size" is the size of the (square) board. * "cells" and "new_cells" are pointers to 1D arrays to hold two board * configurations (the current one and the one being computed for the next * time step). Each array is of size (size+2)*(size+2), to allow for a * one-cell-wide border of always-dead cells. (This simplifies the coding * a bit.) The 2D board configuration is stored in this 1D array in * row-major order. */ typedef struct { int size; int* cells; int* new_cells; } board_t; /* macro to compute 1D index into actual array given 2D coordinates. * see read_board for typical usage. */ #define cell_index(row, col, ncols) ((row)*((ncols)+2) + (col)) int read_board(FILE* infile, board_t *board); int random_board(int size, int seed, board_t *board); void update_board(board_t *board); void print_board(FILE* outfile, board_t *board); void clear_border(int rows, int cols, int *cells); int main(int argc, char* argv[]) { int i; int steps = 0, print_interval = 0; board_t board; FILE* infile; double start_time, end_time; char* args_message = "[ infile | 'random' boardsize seed ] num_steps print_interval"; start_time = get_time(); if (argc < 4) { fprintf(stderr, "usage: %s %s\n", argv[0], args_message); return EXIT_FAILURE; } if (strcmp(argv[1], "random") != 0) { infile = fopen(argv[1], "r"); if (infile == NULL) { fprintf(stderr, "unable to open input file %s\n", argv[1]); return EXIT_FAILURE; } steps = atoi(argv[2]); print_interval = atoi(argv[3]); if ((steps <= 0) || (print_interval <= 0)) { fprintf(stderr, "usage: %s %s\n", argv[0], args_message); return EXIT_FAILURE; } if (read_board(infile, &board) != 0) return EXIT_FAILURE; fclose(infile); } else { int size = 0; int seed = 0; if (argc < 6) { fprintf(stderr, "usage: %s %s\n", argv[0], args_message); return EXIT_FAILURE; } size = atoi(argv[2]); seed = atoi(argv[3]); steps = atoi(argv[4]); print_interval = atoi(argv[5]); if ((steps <= 0) || (print_interval <= 0) || (size <= 0) || (seed <= 0)) { fprintf(stderr, "usage: %s %s\n", argv[0], args_message); return EXIT_FAILURE; } if (random_board(size, seed, &board) != 0) return EXIT_FAILURE; } fprintf(stdout, "Initial board\n\n"); print_board(stdout, &board); fprintf(stdout, "\n\n"); for (i = 0; i < steps; ++i) { update_board(&board); if (((i+1) % print_interval) == 0) { fprintf(stdout, "Board after step %d\n\n", i+1); print_board(stdout, &board); fprintf(stdout, "\n\n"); } } end_time = get_time(); /* writes this to standard error so it can be easily separated from * rest of output (which could be long) */ fprintf(stderr, "\n\nTotal time %g\n", end_time - start_time); fprintf(stderr, "(Board size %d, %d steps, print interval %d)\n\n", board.size, steps, print_interval); return EXIT_SUCCESS; } /* * sets unused "edge" cells to 0 */ void clear_border(int rows, int cols, int *cells) { int r, c; for (c = 0; c < cols+2; ++c) { cells[cell_index(0, c, cols)] = 0; cells[cell_index(rows+1, c, cols)] = 0; } for (r = 0; r < rows+2; ++r) { cells[cell_index(r, 0, cols)] = 0; cells[cell_index(r, cols+1, cols)] = 0; } } /* * reads initial configuration from infile. * returns 0 if all is well, otherwise prints error message and returns * a non-zero value. */ int read_board(FILE* infile, board_t *board) { int i, j, temp; if (fscanf(infile, "%d", &(board->size)) != 1) { fprintf(stderr, "unable to read size of board\n"); return 1; } board->cells = malloc(((board->size)+2)*((board->size)+2)*sizeof(int)); board->new_cells = malloc(((board->size)+2)*((board->size)+2)*sizeof(int)); if ((board->cells == NULL) || (board->new_cells == NULL)) { fprintf(stderr, "unable to allocate space for board of size %d\n", (board->size)); return 2; } for (i = 1; i <= board->size; ++i) { for (j = 1; j <= board->size; ++j) { if (fscanf(infile, "%d", &temp) != 1) { fprintf(stderr, "unable to read values for board\n"); return 1; } if ((temp == 0) || (temp == 1)) board->cells[cell_index(i, j, board->size)] = temp; else { fprintf(stderr, "unable to read values for board\n"); return 1; } } } clear_border(board->size, board->size, board->cells); clear_border(board->size, board->size, board->new_cells); return 0; } /* * generates random board configuration for given size and seed. * returns 0 if all is well, otherwise prints error message and returns * a non-zero value. */ int random_board(int size, int seed, board_t *board) { int i, j; board->size = size; srandom(seed); board->cells = malloc(((board->size)+2)*((board->size)+2)*sizeof(int)); board->new_cells = malloc(((board->size)+2)*((board->size)+2)*sizeof(int)); if ((board->cells == NULL) || (board->new_cells == NULL)) { fprintf(stderr, "unable to allocate space for board of size %d\n", (board->size)); return 2; } for (i = 1; i <= board->size; ++i) { for (j = 1; j <= board->size; ++j) { board->cells[cell_index(i, j, board->size)] = (random() < (RAND_MAX/2)) ? 0 : 1; } } clear_border(board->size, board->size, board->cells); clear_border(board->size, board->size, board->new_cells); return 0; } /* * updates board configuration (uses values in cells to compute values in * new_cells, then swaps pointers to "copy" from new_cells to cells). */ void update_board(board_t *board) { /* YOUR CODE GOES HERE */ } /* * prints current board configuration. */ void print_board(FILE* outfile, board_t *board) { int i, j; for (i = 1; i <= board->size; ++i) { for (j = 1; j <= board->size; ++j) { if (board->cells[cell_index(i, j, board->size)] == 0) fprintf(outfile, ". "); else fprintf(outfile, "1 "); } fprintf(outfile, "\n"); } }