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.
This commit is contained in:
129
legacy/go/tui/bg/automata.go
Normal file
129
legacy/go/tui/bg/automata.go
Normal file
@@ -0,0 +1,129 @@
|
||||
// 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()
|
||||
}
|
||||
Reference in New Issue
Block a user