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