Skip to content

Instantly share code, notes, and snippets.

@danker
Created July 12, 2015 20:01
Show Gist options
  • Save danker/5601511764cd1670791d to your computer and use it in GitHub Desktop.
Save danker/5601511764cd1670791d to your computer and use it in GitHub Desktop.
Conway's Game of Life in Go.
package main
import (
"fmt"
"math/rand"
"time"
"github.com/nsf/termbox-go"
)
// RULES
// < 2 neighors = DIE
// >=2 <=3 = LIVE
// >3 neighors = DIE
// if DEAD and 3 neighbors = LIVE (reproduction!)
const gridsize = 40
const evolutions = 50
const animationSpeed = 150 * time.Millisecond
func main() {
var beings [gridsize][gridsize]bool
seedSimulation(&beings)
// setup GUI
err := termbox.Init()
if err != nil {
panic(err)
}
defer termbox.Close()
for i := 0; i < evolutions; i++ {
updateGridState(&beings)
renderScreen(&beings)
time.Sleep(animationSpeed)
}
}
func seedSimulation(beings *[gridsize][gridsize]bool) {
for i := 0; i < gridsize; i++ {
for j := 0; j < gridsize; j++ {
// Set this being to "ALIVE" (true) based on random value.
if rand.Intn(100) > 85 {
beings[i][j] = true
}
}
}
}
// iterate over the entire grid, changing states on each "being" based on the rules of the game.
func updateGridState(beings *[gridsize][gridsize]bool) {
for i := 0; i < gridsize; i++ {
for j := 0; j < gridsize; j++ {
var liveNeighborCount = determineLiveNeighbors(i, j, beings)
if beings[i][j] == true { // if alive, determine if the being should live or die
if liveNeighborCount < 2 {
beings[i][j] = false // die..."under population"
} else if (liveNeighborCount >= 2) && (liveNeighborCount <= 3) {
beings[i][j] = true
} else if liveNeighborCount > 3 {
beings[i][j] = false // die..."over crowding"
}
} else { // if currently dead, determine if the being should come back to life.
if liveNeighborCount == 3 {
beings[i][j] = true // "reproduction"
}
}
}
}
}
func determineLiveNeighbors(x int, y int, beings *[gridsize][gridsize]bool) int {
var neighborNorthPosition, neighborSouthPosition,
neighborEastPosition, neighborWestPosition int
var aliveNeighbors int
// determine "west" neighbor location
if (x - 1) >= 0 {
neighborWestPosition = x - 1
} else {
neighborWestPosition = gridsize - 1
}
// determine "east" neighbor location
if (x + 1) < gridsize {
neighborEastPosition = x + 1
} else {
neighborEastPosition = 0
}
// determine "north" neighbor location
if (y + 1) < gridsize {
neighborNorthPosition = y + 1
} else {
neighborNorthPosition = 0
}
// determine "south" neighbor location
if (y - 1) >= 0 {
neighborSouthPosition = y - 1
} else {
neighborSouthPosition = gridsize - 1
}
// Now determine which neighbors are alive
if beings[neighborWestPosition][y] == true {
aliveNeighbors++ // neighbor directly west
}
if beings[neighborWestPosition][neighborNorthPosition] == true {
aliveNeighbors++ // neighbor to NW
}
if beings[x][neighborNorthPosition] == true {
aliveNeighbors++ // neighbor directly north
}
if beings[neighborEastPosition][neighborNorthPosition] == true {
aliveNeighbors++ // neighbor to NE
}
if beings[neighborEastPosition][y] == true {
aliveNeighbors++ // neighbor directly east
}
if beings[neighborEastPosition][neighborSouthPosition] == true {
aliveNeighbors++ // neighbor to SE
}
if beings[x][neighborSouthPosition] == true {
aliveNeighbors++ // neighbor directly south
}
if beings[neighborWestPosition][neighborSouthPosition] == true {
aliveNeighbors++ // neighbor to SW
}
return aliveNeighbors
}
// print the state of the grid to STDOUT
func printGrid(beings *[gridsize][gridsize]bool) {
fmt.Println("~~~~~~~~~~~~~~~~")
for i := 0; i < gridsize; i++ {
for j := 0; j < gridsize; j++ {
if beings[i][j] == true {
fmt.Printf("X")
} else {
fmt.Printf("_")
}
}
fmt.Printf("\n")
}
fmt.Println("~~~~~~~~~~~~~~~~")
}
// leverage the termbox library to render to the terminal
func renderScreen(beings *[gridsize][gridsize]bool) {
termbox.Clear(termbox.ColorBlack, termbox.ColorBlack)
for i := 0; i < gridsize; i++ {
for j := 0; j < gridsize; j++ {
if beings[i][j] == true {
termbox.SetCell(i, j, ' ', termbox.ColorGreen, termbox.ColorGreen) // paint "alive" being
} else {
termbox.SetCell(i, j, ' ', termbox.ColorBlack, termbox.ColorBlack) // paint "dead" being
}
}
}
termbox.Flush()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment