// A console conway's game of life program by Bruce Hill // Released under the MIT license, see LICENSE for details. #include #include #include #include #include #define CELL(cells, x, y) cells[((y) % H)*W + ((x) % W)] static char rules[2][9] = {{0,0,0,1,0,0,0,0,0}, {0,0,1,1,0,0,0,0,0}}; static int W, H; static void update(const char *cells, char *future_cells) { for (int y = 0; y < H; y++) { for (int x = 0; x < W; x++) { int neighbors = CELL(cells,x-1,y-1) + CELL(cells,x,y-1) + CELL(cells,x+1,y-1) + CELL(cells,x-1,y) + CELL(cells,x+1,y) + CELL(cells,x-1,y+1) + CELL(cells,x,y+1) + CELL(cells,x+1,y+1); CELL(future_cells, x, y) = rules[CELL(cells, x, y)][neighbors]; if (CELL(future_cells, x, y) != CELL(cells, x, y)) { tb_change_cell(2*x, y, ' ', 0, CELL(future_cells, x, y) ? 8 : 0); tb_change_cell(2*x+1, y, ' ', 0, CELL(future_cells, x, y) ? 8 : 0); } } } } int main(int argc, char **argv) { int randomize = 1; for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--help") == 0) { printf("Conway's Game of Life Viewer\nUsage: conway [-Z] [-S012345678] [-B012345678]\n"); return 0; } else if (strncmp(argv[i], "-B", 2) == 0) { memset(rules[0], 0, sizeof(rules[0])); for (char *p = &argv[i][2]; *p; p++) { if ('0' <= *p && *p <= '8') rules[0][*p - '0'] = 1; } } else if (strncmp(argv[i], "-S", 2) == 0) { memset(rules[1], 0, sizeof(rules[1])); for (char *p = &argv[i][2]; *p; p++) { if ('0' <= *p && *p <= '8') rules[1][*p - '0'] = 1; } } else if (strcmp(argv[i], "-Z") == 0) { randomize = 0; } } int ret = tb_init(); if (ret) { fprintf(stderr, "tb_init() failed with error code %d\n", ret); return 1; } tb_select_input_mode(TB_INPUT_MOUSE); // Cells are 2 characters wide so they look square char *buffers[2]; int flipflop = 0; resize: W = tb_width()/2, H = tb_height(); buffers[0] = calloc(W*H, sizeof(char)); buffers[1] = calloc(W*H, sizeof(char)); if (randomize) for (int x = 0; x < W; x++) for (int y = 0; y < H; y++) CELL(buffers[flipflop], x, y) = random() % 2; int draw_mode = 1; tb_clear(); while (1) { update(buffers[flipflop], buffers[!flipflop]); flipflop = !flipflop; present: tb_present(); usleep(60000); struct tb_event ev; int drew = 0; while (tb_peek_event(&ev, 0)) { switch (ev.type) { case TB_EVENT_RESIZE: free(buffers[0]); free(buffers[1]); goto resize; case TB_EVENT_KEY: if (ev.key == TB_KEY_ESC && tb_peek_event(&ev, 50) == 0) goto done; else if (ev.ch == 'q') goto done; else if (ev.key == TB_KEY_SPACE) draw_mode = !draw_mode; break; case TB_EVENT_MOUSE: CELL(buffers[flipflop], ev.x/2, ev.y) = draw_mode; tb_change_cell(2*(ev.x/2), ev.y, ' ', 0, draw_mode ? 8 : 0); tb_change_cell(2*(ev.x/2)+1, ev.y, ' ', 0, draw_mode ? 8 : 0); drew = 1; break; } } if (drew) goto present; } done: tb_shutdown(); return 0; }