mirror of
https://codeberg.org/emilwilliams/life
synced 2024-11-22 03:54:20 -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