]> Cypherpunks repositories - gostls13.git/commitdiff
doc: add Game of Life to playground toys
authorAndrew Gerrand <adg@golang.org>
Tue, 4 Jun 2013 02:59:28 +0000 (12:59 +1000)
committerAndrew Gerrand <adg@golang.org>
Tue, 4 Jun 2013 02:59:28 +0000 (12:59 +1000)
R=golang-dev, dsymonds, r
CC=golang-dev
https://golang.org/cl/9961043

doc/play/life.go [new file with mode: 0644]
doc/root.html

diff --git a/doc/play/life.go b/doc/play/life.go
new file mode 100644 (file)
index 0000000..0827176
--- /dev/null
@@ -0,0 +1,113 @@
+// An implementation of Conway's Game of Life.
+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 returns 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 := byte(' ')
+                       if l.a.Alive(x, y) {
+                               b = '*'
+                       }
+                       buf.WriteByte(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)
+       }
+}
index 81792671b611679d143af6d91f7472d5a8b6ad1e..e2d53414e724926864d1ab6bffdb67d5083daf22 100644 (file)
@@ -31,6 +31,7 @@ Hello, 世界
 <div class="toys">
 <select>
        <option value="hello.go">Hello, World!</option>
+       <option value="life.go">Conway's Game of Life</option>
        <option value="fib.go">Fibonacci Closure</option>
        <option value="peano.go">Peano Integers</option>
        <option value="pi.go">Concurrent pi</option>