#include #include #include #define LIVE_MIN 3 #define LIVE_MAX 3 #define STAY_ALIVE_MIN 2 #define STAY_ALIVE_MAX 3 #define FILE_DEAD '0' #define FILE_ALIVE '1' #define PRNT_DEAD ' ' #define PRNT_ALIVE 'Q' #define CLR_SCR_LINES 0 /* 0.5s sleep*/ /* #define SLEEP {0, 100000000} */ #define MAP_CELL_TYPE int /*typedef MAP_CELL_TYPE* Map;*/ typedef struct { MAP_CELL_TYPE* map; int width; int height; char live_char; char dead_char; } Map; typedef enum { DEAD, ALIVE } State; typedef enum { SUCCESS, ERROR } Result; State live(int neighbours, State state); Result load_map(Map*, FILE*); State next_state(Map* map); int count_neighbours(Map map, int width, int height); void print_map(Map); void destroy_map(Map); State get_state(char file_state); MAP_CELL_TYPE* getxy(Map, int width, int height); MAP_CELL_TYPE getxy_value(Map, int width, int height); int main(int argc, char *argv[]) { int i, STEPS; double SLEEP_TIME; FILE * file; Map map; map.live_char = PRNT_ALIVE; map.dead_char = PRNT_DEAD; map.width = 0; map.height = 0; map.map = NULL; struct timespec slp; if (argc != 4) { fprintf(stderr, "Usage: life \n"); return 1; } file = fopen(argv[1], "r"); if (file == NULL) { fprintf(stderr, "Could not open %s.\n", argv[1]); return 1; } STEPS = atoi(argv[2]); SLEEP_TIME = atof(argv[3]); slp.tv_sec = (long)SLEEP_TIME; slp.tv_nsec = (SLEEP_TIME-slp.tv_sec)*1e9; if (load_map(&map, file) == ERROR) { /* destroy_map(map); */ fclose(file); return 1; } i=0; while (1) { print_map(map); if (DEAD == next_state(&map)) { print_map(map); break; } if (STEPS && ++i>STEPS) break; nanosleep(&slp, NULL); } fclose(file); destroy_map(map); return 0; } State live(int neighbours, State state) { switch (state) { case DEAD: if (neighbours >= LIVE_MIN && neighbours <= LIVE_MAX) return ALIVE; return DEAD; case ALIVE: if (neighbours >= STAY_ALIVE_MIN && neighbours <= STAY_ALIVE_MAX) return ALIVE; return DEAD; } return DEAD; /* just in case.. */ } Result load_map(Map* map, FILE* file) { int width, height, c, tmp; map->map = NULL; if (file == NULL) return ERROR; width=0; c = fgetc(file); while (c!='\n' && c!=EOF) { ++width; c = fgetc(file); } map->width = width; fseek(file, 0, SEEK_SET); height = 0; tmp = -1; do { ++tmp; c = fgetc(file); if (c == '\n' || c == EOF) { ++height; /*printf("width: %d, tmp: %d\n", width, tmp);*/ if (tmp != width) { --height; break; } if (c == EOF) { break; } tmp = -1; } if (tmp > width) { /* TODO: check if needed */ break; } } while (c!=EOF); map->height = height; printf("PUZZLE: %dx%d\n", map->width, map->height); map->map = malloc(sizeof(MAP_CELL_TYPE)*height*width); if (map->map == NULL) return ERROR; fseek(file, 0, SEEK_SET); for (height=0; height < map->height; ++height) { for (width=0; width < map->width; ++width) { *getxy(*map, width, height) = get_state(fgetc(file)); /* map[height*map->width + width] = get_state(fgetc(file)); */ } if (fgetc(file) != '\n') fprintf(stderr, "map[%d][%d]!=\\n\n", height, width); } return SUCCESS; } State next_state(Map* map) { int width, height; State main_state = DEAD; Map map_tmp; /* make a temp map */ map_tmp.map = map->map; /* swap maps */ map_tmp.width = map->width; map_tmp.height = map->height; map_tmp.live_char = map->live_char; map_tmp.dead_char = map->dead_char; map->map = malloc(sizeof(MAP_CELL_TYPE) * map->width * map->height); if (map->map == NULL) { fprintf(stderr, "Unable to allocate memory(next_state)\n"); map->map = map_tmp.map; return DEAD; } for (height=0; height < map->height; ++height) { for (width=0; width < map->width; ++width) { if (live(count_neighbours(map_tmp,width,height), *getxy(map_tmp,width, height)) == ALIVE) { main_state = ALIVE; *getxy(*map,width,height) = ALIVE; } else { *getxy(*map,width,height) = DEAD; } } } free(map_tmp.map); return main_state; } int count_neighbours(Map map, int width, int height) { int s=0; s+=(getxy_value(map,width-1, height-1)==ALIVE?1:0); s+=(getxy_value(map,width+0, height-1)==ALIVE?1:0); s+=(getxy_value(map,width+1, height-1)==ALIVE?1:0); s+=(getxy_value(map,width-1, height+0)==ALIVE?1:0); s+=(getxy_value(map,width+1, height+0)==ALIVE?1:0); s+=(getxy_value(map,width-1, height+1)==ALIVE?1:0); s+=(getxy_value(map,width+0, height+1)==ALIVE?1:0); s+=(getxy_value(map,width+1, height+1)==ALIVE?1:0); return s; } void print_map(Map map) { int width, height; for (height=CLR_SCR_LINES;height; --height) printf("\n"); printf("----%dx%d----\n", map.width, map.height); for (height=0; height < map.height; ++height) { for (width=0; width < map.width; ++width) { if (*getxy(map, width, height) == DEAD) printf("%c", map.dead_char); else printf("%c", map.live_char); /* map[height*map.width + width] = get_state(fgetc(file)); */ } printf("\n"); } } void destroy_map(Map map) { if (map.map == NULL) return; free(map.map); } State get_state(char file_state) { if (file_state == FILE_DEAD) return DEAD; else return ALIVE; } MAP_CELL_TYPE* getxy(Map map, int width, int height) { return &(map.map[height*map.width + width]); } MAP_CELL_TYPE getxy_value(Map map, int width, int height) { if (width < 0 || height < 0 || width >= map.width || height >= map.height) return 0; else return *getxy(map,width,height); }