mirror of
https://codeberg.org/emilwilliams/life
synced 2024-11-21 19:44:21 -05:00
On the third day...
This commit is contained in:
commit
947ff4e765
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
life
|
334
life.c
Normal file
334
life.c
Normal file
@ -0,0 +1,334 @@
|
||||
/* @BAKE \
|
||||
cc -O2 -Wshadow -Wall -Wextra -Wpedantic -g -fsanitize=address,undefined,bounds \
|
||||
$@ -o $* -lm -DNDEBUG $+ @STOP */
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DELC static inline
|
||||
|
||||
/* nearness mask, life mask */
|
||||
#define LIFE_NEAR_MASK ((1 << 4) - 1)
|
||||
#define LIFE_MASK (32)
|
||||
/* life nearness function */
|
||||
#define life_near life_near_lim
|
||||
|
||||
enum {
|
||||
LIFE_NONE,
|
||||
LIFE_ALIVE,
|
||||
LIFE_DEAD
|
||||
};
|
||||
|
||||
char symbol [] = " O.";
|
||||
|
||||
/* tty */
|
||||
|
||||
#define CSI "\033["
|
||||
|
||||
DELC void clear (void) { printf (CSI "3J"); }
|
||||
|
||||
DELC void move_up (int n) { printf (CSI "%dF", n); }
|
||||
|
||||
DELC void move_down (int n) { printf (CSI "%dE", n); }
|
||||
|
||||
DELC void move_back (int n) { printf (CSI "%dD", n); }
|
||||
|
||||
DELC void move_forward (int n) { printf (CSI "%dC", n); }
|
||||
|
||||
DELC void color (int fg, int bg) { printf (bg != -1 ? CSI "%d;%dm" : CSI "%dm", fg, bg); }
|
||||
|
||||
/* board */
|
||||
|
||||
typedef struct {
|
||||
int w, h;
|
||||
int ** g;
|
||||
} board_t;
|
||||
|
||||
DELC board_t * board_alloc (int w, int h) {
|
||||
board_t * b = malloc (sizeof (board_t));
|
||||
b->w = w;
|
||||
b->h = h;
|
||||
b->g = malloc (sizeof (int *) * h);
|
||||
for (int i = 0; i < h; ++i) {
|
||||
b->g [i] = malloc (sizeof (int) * w);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
DELC void board_free (board_t * b) {
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
free (b->g [i]);
|
||||
}
|
||||
free (b->g);
|
||||
free (b);
|
||||
}
|
||||
|
||||
DELC void board_set (board_t * b, int v) {
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
for (int f = 0; f < b->w; ++f) {
|
||||
b->g [i] [f] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DELC void board_randomize (board_t * b, int v) {
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
for (int f = 0; f < b->w; ++f) {
|
||||
b->g [i] [f] = rand () % v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DELC void board_eq_filter (board_t * b, int v) {
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
for (int f = 0; f < b->w; ++f) {
|
||||
b->g [i] [f] = b->g [i] [f] == v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DELC void board_copy_to (board_t * dest, board_t * src, int x, int y) {
|
||||
for (int i = 0; i < src->h; ++i) {
|
||||
for (int f = 0; f < src->w; ++f) {
|
||||
dest->g [y + i] [x + f] = src->g [i] [f];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DELC void board_copy (board_t * dest, board_t * src) {
|
||||
board_copy_to (dest, src, 0, 0);
|
||||
}
|
||||
|
||||
/* TODO: dup without copy */
|
||||
DELC board_t * board_dup (board_t * b) {
|
||||
board_t * a = board_alloc (b->w, b->h);
|
||||
board_copy (a, b);
|
||||
return a;
|
||||
}
|
||||
|
||||
#if 0
|
||||
DELC int board_cmp (board_t * a, board_t * b) {
|
||||
int s = 0;
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
for (int f = 0; f < b->w; ++f) {
|
||||
s += a->g [i] [f] != b->g [i] [f];
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
DELC void board_invert (board_t * b) {
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
for (int f = 0; f < b->w; ++f) {
|
||||
b->g [i] [f] = !(b->g [i] [f] == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Must place the cursor at the top left of the already printed board */
|
||||
DELC void board_highlight (board_t * b, int fg, int x, int y) {
|
||||
if (y) { move_down (y); }
|
||||
if (x) { move_forward (x*2); }
|
||||
|
||||
color (fg, -1);
|
||||
printf ("%c", symbol [b->g [y] [x]]);
|
||||
color (0, -1);
|
||||
|
||||
if (x) { move_back (x*2); }
|
||||
if (y) { move_up (y); }
|
||||
}
|
||||
|
||||
DELC void board_print (board_t * b) {
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
for (int f = 0; f < b->w; ++f) {
|
||||
printf (f + 1 != b->w ? "%c " : "%c\n", symbol [(b->g [i] [f])]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DELC board_t * board_alloc_text (char * s) {
|
||||
int r = atoi (s);
|
||||
return board_alloc (r, r);
|
||||
}
|
||||
|
||||
/* life */
|
||||
|
||||
#if 0
|
||||
DELC int life_near_loop (board_t * b, int x, int y) {
|
||||
int ** g = b->g, w = b->w, h = b->h;
|
||||
|
||||
int
|
||||
ty = (y-1) % h, lx = (x-1) % w,
|
||||
cy = ( y) % h, cx = ( x) % w,
|
||||
by = (y+1) % h, rx = (x+1) % w;
|
||||
|
||||
return
|
||||
g [ty] [lx] + g [ty] [cx] + g [ty] [rx]
|
||||
+ g [cy] [lx] + (g [cy] [cx] << 5) + g [cy] [rx]
|
||||
+ g [by] [lx] + g [by] [cx] + g [by] [rx];
|
||||
}
|
||||
|
||||
DELC int life_near_lim (board_t * b, int x, int y) {
|
||||
int ** g = b->g, w = b->w, h = b->h;
|
||||
|
||||
int
|
||||
ty = (y-1), lx = (x-1),
|
||||
cy = ( y), cx = ( x),
|
||||
by = (y+1), rx = (x+1),
|
||||
s = g [cy] [cx] << 5;
|
||||
|
||||
if (ty < h) {
|
||||
s += lx < w ? g [ty] [lx] : 0;
|
||||
s += g [ty] [cx] ;
|
||||
s += rx >= 0 ? g [ty] [rx] : 0;
|
||||
}
|
||||
|
||||
s += lx < w ? g [cy] [lx] : 0;
|
||||
s += rx >= 0 ? g [cy] [rx] : 0;
|
||||
|
||||
if (by >= 0) {
|
||||
s += lx < w ? g [by] [lx] : 0;
|
||||
s += g [by] [cx] ;
|
||||
s += rx >= 0 ? g [by] [rx] : 0;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
DELC int life_near_lim (board_t * b, int x, int y) {
|
||||
int ** g = b->g, w = b->w, h = b->h, s = 0, i, f, yi, xf;
|
||||
for (i = -1; i < 2; ++i) {
|
||||
for (f = -1; f < 2; ++f) {
|
||||
if (i == 0 && f == 0)
|
||||
{ s += g [y] [x] * LIFE_MASK; continue; }
|
||||
yi = y + i;
|
||||
xf = x + f;
|
||||
if (yi >= 0 && yi < h
|
||||
&& xf >= 0 && xf < w)
|
||||
{ s += g [yi] [xf] == 1; }
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
DELC int life_pop (board_t * b) {
|
||||
int s = 0;
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
for (int f = 0; f < b->w; ++f) {
|
||||
s += b->g [i] [f] == LIFE_ALIVE;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
DELC void life_update (board_t * a, board_t * b) {
|
||||
int near;
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
for (int f = 0; f < b->w; ++f) {
|
||||
near = life_near (b, f, i);
|
||||
if ((near & LIFE_NEAR_MASK) == 3) { a->g [i] [f] = LIFE_ALIVE; }
|
||||
else if ((near & LIFE_MASK) && (near & LIFE_NEAR_MASK) < 2) { a->g [i] [f] = LIFE_DEAD; }
|
||||
else if ((near & LIFE_MASK) && (near & LIFE_NEAR_MASK) > 3) { a->g [i] [f] = LIFE_DEAD; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
DELC void life_update (board_t * a, board_t * b) {
|
||||
int near, me, ** g = a->g;
|
||||
for (int i = 0; i < b->h; ++i) {
|
||||
for (int f = 0; f < b->w; ++f) {
|
||||
near = life_near (b, f, i);
|
||||
me = near & LIFE_ALIVE;
|
||||
near &= LIFE_NEAR_MASK;
|
||||
g [i] [f] =
|
||||
(near == 3)
|
||||
+ ( (me && (near < 2))
|
||||
|| (me && (near > 3))) * LIFE_DEAD;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
DELC void life (board_t * b, int step, int wait) {
|
||||
printf (
|
||||
"rect %d:%d\n"
|
||||
"step %d\n"
|
||||
"wait sec / %d\n\n",
|
||||
b->w, b->h,
|
||||
step,
|
||||
wait);
|
||||
|
||||
wait = 1e6 / wait;
|
||||
|
||||
board_t * a = board_dup (b);
|
||||
|
||||
int gen = 1;
|
||||
|
||||
while (step) {
|
||||
board_print (b);
|
||||
|
||||
printf ("\npop: %d\ngen: %d\n", life_pop (b), gen);
|
||||
|
||||
move_up (b->h + 3);
|
||||
|
||||
life_update (a, b);
|
||||
board_copy (b, a);
|
||||
|
||||
usleep (wait);
|
||||
--step;
|
||||
++gen;
|
||||
};
|
||||
board_free (a);
|
||||
|
||||
move_down (b->h + 3);
|
||||
|
||||
printf ("\nEnd of this life.\n");
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
DELC void life_debug_near (board_t * b, int w, int h) {
|
||||
board_print (b);
|
||||
move_up (b->h);
|
||||
board_highlight (b, 31, w, h);
|
||||
move_down (b->h);
|
||||
int near = life_near (b, w, h);
|
||||
printf ("%s near %d,%d: %d\n", near & LIFE_MASK ? "alive" : "dead", w, h, near & LIFE_NEAR_MASK);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main (int argc, char ** argv) {
|
||||
srand (time (NULL));
|
||||
|
||||
if ( argc >= 2
|
||||
&& (strcmp (argv [1], "-h") == 0
|
||||
|| strcmp (argv [1], "--help") == 0)) {
|
||||
printf ("%s [GRID SIZE] [WAIT BETWEEN EACH STEP=4] [MAX STEP=-1]\n", argv [0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char * rect = argc >= 2 ? argv [1] : "20";
|
||||
board_t * b = board_alloc_text (rect);
|
||||
|
||||
board_randomize (b, 5);
|
||||
board_eq_filter (b, 1);
|
||||
|
||||
int wait = argc >= 3 ? atoi (argv [2]) : 4;
|
||||
int step = argc >= 4 ? atoi (argv [3]) : -1;
|
||||
|
||||
#ifndef NDEBUG
|
||||
life_debug_near (b, 0, 0);
|
||||
#endif
|
||||
|
||||
life (b, step, wait);
|
||||
|
||||
board_free (b);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user