Skip to content

Instantly share code, notes, and snippets.

@madgarden
Created June 14, 2021 01:57
Show Gist options
  • Save madgarden/5de44ff4987bf8e8fceced07b68c9c0b to your computer and use it in GitHub Desktop.
Save madgarden/5de44ff4987bf8e8fceced07b68c9c0b to your computer and use it in GitHub Desktop.
Cellular automata with configurable rules
#include <ctype.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define CELLS_W 40
#define CELLS_H 20
#define RULES 9
enum
{
BORDER_DEAD = 0,
BORDER_LIVE,
BORDER_WRAP
};
static char cells[CELLS_W][CELLS_H];
static char cells_buff[CELLS_W][CELLS_H];
static int rules_survive[RULES];
static int rules_birth[RULES];
static int border_mode = BORDER_WRAP;
static int fill_percent = 50;
static void process_cell(int x, int y)
{
int dx, dy;
int around = 0;
int alive = 0;
int i;
for(dy = -1; dy < 2; dy++)
{
for(dx = -1; dx < 2; dx++)
{
int cellx = dx + x;
int celly = dy + y;
if(!dx && !dy) continue;
if(cellx < 0 || cellx >= CELLS_W)
{
if(border_mode == BORDER_WRAP)
{
cellx = (cellx + CELLS_W) % CELLS_W;
}
else if(border_mode == BORDER_LIVE)
{
around++;
continue;
}
else
{
continue;
}
}
if(celly < 0 || celly >= CELLS_H)
{
if(border_mode == BORDER_WRAP)
{
celly = (celly + CELLS_H) % CELLS_H;
}
else if(border_mode == BORDER_LIVE)
{
around++;
continue;
}
else
{
continue;
}
}
if(cells[cellx][celly])
{
around++;
}
}
}
// Living cells
if(cells[x][y])
{
// Survive
for(i = 0; i < RULES; i++)
{
if(around == rules_survive[i])
{
alive = 1;
break;
}
}
}
// Dead cells
else
{
// Birth
for(i = 0; i < RULES; i++)
{
if(around == rules_birth[i])
{
alive = 1;
break;
}
}
}
cells_buff[x][y] = alive;
}
static void step_cells(void)
{
int x, y;
memset(cells_buff, 0, sizeof(cells_buff));
for(y = 0; y < CELLS_H; y++)
{
for(x = 0; x < CELLS_W; x++)
{
process_cell(x, y);
}
}
memcpy(cells, cells_buff, sizeof(cells));
}
static void reset_random(void)
{
int x, y;
for(y = 0; y < CELLS_H; y++)
{
for(x = 0; x < CELLS_W; x++)
{
cells[x][y] = ((rand() >> 8) % 100) < fill_percent;
}
}
}
static int parse_rules(int argc, char *argv[])
{
int i;
int *rules;
int ok = 0;
for(i = 1; i < argc; i++)
{
char *ptr = argv[i];
int j;
int ch = tolower(*ptr);
if(ch == 'l')
{
border_mode = BORDER_LIVE;
continue;
}
if(ch == 'b')
{
rules = rules_birth;
}
else if(ch == 's')
{
rules = rules_survive;
}
else
{
continue;
}
ptr++;
j = 0;
ok = 1;
memset(rules, -1, sizeof(rules_birth));
while(*ptr && j < RULES)
{
rules[j] = *ptr - '0';
j++;
ptr++;
}
}
return ok;
}
static void print_rules(int steps)
{
int i;
printf("RULES: ");
printf("B");
for(i = 0; i < RULES; i++)
{
if(rules_birth[i] < 0 || rules_birth[i] > 8) break;
printf("%d", rules_birth[i]);
}
printf("/S");
for(i = 0; i < RULES; i++)
{
if(rules_survive[i] < 0 || rules_survive[i] > 8) break;
printf("%d", rules_survive[i]);
}
if(border_mode == BORDER_LIVE)
{
printf(", live border");
}
else if(border_mode == BORDER_WRAP)
{
printf(", wrap border");
}
else
{
printf(", dead border");
}
printf("\nstep %d", steps);
if(!steps)
{
printf(" (random fill %%%d)", fill_percent);
}
printf("\n");
}
int main(int argc, char *argv[])
{
int ch = 0, in;
int x, y;
int steps = 0;
int ok = 0;
memset(rules_survive, -1, sizeof(rules_survive));
memset(rules_birth, -1, sizeof(rules_birth));
if(argc > 1)
{
ok = parse_rules(argc, argv);
}
if(!ok)
{
// Conway default
rules_survive[0] = 2;
rules_survive[1] = 3;
rules_birth[0] = 3;
}
srand(time(NULL));
memset(cells, 0, sizeof(cells));
reset_random();
while(ch != 'q')
{
int chars = 0;
int *rule = NULL;
int changed = 0;
print_rules(steps);
for(y = 0; y < CELLS_H; y++)
{
printf(" ");
for(x = 0; x < CELLS_W; x++)
{
int icon = '.';
if(cells[x][y]) icon = 'O';
putchar(icon);
}
printf("\n");
}
printf("\n(r)eset, (b/s) rule, (q)uit: ");
ch = 0;
while((in = getchar()) != '\n')
{
ch = tolower(in);
if(ch == 'b')
{
rule = rules_birth;
chars = 0;
}
else if(ch == 's')
{
rule = rules_survive;
chars = 0;
}
else if(ch == 'l')
{
border_mode = BORDER_LIVE;
changed = 1;
}
else if(ch == 'd')
{
border_mode = BORDER_DEAD;
changed = 1;
}
else if(ch == 'w')
{
border_mode = BORDER_WRAP;
changed = 1;
}
else if(ch == 'f')
{
unsigned int amount = 0;
while((in = getchar()))
{
int digit = in - '0';
if(digit < 0 || digit > 9) break;
amount *= 10;
amount += digit;
}
ungetc(in, stdin);
if(amount > 100) amount = 100;
fill_percent = amount;
changed = 1;
}
if(rule && chars <= RULES)
{
if(chars == 0)
{
memset(rule, -1, sizeof(rules_birth));
}
else
{
rule[chars - 1] = ch - '0';
}
changed = 1;
}
chars++;
}
printf("\n");
if(!changed)
{
step_cells();
steps++;
}
if(ch == 'r')
{
reset_random();
steps = 0;
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment