Last active
December 16, 2016 23:34
-
-
Save lecram/72725f29eadf356da3074d75c324c29e to your computer and use it in GitHub Desktop.
Game of Life in terminal using braille.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _POSIX_C_SOURCE 200809L | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include <assert.h> | |
#include <locale.h> | |
#include <time.h> | |
#include <poll.h> | |
#include <signal.h> | |
#define CW 80 | |
#define CH 24 | |
#define PW (CW * 2) | |
#define PH (CH * 4) | |
typedef struct Surf { | |
int pw, ph; | |
size_t stride; | |
uint8_t data[]; | |
} Surf; | |
typedef struct Screen { | |
int cw, ch; | |
Surf *cur, *old; | |
} Screen; | |
#define PGET(S, X, Y) \ | |
((S)->data[(S)->stride * (Y) + (X) / 8] & (1 << (7 - ((X) & 7)))) | |
#define PSET(S, X, Y) \ | |
((S)->data[(S)->stride * (Y) + (X) / 8] |= (1 << (7 - ((X) & 7)))) | |
#define PRST(S, X, Y) \ | |
((S)->data[(S)->stride * (Y) + (X) / 8] &= ~(1 << (7 - ((X) & 7)))) | |
static volatile sig_atomic_t running; | |
Surf * | |
new_surf(int pw, int ph) | |
{ | |
Surf *surf; | |
size_t stride; | |
stride = (pw >> 3) + !!(pw & 7); | |
surf = calloc(1, sizeof(*surf) + stride * ph * sizeof(surf->data[0])); | |
if (surf) { | |
surf->pw = pw; | |
surf->ph = ph; | |
surf->stride = stride; | |
} | |
return surf; | |
} | |
Screen * | |
new_screen(int cw, int ch) | |
{ | |
Screen *screen; | |
int pw, ph; | |
pw = cw * 2; | |
ph = ch * 4; | |
screen = malloc(sizeof(*screen)); | |
if (screen) { | |
screen->cw = cw; | |
screen->ch = ch; | |
screen->cur = new_surf(pw, ph); | |
screen->old = new_surf(pw, ph); | |
memset(screen->old->data, 0xFF, screen->old->stride * screen->old->ph); | |
} | |
return screen; | |
} | |
void | |
flip(Screen *screen) | |
{ | |
int cx, cy; | |
int px, py; | |
uint8_t oldc, newc; | |
uint8_t mask[8] = {0x01, 0x08, 0x02, 0x10, 0x04, 0x20, 0x40, 0x80}; | |
uint8_t mb[4] = {0xE2, 0x00, 0x00, 0x00}; | |
int i; | |
Surf *tmp; | |
for (cy = 0; cy < screen->ch; cy++) { | |
for (cx = 0; cx < screen->cw; cx++) { | |
oldc = newc = 0x00; | |
i = 0; | |
for (py = cy * 4; py < (cy+1) * 4; py++) { | |
for (px = cx * 2; px < (cx+1) * 2; px++) { | |
if (PGET(screen->old, px, py)) | |
oldc += mask[i]; | |
if (PGET(screen->cur, px, py)) | |
newc += mask[i]; | |
i++; | |
} | |
} | |
if (newc != oldc) { | |
mb[1] = 0xA0 | (newc >> 6); | |
mb[2] = (newc & 0xBF) | 0x80; | |
printf("\x1B[%d;%dH%s", cy + 1, cx + 1, mb); | |
} | |
} | |
} | |
fflush(stdout); | |
tmp = screen->old; | |
screen->old = screen->cur; | |
screen->cur = tmp; | |
} | |
void | |
free_screen(Screen *screen) | |
{ | |
free(screen->cur); | |
free(screen->old); | |
free(screen); | |
} | |
void | |
random_surf(Surf *surf) | |
{ | |
unsigned i, n; | |
uint8_t c; | |
for (i = 0; i < surf->stride * surf->ph; i++) { | |
c = 0xFF; | |
for (n = 0; n < 3; n++) | |
c &= rand() % 0x100; | |
surf->data[i] = c; | |
} | |
} | |
void | |
update(Screen *screen) | |
{ | |
int x, y; | |
int c, n; | |
for (y = 0; y < PH; y++) { | |
for (x = 0; x < PW; x++) { | |
c = PGET(screen->old, x, y); | |
n = !!PGET(screen->old, (PW+x-1) % PW, (PH+y-1) % PH) | |
+ !!PGET(screen->old, (PW+x ) % PW, (PH+y-1) % PH) | |
+ !!PGET(screen->old, (PW+x+1) % PW, (PH+y-1) % PH) | |
+ !!PGET(screen->old, (PW+x-1) % PW, (PH+y ) % PH) | |
+ !!PGET(screen->old, (PW+x+1) % PW, (PH+y ) % PH) | |
+ !!PGET(screen->old, (PW+x-1) % PW, (PH+y+1) % PH) | |
+ !!PGET(screen->old, (PW+x ) % PW, (PH+y+1) % PH) | |
+ !!PGET(screen->old, (PW+x+1) % PW, (PH+y+1) % PH); | |
if (c) { | |
if (n < 2 || n > 3) | |
PRST(screen->cur, x, y); | |
else | |
PSET(screen->cur, x, y); | |
} else { | |
if (n == 3) | |
PSET(screen->cur, x, y); | |
else | |
PRST(screen->cur, x, y); | |
} | |
} | |
} | |
} | |
void | |
handle_int(int signum) | |
{ | |
(void) signum; | |
running = 0; | |
} | |
int | |
main() | |
{ | |
Screen *scr; | |
struct sigaction sa; | |
srand(time(NULL)); | |
memset(&sa, 0, sizeof(sa)); | |
sa.sa_handler = handle_int; | |
sigaction(SIGINT, &sa, NULL); | |
printf("\x1B[?25l"); | |
setlocale(LC_ALL, ""); | |
scr = new_screen(CW, CH); | |
flip(scr); | |
random_surf(scr->cur); | |
running = 1; | |
while (running) { | |
flip(scr); | |
update(scr); | |
poll(NULL, 0, 10); | |
} | |
printf("\x1B[?25h\x1B[%d;1H\n", CH); | |
free_screen(scr); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment