Matrix/conway.go
2024-04-14 21:29:40 +02:00

109 lines
2.3 KiB
Go

package main
import (
"errors"
"time"
)
type Cell struct {
x int
y int
live bool
}
func (c *Cell) NeighborCount(arr [][]Cell) int {
count := 0
// Iterate through 3x3 neighboring grid
for i := -1; i <= 1; i++ {
for j := -1; j <= 1; j++ {
// Ignore own position
if i == 0 && j == 0 {
continue
}
// Get neighbor coordinates
nx, ny := c.x+i, c.y+j
// Check if neighbor is within bounds
if nx < 0 || nx >= len(arr) || ny < 0 || ny >= len(arr[0]) {
continue
}
// Count if neighbor is alive
if arr[nx][ny].live {
count++
}
}
}
return count
}
func initGrid(width, height int, parent ...[][]Cell) ([][]Cell, error) {
exists := len(parent) == 1
if exists && len(parent) > 1 {
return nil, errors.New("Too many parents specified")
}
// Make first dimension
cells := make([][]Cell, width)
for i := 0; i < width; i++ {
// Make second dimension
cells[i] = make([]Cell, height)
for j := 0; j < height; j++ {
// Make cells
cells[i][j].x = i
cells[i][j].y = j
// If specified, copy state from parent
if exists {
cells[i][j].live = parent[0][i][j].live
}
}
}
return cells, nil
}
var grid [][]Cell
func setup(callback func([][]Cell), width, height, FPS int) chan bool {
grid, _ = initGrid(width, height)
// Prepare ticker and finishing flag
ticker := time.NewTicker(time.Second / time.Duration(FPS))
done := make(chan bool)
// Run game loop
go func() {
for {
select {
case <-done:
return
case <-ticker.C:
draw(callback)
}
}
}()
// Return flag to be stopped outside
return done
}
func draw(callback func([][]Cell)) {
generation, _ := initGrid(len(grid), len(grid[0]), grid)
// Iterate through grid
for i := 0; i < len(grid); i++ {
for j := 0; j < len(grid[0]); j++ {
// Count neighbors
cout := grid[i][j].NeighborCount(grid)
// Get state
curr := grid[i][j].live
// Apply rules
died := curr && (cout < 2 || cout > 3)
born := !curr && cout == 3
next := curr && !died || born
// Set state
generation[i][j].live = next
// A * !(A * (B + C)) + !A * D
// = A * !B * !C + !A * D
// curr && cout >= 2 && cout <= 3 || !curr && cout == 3
}
}
callback(generation)
}