Created
July 12, 2015 20:01
-
-
Save danker/5601511764cd1670791d to your computer and use it in GitHub Desktop.
Conway's Game of Life in Go.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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