// Conway's Game of Life on 2x2 cells, one print per generation so // you can step through it. Live cells cool from white-hot as they // age. Dead ones fade out as embers. let seed = 42; let size = 2; let cols = ps.doc_width() / size; let rows = ps.doc_height() / size; let gens = 40; let heat = ["#FFF3B0", "#FFD23C", "#FF5B3E", "#E02948", "#A51D45"]; let ember = ["#0A0A1E", "#1E1B44", "#2E2A57", "#5A1236"]; let dark = "#0A0A1E"; fn next(s) { (s * 1103515245 + 12345) % 2147483648 } // A dead border means every cell has eight neighbors to count. let stride = cols + 2; let live = []; live.pad(stride * (rows + 2), 0); let age = live; ps.pixel_fill(0, 0, ps.doc_width() - 1, ps.doc_height() - 1, dark); for y in 1..=rows { for x in 1..=cols { seed = next(seed); if (seed / 65536) % 100 < 30 { live[y * stride + x] = 1; } } } for g in 1..=gens { let was = live; let alive = 0; for y in 1..=rows { let row = y * stride; for x in 1..=cols { let i = row + x; let n = was[i - stride - 1] + was[i - stride] + was[i - stride + 1] + was[i - 1] + was[i + 1] + was[i + stride - 1] + was[i + stride] + was[i + stride + 1]; let a = age[i]; // age > 0: alive that many generations. age < 0: an ember. let b = if was[i] == 1 { if n == 2 || n == 3 { (a + 1).min(5) } else { -3 } } else if n == 3 { 1 } else if a < 0 { a + 1 } else { 0 }; if b != a { age[i] = b; live[i] = if b > 0 { 1 } else { 0 }; let c = if b > 0 { heat[(b - 1).min(4)] } else { ember[-b] }; ps.pixel_fill((x - 1) * size, (y - 1) * size, x * size - 1, y * size - 1, c); } alive += live[i]; } } print(`gen ${g}: ${alive} alive`); }