package main import ( "flag" "fmt" "image" "image/color" "image/jpeg" "math/rand" "os" "time" ) const ( // Grid size //size = 150 size = 30 // Image zoom value zoom = 8 // Generations per second gps = 2 ) type Grid struct { G [size][size]bool } func (g *Grid) Blinker() { g.G[14][13] = true g.G[14][14] = true g.G[14][15] = true } func (g *Grid) Bipole() { g.G[14][14] = true g.G[14][15] = true g.G[15][14] = true g.G[16][17] = true g.G[17][16] = true g.G[17][17] = true } func (g *Grid) Tripole() { g.G[14][14] = true g.G[14][15] = true g.G[15][14] = true g.G[16][15] = true g.G[16][17] = true g.G[17][18] = true g.G[18][17] = true g.G[18][18] = true } func (g *Grid) Pulsator() { for i := 10; i < 20; i++ { g.G[i][14] = true } } func (g *Grid) Glider() { g.G[1][0] = true g.G[2][1] = true g.G[2][2] = true g.G[1][2] = true g.G[0][2] = true } func (g *Grid) Random() { rand.Seed(size) for i := 0; i < size; i++ { for j := 0; j < size; j++ { g.G[i][j] = rand.Intn(2) == 1 } } } /* func (g *Grid) Pentomino() { g.G[75][74] = true g.G[76][74] = true g.G[74][75] = true g.G[75][75] = true g.G[75][76] = true } */ type GOL struct { grid1 *Grid grid2 *Grid Gen int } func NewGOL() (g *GOL) { g = &GOL{grid1: new(Grid), grid2: new(Grid)} g.grid1.Blinker() //g.grid1.Bipole() //g.grid1.Tripole() //g.grid1.Pulsator() //g.grid1.Random() //g.grid1.Pentomino() return } func min(i int) int { if i == -1 { return i + 1 } return i } func max(i int) int { if i == size { return i - 1 } return i } func (g *GOL) n(x, y int) (n int) { for i := min(x - 1); i <= max(x+1); i++ { for j := min(y - 1); j <= max(y+1); j++ { if g.grid1.G[i][j] { n++ } } } return } func (g *GOL) check(x, y int) { n := g.n(x, y) if g.grid1.G[x][y] { n-- switch n { case 0, 1: g.grid2.G[x][y] = false case 2, 3: g.grid2.G[x][y] = true default: g.grid2.G[x][y] = false } } else { if n == 3 { g.grid2.G[x][y] = true } else { g.grid2.G[x][y] = false } } } func (g *GOL) grid() (gr *Grid) { gr = new(Grid) for i := 0; i < size; i++ { gr.G[i] = g.grid1.G[i] } g.grid1, g.grid2 = g.grid2, g.grid1 return } func (g *GOL) Calc() (gr *Grid) { for i := 0; i < size; i++ { for j := 0; j < size; j++ { g.check(i, j) } } g.Gen++ return g.grid() } var text bool func main() { flag.BoolVar(&text, "text", false, "text mode") flag.Parse() gol := NewGOL() gc := make(chan *Grid, 10) if text { go func() { var buf [size * (size + 6)]byte for { buf[0] = '+' c := 1 for ; c < size+1; c++ { buf[c] = '-' } buf[c] = '+' c++ buf[c] = '\n' c++ grid := <-gc for i := 0; i < size; i++ { buf[c] = '|' c++ for j := 0; j < size; j++ { if grid.G[j][i] { buf[c] = '#' } else { buf[c] = ' ' } c++ } buf[c] = '|' c++ buf[c] = '\n' c++ } buf[c] = '+' c++ for i := 0; i < size; i++ { buf[c] = '-' c++ } buf[c] = '+' c++ buf[c] = '\n' fmt.Printf("\r%s", string(buf[:])) } }() } else { ic := make(chan image.Image, 10) go func() { o := jpeg.Options{100} img := <-ic for { select { case img = <-ic: default: } if jpeg.Encode(os.Stdout, img, &o) == nil { os.Stdout.Sync() } time.Sleep(time.Millisecond * 16) } }() go func() { s := size * zoom r := image.Rect(0, 0, s, s) for { img := image.NewGray(r) grid := <-gc x := 0 y := 0 var c color.Color for i := 0; i < size; i++ { for j := 0; j < size; j++ { if grid.G[i][j] { c = color.Black } else { c = color.White } for a := 0; a < zoom; a++ { for b := 0; b < zoom; b++ { img.Set(x+a, y+b, c) } } y += zoom } x += zoom y = 0 } ic <- img } }() } for { gc <- gol.Calc() if !text { fmt.Fprintf(os.Stderr, "\rGeneration: %d", gol.Gen) } time.Sleep(time.Second / gps) } }