import echo::{Context, Cell, contain, prev_cell};
import lygia::generative::random::random2;
// This is an implementation of Conway's Game of Life, the
// classic cellular automata devised by John Conway in 1970:
// <https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life>
//
// Selecting text will spawn cells! From there, each
// generation of cells follows some simple rules:
//
// 1. If the cell is alive, it survives provided it has two
// or three neighbouring cells that are also alive.
// 2. If the cell is dead, and has 3 neighbours, it revives.
//
// From this simple ruleset, we find that complex emergent
// behaviour arises. You'll pretty quickly see common stable
// Patterns like the cross and square, but watch out for
// more complex patterns like the glider and pulsar.
fn map_cell(i: Cell, ctx: Context) -> Cell {
var neighbours = 0u;
for (var x = -1; x <= 1; x++) {
for (var y = -1; y <= 1; y++) {
if (x == 0 && y == 0) {
continue;
}
if (is_live(prev_cell(vec2(x, y)))) {
neighbours += 1;
}
}
}
let cell = prev_cell(vec2(0));
var o = i;
o.bg = vec3(0.15, max(0.05, cell.bg.g), 0.35);
if (make_live(cell, neighbours)) {
o.bg.g = 0.95;
} else {
o.bg.g -= 0.05;
}
if (o.bg.g > 0.1) {
o.fg = vec3(0, 1 - o.bg.g, 0);
o.ch = u32(34 + random2(i.sp + round(ctx.time + i.sp * 20) * 0.2) * 80);
}
return map_cell_selection(o, i, ctx);
}
fn is_live(cell: Cell) -> bool {
return cell.bg.g > 0.9;
}
fn make_live(cell: Cell, neighbours: u32) -> bool {
if (is_live(cell)) {
return neighbours == 2 || neighbours == 3;
} else {
return neighbours == 3;
}
}
fn map_cell_selection(ooo: Cell, i: Cell, ctx: Context) -> Cell {
var o = ooo;
if (i.selection.z > 0) {
o.fg = i.fg;
o.bg = i.bg;
o.ch = i.ch;
}
if (i.error) {
o.bg = vec3(1, 0, 0);
}
if (i.selection.w > 0) {
o.bg += vec3(1);
}
if (i.selection.x > 0) {
o.bg += vec3(0.25, 1, 1);
}
return o;
}