Introducing concept of mutation

which appears to delay the onset of stasis until about twice as many
generations (???)
This commit is contained in:
Dan Buch 2012-12-10 00:19:31 -05:00
parent ea5bb19b0b
commit ad1bd2537a
3 changed files with 90 additions and 0 deletions

View File

@ -341,3 +341,24 @@ func TestGenerationScoreCardCalculateResultsInCorrectNeighborCounts(t *testing.T
return 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)
}
}

View File

@ -14,6 +14,7 @@ import (
var ( var (
height = flag.Int("height", 40, "Game height") height = flag.Int("height", 40, "Game height")
width = flag.Int("width", 80, "Game width") width = flag.Int("width", 80, "Game width")
mutate = flag.Bool("mutate", false, "Mutate every other generation")
sleepMs = flag.Int("sleep.millis", 200, sleepMs = flag.Int("sleep.millis", 200,
"Millisecond sleep interval per generation") "Millisecond sleep interval per generation")
) )
@ -34,6 +35,9 @@ func main() {
fmt.Printf("\nGeneration %v\n%v\n", generations, now) fmt.Printf("\nGeneration %v\n%v\n", generations, now)
fmt.Println(game) fmt.Println(game)
game.EvaluateGeneration() game.EvaluateGeneration()
if *mutate && generations%2 == 0 {
game.Mutate()
}
generations++ generations++
} }
} }

View File

@ -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),