conway/conway.c

131 lines
4.4 KiB
C
Raw Normal View History

2019-03-18 16:05:51 -07:00
// A console conway's game of life program by Bruce Hill
// Released under the MIT license, see LICENSE for details.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <termbox.h>
#include <unistd.h>
2019-03-18 16:44:35 -07:00
#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}};
2019-03-18 17:20:07 -07:00
static int W, H, DEAD = 0, ALIVE = 8;
2019-03-18 16:05:51 -07:00
2019-03-18 16:07:40 -07:00
static void update(const char *cells, char *future_cells)
2019-03-18 16:05:51 -07:00
{
for (int y = 0; y < H; y++) {
for (int x = 0; x < W; x++) {
2019-03-18 16:44:35 -07:00
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)) {
2019-03-18 17:20:07 -07:00
tb_change_cell(2*x, y, ' ', 0, CELL(future_cells, x, y) ? ALIVE : DEAD);
tb_change_cell(2*x+1, y, ' ', 0, CELL(future_cells, x, y) ? ALIVE : DEAD);
2019-03-18 16:05:51 -07:00
}
}
}
}
int main(int argc, char **argv) {
int randomize = 1;
2019-03-18 16:05:51 -07:00
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");
2019-03-18 16:05:51 -07:00
return 0;
} else if (strncmp(argv[i], "-B", 2) == 0) {
2019-03-18 16:44:35 -07:00
memset(rules[0], 0, sizeof(rules[0]));
2019-03-18 16:05:51 -07:00
for (char *p = &argv[i][2]; *p; p++) {
if ('0' <= *p && *p <= '8')
2019-03-18 16:44:35 -07:00
rules[0][*p - '0'] = 1;
2019-03-18 16:05:51 -07:00
}
} else if (strncmp(argv[i], "-S", 2) == 0) {
2019-03-18 16:44:35 -07:00
memset(rules[1], 0, sizeof(rules[1]));
2019-03-18 16:05:51 -07:00
for (char *p = &argv[i][2]; *p; p++) {
if ('0' <= *p && *p <= '8')
2019-03-18 16:44:35 -07:00
rules[1][*p - '0'] = 1;
2019-03-18 16:05:51 -07:00
}
2019-03-18 17:20:07 -07:00
} else if (strncmp(argv[i], "-A", 2) == 0) {
ALIVE = atoi(&argv[i][2]);
if (ALIVE & ~0xFF) {
fprintf(stderr, "Colors must be between 0-255\n");
return 1;
}
} else if (strncmp(argv[i], "-D", 2) == 0) {
DEAD = atoi(&argv[i][2]);
if (DEAD & ~0xFF) {
fprintf(stderr, "Colors must be between 0-255\n");
return 1;
}
} else if (strcmp(argv[i], "-Z") == 0) {
randomize = 0;
2019-03-18 16:05:51 -07:00
}
}
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);
2019-03-18 17:20:07 -07:00
tb_select_output_mode(TB_OUTPUT_256);
2019-03-18 16:05:51 -07:00
2019-03-18 16:11:18 -07:00
// Cells are 2 characters wide so they look square
2019-03-18 16:07:40 -07:00
char *buffers[2];
2019-03-18 16:44:35 -07:00
int flipflop = 0;
2019-03-18 16:05:51 -07:00
resize:
2019-03-18 16:44:35 -07:00
W = tb_width()/2, H = tb_height();
2019-03-18 16:07:40 -07:00
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;
2019-03-18 16:05:51 -07:00
2019-03-18 16:56:32 -07:00
int draw_mode = 1, paused = 0;
2019-03-18 17:20:07 -07:00
tb_set_clear_attributes(ALIVE, DEAD);
2019-03-18 16:05:51 -07:00
tb_clear();
while (1) {
2019-03-18 16:56:32 -07:00
if (!paused) {
update(buffers[flipflop], buffers[!flipflop]);
flipflop = !flipflop;
}
2019-03-18 16:44:35 -07:00
present:
2019-03-18 16:05:51 -07:00
tb_present();
usleep(60000);
struct tb_event ev;
2019-03-18 16:44:35 -07:00
int drew = 0;
2019-03-18 16:05:51 -07:00
while (tb_peek_event(&ev, 0)) {
switch (ev.type) {
case TB_EVENT_RESIZE:
2019-03-18 16:44:35 -07:00
free(buffers[0]);
free(buffers[1]);
2019-03-18 16:05:51 -07:00
goto resize;
case TB_EVENT_KEY:
2019-03-18 16:44:35 -07:00
if (ev.key == TB_KEY_ESC && tb_peek_event(&ev, 50) == 0)
goto done;
else if (ev.ch == 'q')
goto done;
2019-03-18 16:56:32 -07:00
else if (ev.ch == 'p')
paused = !paused;
2019-03-18 16:44:35 -07:00
else if (ev.key == TB_KEY_SPACE)
draw_mode = !draw_mode;
2019-03-18 16:05:51 -07:00
break;
case TB_EVENT_MOUSE:
2019-03-18 16:44:35 -07:00
CELL(buffers[flipflop], ev.x/2, ev.y) = draw_mode;
2019-03-18 17:20:07 -07:00
tb_change_cell(2*(ev.x/2), ev.y, ' ', 0, draw_mode ? ALIVE : DEAD);
tb_change_cell(2*(ev.x/2)+1, ev.y, ' ', 0, draw_mode ? ALIVE : DEAD);
2019-03-18 16:44:35 -07:00
drew = 1;
2019-03-18 16:05:51 -07:00
break;
}
}
2019-03-18 16:44:35 -07:00
if (drew) goto present;
2019-03-18 16:05:51 -07:00
}
done:
tb_shutdown();
return 0;
}