Skip to content

Instantly share code, notes, and snippets.

@mikezila
Created August 29, 2014 00:22
Show Gist options
  • Save mikezila/51df313a9f1123f0c292 to your computer and use it in GitHub Desktop.
Save mikezila/51df313a9f1123f0c292 to your computer and use it in GitHub Desktop.
Conway's Game of Life using OpenGL and Go
// Life.go
package main
import (
"fmt"
"github.com/go-gl/gl"
glfw "github.com/go-gl/glfw3"
"math/rand"
"runtime"
"time"
)
const VERSION string = "v0.1"
const TITLE_STRING string = "Life " + VERSION
const DEBUG bool = false
const DEBUG_VERBOSE bool = true
const BUFFER_WIDTH = 640
const BUFFER_HEIGHT = 480
const BUFFER_SIZE = BUFFER_HEIGHT * BUFFER_WIDTH
const BUFFER_SCALE = 2
func main() {
fmt.Println("Life ", VERSION)
// lock glfw/gl calls to a single thread
runtime.LockOSThread()
glfw.Init()
defer glfw.Terminate()
glfw.WindowHint(glfw.Resizable, 0)
window, err := glfw.CreateWindow(BUFFER_WIDTH*BUFFER_SCALE, BUFFER_HEIGHT*BUFFER_SCALE, TITLE_STRING, nil, nil)
if err != nil {
panic(err)
}
defer window.Destroy()
window.MakeContextCurrent()
glfw.SwapInterval(1)
gl.Init()
gl.Disable(gl.DEPTH_TEST)
gl.PointSize(float32(BUFFER_SCALE))
gl.ClearColor(255, 255, 0, 0)
gl.Viewport(0, 0, BUFFER_WIDTH*BUFFER_SCALE, BUFFER_HEIGHT*BUFFER_SCALE)
gl.MatrixMode(gl.PROJECTION)
gl.LoadIdentity()
gl.Ortho(-0.5, float64(BUFFER_WIDTH)-0.5, float64(BUFFER_HEIGHT)-0.5, -0.5, -1, 1)
gl.Clear(gl.COLOR_BUFFER_BIT)
gl.MatrixMode(gl.MODELVIEW)
gl.LoadIdentity()
var life = new(LifeBoard)
life.Randomize()
for !window.ShouldClose() {
life.PlayRound()
gl.Clear(gl.COLOR_BUFFER_BIT)
gl.Begin(gl.POINTS)
for y := 0; y < BUFFER_HEIGHT; y++ {
for x := 0; x < BUFFER_WIDTH; x++ {
if life.CheckStatus(x, y) {
gl.Color3ub(255, 255, 255)
} else {
gl.Color3ub(0, 0, 0)
}
gl.Vertex2i(x, y)
}
}
gl.End()
window.SwapBuffers()
glfw.PollEvents()
if window.GetKey(glfw.KeyEscape) == glfw.Press {
window.SetShouldClose(true)
}
if window.GetKey(glfw.KeyR) == glfw.Press {
life.Randomize()
}
}
}
type LifeCell struct {
Alive bool
NextRound bool
}
type LifeBoard struct {
cells [BUFFER_WIDTH * BUFFER_HEIGHT]LifeCell
}
func (board *LifeBoard) Randomize() {
rand.Seed(int64(time.Now().Nanosecond()))
for e := range board.cells {
if rand.Int31n(3) == 2 {
board.cells[e].Alive = true
}
}
}
func (board *LifeBoard) CheckStatus(x int, y int) (status bool) {
if x < 0 || x >= BUFFER_WIDTH || y < 0 || y >= BUFFER_HEIGHT {
status = false
} else {
status = board.cells[(y*BUFFER_WIDTH)+x].Alive
}
return
}
func (board *LifeBoard) SetNextStatus(x int, y int, status bool) {
board.cells[(y*BUFFER_WIDTH)+x].NextRound = status
}
func (board *LifeBoard) LiveNeighbors(x int, y int) (count int) {
count = 0
if board.CheckStatus(x-1, y-1) {
count++
}
if board.CheckStatus(x, y-1) {
count++
}
if board.CheckStatus(x+1, y-1) {
count++
}
if board.CheckStatus(x-1, y) {
count++
}
if board.CheckStatus(x+1, y) {
count++
}
if board.CheckStatus(x-1, y+1) {
count++
}
if board.CheckStatus(x, y+1) {
count++
}
if board.CheckStatus(x+1, y+1) {
count++
}
return
}
func (board *LifeBoard) PlayRound() {
// Go through rules to see what should happen to each cell
for y := 0; y < BUFFER_HEIGHT; y++ {
for x := 0; x < BUFFER_WIDTH; x++ {
//rules
neighbors := board.LiveNeighbors(x, y)
status := board.CheckStatus(x, y)
if status {
//cell is alive
switch {
case neighbors < 2:
board.SetNextStatus(x, y, false)
case neighbors == 2 || neighbors == 3:
board.SetNextStatus(x, y, true)
case neighbors > 3:
board.SetNextStatus(x, y, false)
}
} else {
//cell is dead
if neighbors == 3 {
board.SetNextStatus(x, y, true)
}
}
}
}
// Apply outcome
for e := range board.cells {
board.cells[e].Alive = board.cells[e].NextRound
}
}
@mikezila
Copy link
Author

A simple version of Conway's Game of Life in Go. Wanted to do the game simulation broken into pieces in a bunch of goroutines, but it turned out to be faster just letting it block and do sim>render over and over. Might try again to thread it later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment