Created
March 4, 2015 20:35
-
-
Save progrium/9e1d085d9e978d32e99a to your computer and use it in GitHub Desktop.
Run this program here: http://play.golang.org/p/nr2wehptjW
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 ( | |
"bytes" | |
"fmt" | |
"math/rand" | |
"time" | |
) | |
// Field represents a two-dimensional field of cells. | |
type Field struct { | |
s [][]bool | |
w, h int | |
} | |
// NewField returns an empty field of the specified width and height. | |
func NewField(w, h int) *Field { | |
s := make([][]bool, h) | |
for i := range s { | |
s[i] = make([]bool, w) | |
} | |
return &Field{s: s, w: w, h: h} | |
} | |
// Set sets the state of the specified cell to the given value. | |
func (f *Field) Set(x, y int, b bool) { | |
f.s[y][x] = b | |
} | |
// Alive reports whether the specified cell is alive. | |
// If the x or y coordinates are outside the field boundaries they are wrapped | |
// toroidally. For instance, an x value of -1 is treated as width-1. | |
func (f *Field) Alive(x, y int) bool { | |
x += f.w | |
x %= f.w | |
y += f.h | |
y %= f.h | |
return f.s[y][x] | |
} | |
// Next returns the state of the specified cell at the next time step. | |
func (f *Field) Next(x, y int) bool { | |
// Count the adjacent cells that are alive. | |
alive := 0 | |
for i := -1; i <= 1; i++ { | |
for j := -1; j <= 1; j++ { | |
if (j != 0 || i != 0) && f.Alive(x+i, y+j) { | |
alive++ | |
} | |
} | |
} | |
// Return next state according to the game rules: | |
// exactly 3 neighbors: on, | |
// exactly 2 neighbors: maintain current state, | |
// otherwise: off. | |
return alive == 3 || alive == 2 && f.Alive(x, y) | |
} | |
// Life stores the state of a round of Conway's Game of Life. | |
type Life struct { | |
a, b *Field | |
w, h int | |
} | |
// NewLife returns a new Life game state with a random initial state. | |
func NewLife(w, h int) *Life { | |
a := NewField(w, h) | |
for i := 0; i < (w * h / 4); i++ { | |
a.Set(rand.Intn(w), rand.Intn(h), true) | |
} | |
return &Life{ | |
a: a, b: NewField(w, h), | |
w: w, h: h, | |
} | |
} | |
// Step advances the game by one instant, recomputing and updating all cells. | |
func (l *Life) Step() { | |
// Update the state of the next field (b) from the current field (a). | |
for y := 0; y < l.h; y++ { | |
for x := 0; x < l.w; x++ { | |
l.b.Set(x, y, l.a.Next(x, y)) | |
} | |
} | |
// Swap fields a and b. | |
l.a, l.b = l.b, l.a | |
} | |
// String returns the game board as a string. | |
func (l *Life) String() string { | |
var buf bytes.Buffer | |
for y := 0; y < l.h; y++ { | |
for x := 0; x < l.w; x++ { | |
b := " " | |
if l.a.Alive(x, y) { | |
b = "\u2596" | |
} | |
buf.Write([]byte(b)) | |
} | |
buf.WriteByte('\n') | |
} | |
return buf.String() | |
} | |
func main() { | |
l := NewLife(40, 15) | |
for i := 0; i < 300; i++ { | |
l.Step() | |
fmt.Print("\x0c", l) // Clear screen and print field. | |
time.Sleep(time.Second / 30) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment