package main import ( "errors" "math/rand" "time" ) type Cell struct { x uint y uint live bool } func (c *Cell) NeighborCount(arr [][]Cell) uint { // Read grid dimensions width := uint(len(arr)) height := uint(len(arr[0])) count := uint(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 := uint(int(c.x+width)+i) % width ny := uint(int(c.y+height)+j) % height // Count if neighbor is alive if arr[nx][ny].live { count++ } } } return count } func initGrid(width, height uint, 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 := uint(0); i < width; i++ { // Make second dimension cells[i] = make([]Cell, height) for j := uint(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 } else { cells[i][j].live = rand.Intn(2) == 1 } } } return cells, nil } func setup(callback func([][]Cell), scale, width, height uint, FPS time.Duration) chan bool { // Initialize grid at specified scale grid, _ := initGrid(width/scale, height/scale) // Prepare ticker and finishing flag ticker := time.NewTicker((1000 / FPS) * time.Millisecond) done := make(chan bool) // Run game loop go func() { for { select { case <-done: return case <-ticker.C: grid = draw(grid, callback) } } }() // Return flag to be stopped outside return done } func draw(grid [][]Cell, callback func([][]Cell)) [][]Cell { width := uint(len(grid)) height := uint(len(grid[0])) generation, _ := initGrid(width, height, grid) // Iterate through grid for i := uint(0); i < width; i++ { for j := uint(0); j < height; 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) return generation }