Files
latchd/legacy/go/tui/bg/automata.go
Zane Walker faf5b27328 feat: ship Rust login manager and GitLab release pipeline
Replace the legacy Go implementation as the production path, quarantine the reference tree, add deterministic release packaging and version metadata, and run verification through GitLab CI.
2026-09-25 21:33:46 +05:30

130 lines
2.4 KiB
Go

// bg — cellular automata background for the TUI.
//
// Conway's Game of Life rendered at 30 Hz using Unicode half-block
// characters (▀) to double the effective vertical resolution.
// The grid is double-buffered for zero-allocation ticking, and
// render output is built in a pre-allocated strings.Builder so the
package bg
import (
"math/rand"
"strings"
)
// Bright orange (accent) for alive cells, dark grey for dead.
const (
fgAlive = "\x1b[38;2;255;127;0m"
fgDead = "\x1b[38;2;30;30;30m"
bgAlive = "\x1b[48;2;255;127;0m"
bgDead = "\x1b[48;2;30;30;30m"
reset = "\x1b[0m"
block = "▀"
)
type Automata struct {
w, h int
a, b []uint8
useA bool
buf strings.Builder
}
func NewAutomata(w, h int) *Automata {
a := &Automata{useA: true}
a.Resize(w, h)
return a
}
func (a *Automata) Resize(w, h int) {
logH := h * 2
if a.w == w && a.h == logH {
return
}
a.w = w
a.h = logH
sz := w * logH
a.a = make([]uint8, sz)
a.b = make([]uint8, sz)
for i := 0; i < sz; i++ {
if rand.Float32() > 0.85 {
a.a[i] = 1
}
}
a.buf.Grow(w * h * 40)
}
func (a *Automata) Tick() {
src, dst := a.a, a.b
if !a.useA {
src, dst = a.b, a.a
}
w, h := a.w, a.h
for y := range h {
for x := range w {
i := y*w + x
alive := src[i]
n := a.count(src, x, y, w, h)
if alive == 1 && (n == 2 || n == 3) {
dst[i] = 1
} else if alive == 0 && n == 3 {
dst[i] = 1
} else {
dst[i] = 0
}
}
}
a.useA = !a.useA
}
func (a *Automata) count(g []uint8, x, y, w, h int) uint8 {
var c uint8
for dy := -1; dy <= 1; dy++ {
for dx := -1; dx <= 1; dx++ {
if dx == 0 && dy == 0 {
continue
}
nx, ny := x+dx, y+dy
if nx >= 0 && nx < w && ny >= 0 && ny < h {
c += g[ny*w+nx]
}
}
}
return c
}
// Frame returns the current generation as a single string suitable for
// writing to the alternate screen.
func (a *Automata) Frame() string {
a.buf.Reset()
src := a.a
if !a.useA {
src = a.b
}
w, h := a.w, a.h
for y := 0; y < h; y += 2 {
for x := range w {
top := src[y*w+x]
bot := uint8(0)
if y+1 < h {
bot = src[(y+1)*w+x]
}
if top == 1 {
a.buf.WriteString(fgAlive)
} else {
a.buf.WriteString(fgDead)
}
if bot == 1 {
a.buf.WriteString(bgAlive)
} else {
a.buf.WriteString(bgDead)
}
a.buf.WriteString(block)
}
a.buf.WriteString(reset)
if y < h-2 {
a.buf.WriteByte('\n')
}
}
return a.buf.String()
}