conway

conway.git
git clone git://git.lenczewski.org/conway.git
Log | Files | Refs | README

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 }