I got bored and wrote this:
package main import "core:fmt" import "core:math/rand" import "intrinsics" elementary_cellular_automata :: proc(state: $T, rule: u8, generations: int) where intrinsics.type_is_integer(T), intrinsics.type_is_unsigned(T) { N :: 8*size_of(state); output :: proc(state: T) { buf: [N]byte; for i in 0..<T(N) { buf[N-1-i] = state & (1<<i) != 0 ? '#' : ' '; } fmt.println(string(buf[:])); } bit :: proc(x, i: T) -> T { return (x >> i) & 0x1; } set :: proc(x: ^T, cell, k: T, rule: u8) { x^ &~= 1<<cell; if rule>>k&1 != 0 { x^ |= 1<<cell; } } a := state; a1 := T(0); output(a); last := T(N-1); for r in 0..<generations { k := bit(a, last) | bit(a, 0)<<1 | bit(a, 1)<<2; set(&a1, 0, k, rule); a1 |= (1<<0) * T(rule>>k&1); for c in 1..<last { k = k>>1 | bit(a, c+1)<<2; set(&a1, c, k, rule); } set(&a1, last, k>>1|bit(a, 0)<<2, rule); a, a1 = a1, a; output(a); } } main :: proc() { elementary_cellular_automata( state=rand.uint128(), rule=30, generations=50, ); }
See: https://en.wikipedia.org/wiki/Elementary_cellular_automaton