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