|
|
@ -1,8 +1,10 @@
|
|
|
|
package conway
|
|
|
|
package conway
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
import (
|
|
|
|
|
|
|
|
"crypto/sha1"
|
|
|
|
"errors"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"math"
|
|
|
|
"math/rand"
|
|
|
|
"math/rand"
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
)
|
|
|
@ -11,6 +13,12 @@ type GameOfLife struct {
|
|
|
|
State *GameState
|
|
|
|
State *GameState
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type GameStateCell struct {
|
|
|
|
|
|
|
|
Value int
|
|
|
|
|
|
|
|
X int
|
|
|
|
|
|
|
|
Y int
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type gameGridRow struct {
|
|
|
|
type gameGridRow struct {
|
|
|
|
Cols []int
|
|
|
|
Cols []int
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -106,6 +114,63 @@ func (state *GameState) Import(other *GameState) (err error) {
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (state *GameState) Cells(cells chan *GameStateCell) error {
|
|
|
|
|
|
|
|
height := state.Height()
|
|
|
|
|
|
|
|
width := state.Width()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if height < 0 || width < 0 {
|
|
|
|
|
|
|
|
return errors.New("state has invalid dimensions!")
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
defer close(cells)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for y := 0; y < height; y++ {
|
|
|
|
|
|
|
|
for x := 0; x < width; x++ {
|
|
|
|
|
|
|
|
value, err := state.Get(x, y)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
panic(err)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
cells <- &GameStateCell{
|
|
|
|
|
|
|
|
Value: value,
|
|
|
|
|
|
|
|
X: x,
|
|
|
|
|
|
|
|
Y: y,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (game *GameOfLife) Mutate() error {
|
|
|
|
|
|
|
|
return game.State.Mutate()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (state *GameState) Mutate() error {
|
|
|
|
|
|
|
|
randX := rand.Intn(state.Width())
|
|
|
|
|
|
|
|
randY := rand.Intn(state.Height())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
curVal, err := state.Get(randX, randY)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = state.Set(randX, randY, int(math.Abs(float64(curVal-1))))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (state *GameState) Checksum() string {
|
|
|
|
|
|
|
|
ck := sha1.New()
|
|
|
|
|
|
|
|
cells := make(chan *GameStateCell)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
go state.Cells(cells)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for cell := range cells {
|
|
|
|
|
|
|
|
fmt.Fprintf(ck, "%v", cell.Value)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprintf("%x", ck.Sum(nil))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewGameOfLife(height, width int) *GameOfLife {
|
|
|
|
func NewGameOfLife(height, width int) *GameOfLife {
|
|
|
|
return &GameOfLife{
|
|
|
|
return &GameOfLife{
|
|
|
|
State: NewGameState(height, width),
|
|
|
|
State: NewGameState(height, width),
|
|
|
|