If you are here for the boy band, sorry. This is about mathematics.
Usagi on YouTube (https://www.youtube.com/watch?v=bpdYBsgYF_c) gave me the idea to practice my C skills and play around with code for the Game of Life and different Cellular Automata.
Think of having a petri dish in front of you with something disgusting your dog coughed up, and you watch cells dividing, spreading, and dying under the microscope.
There are very good explanations on the internet about what the Game of Life is and how it relates to Cellular Automata, for example at https://jonmillen.com/1dlife/index.html. I started with the one-dimensional version of it: the survival of a cell is dependent on the state of its direct neighbor cells to the left and to the right. For example, a simple rule is „An alive cell will survive into the next generation if it has 2 or 3 alive neighbors. A dead cell with three alive neighbors will be reborn“. If alive cells are printed on the screen with a symbol or color and the dead cells are not visible anymore, the result are interesting patterns. Most rules create repeating patterns with a visible structure:

In above example, we start with a row of random cells that are either alive or dead. The rule book that was used to define the state of the next cell generation and creates this pattern is
// Rule 1 - Cell stays alive if 2 or 4 live neighbor cells
// Rule 2 - Alive cells dies if 1 or 3 alive neighbor cells
// Rule 3 - Cell reborn if 2 or 3 alive neighbor cells
// Rule 4 - Otherwise cell dies
An alive cell is shown as the symbol „o“, a blank is a dead cell. This rule book (which has number #20) starts seemingly random but ends up always with the same repeating pattern.
If the rule book is slightly modified, we suddenly get a completely different pattern with repeating triangles:

The rule book for above pattern is
// Rule 1 - Cell stays alive if 1 or 2 live neighbor cells
// Rule 2 - Alive cell dies if 3 or 4 alive neighbor cells
// Rule 3 - Cell reborn if 2 or 3 alive neighbor cells
// Rule 4 - Otherwise cell dies
Because the code is so easy to understand and compact, it is fun to modify the rule book and look at the new result.
The best and most comprehensive book about this topic is Stephen Wolfram’s „A New Kind of Science“ (https://www.wolframscience.com/nks/p24–how-do-simple-programs-behave/). He documented all the different patterns and gave them a number. For example, my code 1dlife-30.c is an implementation of his rule 30. Rule 254 in his book creates a very simple pattern out of one alive cell, a triangle:

If the rule book is modified just a little bit, we see triangles appearing inside the big triangle (rule 30):

Modified again, we get the pattern of rule 90. Now, the whole structure is set up of triangles with different sizes:

There is software out there that can do the same but in a prettier package, e.g. the Mathgrapher v2.03 (https://www.mathgrapher.com/cellular-automata-1d-rule/). My code has the advantage that it is short and very easy to understand. It does not even have a function outside of main( ). Also, it is quite portable to other platforms.
To keep it simple, I created the code to print the patterns on the screen of an ANSI terminal. Green characters (cells) on a black background are a must.
At the beginning of the code, the symbols for alive and dead cells are being defined:
#define ALIVE 'o'
#define DEAD ' '
For the current generation of cells and the next one, two one-dimensional byte arrays of length MAXX are defined:
char x[MAXX]; // Current generation
char y[MAXX]; // Next generation
My ANSI terminal has a width of 120 characters, so MAXX is set to 120. If the rule book is asking for the number of alive neighbors, this number is stored in a variable:
unsigned int aliveN; // Number of alive neighbors
For all rules that start with one row of cells in a random state, first the random number function is seeded with current time. Otherwise, the output of rand( ) is not random:
srand((unsigned int) time(NULL));
Next, the current generation of cells is seeded:
x[i] = rand() % 2; // Generate random 0s and 1s
Depending on what the rule book is asking for, the neighbor cells are checked for their status:
aliveN = 0;
if(x[i-2] == ALIVE)
aliveN++;
if(x[i-1] == ALIVE)
aliveN++;
if(x[i+1] == ALIVE)
aliveN++;
if(x[i+2] == ALIVE)
aliveN++;
The rule book itself is a simple test for the status of the current cell x[i] and either the number of alive neighbors or the actual state of a neighbor cell, for example x[i-1] for the left neighbor:
// Rule 1 - Cell stays alive if 2 or 4 live neighbor cells
if(x[i] == ALIVE && (aliveN == 2 || aliveN == 4))
y[i] = ALIVE;
// Rule 2 - Alive cells dies if 1 or 3 alive neighbor cells
else if(x[i] == ALIVE && (aliveN == 1 || aliveN == 3))
y[i] = DEAD;
// Rule 3 - Cell reborn if 2 or 3 alive neighbor cells
else if(x[i] == DEAD && (aliveN == 2 || aliveN == 3))
y[i] = ALIVE;
// Rule 4 - Otherwise cell dies
else
y[i] = DEAD;
Depending on the rule, the next generation cell y[i] is set.
All my coded rules and their snapshots can be found at my GitHub repository jklingel/Game-of-Life: I played around with code for the Game of Life and different Cellular Automata.