life.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // An implementation of Conway's Game of Life.
  2. package main
  3. import (
  4. "bytes"
  5. "fmt"
  6. "math/rand"
  7. "time"
  8. )
  9. // Field represents a two-dimensional field of cells.
  10. type Field struct {
  11. s [][]bool
  12. w, h int
  13. }
  14. // NewField returns an empty field of the specified width and height.
  15. func NewField(w, h int) *Field {
  16. s := make([][]bool, h)
  17. for i := range s {
  18. s[i] = make([]bool, w)
  19. }
  20. return &Field{s: s, w: w, h: h}
  21. }
  22. // Set sets the state of the specified cell to the given value.
  23. func (f *Field) Set(x, y int, b bool) {
  24. f.s[y][x] = b
  25. }
  26. // Alive reports whether the specified cell is alive.
  27. // If the x or y coordinates are outside the field boundaries they are wrapped
  28. // toroidally. For instance, an x value of -1 is treated as width-1.
  29. func (f *Field) Alive(x, y int) bool {
  30. x += f.w
  31. x %= f.w
  32. y += f.h
  33. y %= f.h
  34. return f.s[y][x]
  35. }
  36. // Next returns the state of the specified cell at the next time step.
  37. func (f *Field) Next(x, y int) bool {
  38. // Count the adjacent cells that are alive.
  39. alive := 0
  40. for i := -1; i <= 1; i++ {
  41. for j := -1; j <= 1; j++ {
  42. if (j != 0 || i != 0) && f.Alive(x+i, y+j) {
  43. alive++
  44. }
  45. }
  46. }
  47. // Return next state according to the game rules:
  48. // exactly 3 neighbors: on,
  49. // exactly 2 neighbors: maintain current state,
  50. // otherwise: off.
  51. return alive == 3 || alive == 2 && f.Alive(x, y)
  52. }
  53. // Life stores the state of a round of Conway's Game of Life.
  54. type Life struct {
  55. a, b *Field
  56. w, h int
  57. }
  58. // NewLife returns a new Life game state with a random initial state.
  59. func NewLife(w, h int) *Life {
  60. a := NewField(w, h)
  61. for i := 0; i < (w * h / 4); i++ {
  62. a.Set(rand.Intn(w), rand.Intn(h), true)
  63. }
  64. return &Life{
  65. a: a, b: NewField(w, h),
  66. w: w, h: h,
  67. }
  68. }
  69. // Step advances the game by one instant, recomputing and updating all cells.
  70. func (l *Life) Step() {
  71. // Update the state of the next field (b) from the current field (a).
  72. for y := 0; y < l.h; y++ {
  73. for x := 0; x < l.w; x++ {
  74. l.b.Set(x, y, l.a.Next(x, y))
  75. }
  76. }
  77. // Swap fields a and b.
  78. l.a, l.b = l.b, l.a
  79. }
  80. // String returns the game board as a string.
  81. func (l *Life) String() string {
  82. var buf bytes.Buffer
  83. for y := 0; y < l.h; y++ {
  84. for x := 0; x < l.w; x++ {
  85. b := byte(' ')
  86. if l.a.Alive(x, y) {
  87. b = '*'
  88. }
  89. buf.WriteByte(b)
  90. }
  91. buf.WriteByte('\n')
  92. }
  93. return buf.String()
  94. }
  95. func main() {
  96. l := NewLife(40, 15)
  97. for i := 0; i < 300; i++ {
  98. l.Step()
  99. fmt.Print("\x0c", l) // Clear screen and print field.
  100. time.Sleep(time.Second / 30)
  101. }
  102. }