go/doc/play/life.go
Rob Pike abe384f68a all: be more idiomatic when documenting boolean return values.
Phrases like "returns whether or not the image is opaque" could be
describing what the function does (it always returns, regardless of
the opacity) or what it returns (a boolean indicating the opacity).
Even when the "or not" is missing, the phrasing is bizarre.

Go with "reports whether", which is still clunky but at least makes
it clear we're talking about the return value.

These were edited by hand. A few were cleaned up in other ways.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/11699043
2013-07-23 11:59:49 +10:00

114 lines
2.4 KiB
Go

// 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 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 := 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)
}
}