|
|
|
package conway
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"math/rand"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
rand.Seed(time.Now().UTC().UnixNano())
|
|
|
|
}
|
|
|
|
|
|
|
|
type GameOfLife struct {
|
|
|
|
State *GameState
|
|
|
|
}
|
|
|
|
|
|
|
|
func (game *GameOfLife) Mutate() error {
|
|
|
|
return game.State.Mutate()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (game *GameOfLife) Checksum() (string, error) {
|
|
|
|
return game.State.Checksum()
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewGameOfLife(height, width int) *GameOfLife {
|
|
|
|
return &GameOfLife{
|
|
|
|
State: NewGameState(height, width),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (game *GameOfLife) EvaluateGeneration() error {
|
|
|
|
height, width := game.State.Height(), game.State.Width()
|
|
|
|
|
|
|
|
genScore := NewGenerationScoreCard(height, width)
|
|
|
|
genScore.Calculate(game.State)
|
|
|
|
|
|
|
|
cells, err := genScore.Cells()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for cell := range cells {
|
|
|
|
score := cell.Value
|
|
|
|
|
|
|
|
curState, err := game.State.Get(cell.X, cell.Y)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if curState == 1 {
|
|
|
|
|
|
|
|
if score < 2 {
|
|
|
|
err = game.State.Deaden(cell.X, cell.Y)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if score == 2 || score == 3 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if score > 3 {
|
|
|
|
err = game.State.Deaden(cell.X, cell.Y)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
} else if curState == 0 {
|
|
|
|
|
|
|
|
if score == 3 {
|
|
|
|
err = game.State.Enliven(cell.X, cell.Y)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
} else {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (game *GameOfLife) ImportState(state *GameState) error {
|
|
|
|
return game.State.Import(state)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (game *GameOfLife) ImportRandomState() error {
|
|
|
|
height := game.State.Height()
|
|
|
|
width := game.State.Width()
|
|
|
|
|
|
|
|
if height < 0 || width < 0 {
|
|
|
|
errStr := fmt.Sprintf("current game has invalid dimensions! %vx%v",
|
|
|
|
height, width)
|
|
|
|
return errors.New(errStr)
|
|
|
|
}
|
|
|
|
|
|
|
|
randState := NewGameState(height, width)
|
|
|
|
|
|
|
|
cells, err := randState.Cells()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for cell := range cells {
|
|
|
|
cell.SetValue(rand.Intn(2))
|
|
|
|
}
|
|
|
|
|
|
|
|
return game.ImportState(randState)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (game *GameOfLife) String() string {
|
|
|
|
return fmt.Sprintf("%s\n", game.State)
|
|
|
|
}
|