conway.c (4571B)
1 #define _GNU_SOURCE 1 2 3 #include <assert.h> 4 #include <inttypes.h> 5 #include <stdint.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <time.h> 10 11 #define BOARD_SIZE 64 12 13 #define NEIGHBOURS 8 14 static int const neighbour_dx[NEIGHBOURS] = { -1, 0, +1, -1, +1, -1, 0, +1 }; 15 static int const neighbour_dy[NEIGHBOURS] = { -1, -1, -1, 0, 0, +1, +1, +1 }; 16 17 #define LIMIT_LONELY 2 18 #define LIMIT_CROWDED 4 19 20 enum cell_state { 21 CELL_DEAD, 22 CELL_ALIVE, 23 }; 24 25 struct cell { 26 enum cell_state state; 27 }; 28 29 struct board { 30 struct cell *buf; 31 size_t width, height; 32 }; 33 34 static inline struct cell * 35 board_cell(struct board *board, size_t x, size_t y) 36 { 37 if (0 <= x && x < board->width && 0 <= y && y < board->height) 38 return &board->buf[(y * board->width) + x]; 39 40 return NULL; 41 } 42 43 void 44 board_init(struct board *board, size_t width, size_t height) 45 { 46 board->buf = malloc(width * height * sizeof *board->buf); 47 assert(board->buf); 48 49 board->width = width; 50 board->height = height; 51 } 52 53 void 54 board_reset(struct board *board) 55 { 56 memset(board->buf, 0, board->width * board->height * sizeof *board->buf); 57 } 58 59 void 60 board_scramble(struct board *board) 61 { 62 for (size_t j = 0; j < board->height; j++) { 63 for (size_t i = 0; i < board->width; i++) { 64 struct cell *cell = board_cell(board, i, j); 65 cell->state = (random() % 2) ? CELL_ALIVE : CELL_DEAD; 66 } 67 } 68 } 69 70 void 71 board_copy(struct board const *restrict src, struct board *restrict dst) 72 { 73 assert(src->width == dst->width); 74 assert(src->height == dst->height); 75 76 memcpy(dst->buf, src->buf, src->width * src->height * sizeof *src->buf); 77 } 78 79 int 80 board_cmp(struct board const *restrict board, struct board const *restrict copy) 81 { 82 assert(board->width == copy->width); 83 assert(board->height == copy->height); 84 85 return memcmp(board->buf, copy->buf, board->width * board->height * sizeof *board->buf); 86 } 87 88 void 89 board_print(struct board *board) 90 { 91 for (size_t j = 0; j < board->height; j++) { 92 for (size_t i = 0; i < board->width; i++) { 93 struct cell *cell = board_cell(board, i, j); 94 95 char repr = (cell->state == CELL_ALIVE) ? 'X' : ' '; 96 printf(" %c ", repr); 97 } 98 printf("\n"); 99 } 100 } 101 102 void 103 board_evaluate_cell(struct board *restrict board, struct board *restrict shadow, 104 size_t x, size_t y) 105 { 106 size_t neighbours = 0; 107 for (size_t i = 0; i < NEIGHBOURS; i++) { 108 size_t px = x + neighbour_dx[i]; 109 size_t py = y + neighbour_dy[i]; 110 111 struct cell *neighbour = board_cell(board, px, py); 112 if (!neighbour) 113 continue; 114 115 if (neighbour->state == CELL_ALIVE) 116 neighbours++; 117 } 118 119 struct cell *save = board_cell(shadow, x, y); 120 121 if (LIMIT_LONELY < neighbours && neighbours < LIMIT_CROWDED) { 122 save->state = CELL_ALIVE; 123 } else { 124 save->state = CELL_DEAD; 125 } 126 } 127 128 void 129 board_evaluate(struct board *restrict board, struct board *restrict shadow) 130 { 131 for (size_t j = 0; j < board->height; j++) { 132 for (size_t i = 0; i < board->width; i++) { 133 board_evaluate_cell(board, shadow, i, j); 134 } 135 } 136 } 137 138 void 139 benchmark(struct board *board, struct board *shadow) 140 { 141 struct board *cur = board, *old = shadow, *tmp; 142 143 struct timespec start, end; 144 clock_gettime(CLOCK_MONOTONIC_RAW, &start); 145 146 size_t iters = 1000000; 147 for (size_t i = 0; i < iters; i++) { 148 board_evaluate(cur, old); 149 150 tmp = cur; 151 cur = old; 152 old = tmp; 153 154 155 } 156 157 clock_gettime(CLOCK_MONOTONIC_RAW, &end); 158 159 uintmax_t mult = 1000000000; 160 uintmax_t nanos = (end.tv_sec - start.tv_sec) * mult + (end.tv_nsec - start.tv_nsec); 161 162 printf("%zu iters in %" PRIuMAX " nsec: %" PRIuMAX " iters/sec\n", 163 iters, nanos, (iters * mult) / nanos); 164 } 165 166 void 167 display(struct board *board, struct board *shadow) 168 { 169 struct board *cur = board, *old = shadow, *tmp; 170 171 uintmax_t delay = 250 * 1000000; 172 173 size_t iter = 0; 174 while (board_cmp(cur, old)) { 175 board_evaluate(cur, old); 176 177 printf("iteration: %zu\n", iter++); 178 board_print(cur); 179 printf("\n"); 180 181 /* swap around current board with shadow board */ 182 tmp = cur; 183 cur = old; 184 old = tmp; 185 186 struct timespec time = { 187 .tv_sec = delay / 1000000000, 188 .tv_nsec = delay % 1000000000, 189 }; 190 191 nanosleep(&time, NULL); 192 } 193 } 194 195 int 196 main(void) 197 { 198 srandom(time(NULL)); 199 200 const size_t width = BOARD_SIZE; 201 const size_t height = BOARD_SIZE; 202 203 struct board board, shadow; 204 205 board_init(&board, width, height); 206 board_init(&shadow, width, height); 207 208 board_scramble(&board); 209 210 #if 0 211 printf("initial\n=====================================\n"); 212 board_print(&board); 213 printf("\n"); 214 #endif 215 216 // display(&board, &shadow); 217 benchmark(&board, &shadow); 218 219 #if 0 220 printf("final\n=====================================\n"); 221 board_print(&board); 222 printf("\n"); 223 #endif 224 225 226 }