Introducing concept of mutation
which appears to delay the onset of stasis until about twice as many generations (???)
This commit is contained in:
parent
ea5bb19b0b
commit
ad1bd2537a
@ -341,3 +341,24 @@ func TestGenerationScoreCardCalculateResultsInCorrectNeighborCounts(t *testing.T
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateCanMutate(t *testing.T) {
|
||||
state := NewGameState(16, 16)
|
||||
|
||||
err := state.Import(TEST_SIMPLE_INITIAL_STATE)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
curCksum := state.Checksum()
|
||||
err = state.Mutate()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if curCksum == state.Checksum() {
|
||||
t.Errorf("Checksum did not change! %v", curCksum)
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
var (
|
||||
height = flag.Int("height", 40, "Game height")
|
||||
width = flag.Int("width", 80, "Game width")
|
||||
mutate = flag.Bool("mutate", false, "Mutate every other generation")
|
||||
sleepMs = flag.Int("sleep.millis", 200,
|
||||
"Millisecond sleep interval per generation")
|
||||
)
|
||||
@ -34,6 +35,9 @@ func main() {
|
||||
fmt.Printf("\nGeneration %v\n%v\n", generations, now)
|
||||
fmt.Println(game)
|
||||
game.EvaluateGeneration()
|
||||
if *mutate && generations%2 == 0 {
|
||||
game.Mutate()
|
||||
}
|
||||
generations++
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
package conway
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
)
|
||||
@ -11,6 +13,12 @@ type GameOfLife struct {
|
||||
State *GameState
|
||||
}
|
||||
|
||||
type GameStateCell struct {
|
||||
Value int
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
type gameGridRow struct {
|
||||
Cols []int
|
||||
}
|
||||
@ -106,6 +114,63 @@ func (state *GameState) Import(other *GameState) (err error) {
|
||||
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 {
|
||||
return &GameOfLife{
|
||||
State: NewGameState(height, width),
|
||||
|
Loading…
Reference in New Issue
Block a user