cgol/main.go

120 lines
2.0 KiB
Go

package main
import (
"fmt"
"math/rand"
"os"
tea "github.com/charmbracelet/bubbletea"
)
// Create simple constants
const (
ROW = 35
COL = 70
)
// Just need a grid and buffer
type gol struct {
grid [ROW][COL]int
buffer [ROW][COL]int
}
// Create array that holds field's to check for neighbours
var CHECK_ARRAY = [8][2]int{{-1, -1}, {-1, 0}, {-1, +1}, {0, -1}, {0, +1}, {+1, -1}, {+1, 0}, {+1, +1}}
// Initialize empty game of life
func initGol() gol {
start := [ROW][COL]int{}
// Intentionally skipping field around the array making it empty
for i := 1; i < ROW-1; i++ {
for j := 1; j < COL-1; j++ {
if rand.Intn(2) == 1 {
start[i][j] = 1
} else {
start[i][j] = 0
}
}
}
return gol{
grid: start,
buffer: start,
}
}
// Simple init
func (g gol) Init() tea.Cmd {
return nil
}
// Check neighobours
func (g gol) countNeighbours(x int, y int) int {
n := 0
for i := 0; i < 8; i++ {
if g.buffer[x+CHECK_ARRAY[i][0]][y+CHECK_ARRAY[i][1]] == 1 {
n += 1
}
}
return n
}
// Life logic
func (g gol) Life() tea.Model {
for i := 1; i < ROW-1; i++ {
for j := 1; j < COL-1; j++ {
n := g.countNeighbours(i, j)
if g.buffer[i][j] == 1 {
if n < 2 || n > 3 {
g.buffer[i][j] = 0
}
} else {
if n == 3 {
g.buffer[i][j] = 1
}
}
}
}
return g
}
// Simple update
func (g gol) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
// Just quit when using ctrl+c or q
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return g, tea.Quit
case " ":
g.Life()
return g, nil
}
}
return g, nil
}
// Let's draw this all simply
func (g gol) View() string {
var s string
// Making sure to not draw the empty field around the array
for i := 1; i < ROW-1; i++ {
for j := 1; j < COL-1; j++ {
if g.grid[i][j] == 1 {
s += "*"
} else {
s += " "
}
}
s += "\n"
}
return s
}
func main() {
p := tea.NewProgram(initGol())
if _, err := p.Run(); err != nil {
fmt.Printf("Oh no, an error: %v", err)
os.Exit(1)
}
}