Extracting and testing generation emit and checksumming bits

This commit is contained in:
Dan Buch 2012-12-11 23:35:49 -05:00
parent c0184dd9df
commit 353b59b303
4 changed files with 129 additions and 40 deletions

View File

@ -452,3 +452,31 @@ func TestGameStateCellsCanHaveTheirValueSet(t *testing.T) {
} }
} }
} }
func TestGameOfLifeEmitsGenerationTicksUntilStasis(t *testing.T) {
game, err := newTestGameOfLife()
if err != nil {
t.Error(err)
return
}
genTicks, err := game.Generations()
if err != nil {
t.Error(err)
return
}
nGens := 0
for gen := range genTicks {
if gen.N > 3000 {
t.Errorf("%v is too many generations!", gen.N)
return
}
nGens = gen.N
}
if nGens < 3 {
t.Errorf("%v is too few generations!", nGens)
}
}

View File

@ -19,15 +19,6 @@ var (
"Millisecond sleep interval per generation") "Millisecond sleep interval per generation")
) )
func pushChecksum(checksum string, checksums []string) {
head := make([]string, 3)
copy(head, checksums[:3])
checksums[0] = checksum
checksums[1] = head[0]
checksums[2] = head[1]
checksums[3] = head[2]
}
func main() { func main() {
flag.Parse() flag.Parse()
@ -38,52 +29,32 @@ func main() {
os.Exit(2) os.Exit(2)
} }
checksums := make([]string, 4) genTicks, err := game.Generations()
checksums[0], checksums[1], checksums[2], checksums[3] = "foo", "bar", "baz", "qwx"
ck, err := game.Checksum()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "NAY NAY: %v\n", err) fmt.Fprintf(os.Stderr, "No generations?: %v\n", err)
os.Exit(3) os.Exit(3)
} }
pushChecksum(ck, checksums)
ticks := time.Tick(time.Duration(*sleepMs) * time.Millisecond) sleepInterval := time.Duration(*sleepMs * 1000 * 1000)
generations := 0 for genTick := range genTicks {
for now := range ticks { fmt.Printf("\nGeneration %v\n%v\n", genTick.N, time.Now())
fmt.Printf("\nGeneration %v\n%v\n", generations, now)
fmt.Println(game) fmt.Println(game)
game.EvaluateGeneration() game.EvaluateGeneration()
curChecksum, err := game.Checksum() if genTick.Error != nil {
if err != nil { fmt.Fprintf(os.Stderr, "%s: %s\n", genTick.Message, genTick.Error)
fmt.Fprintf(os.Stderr, "Failed to calculate current game checksum: %v\n", err)
os.Exit(4) os.Exit(4)
} }
if checksums[0] == curChecksum || checksums[1] == curChecksum { if len(genTick.Message) > 0 {
fmt.Println("Stasis!") fmt.Println(genTick.Message)
os.Exit(0)
} }
if checksums[2] == curChecksum { if *mutate && genTick.N%2 == 0 {
fmt.Println("Checksum found 2 periods ago")
fmt.Println("Stasis with 2-period oscillator(s)!")
os.Exit(0)
}
if checksums[3] == curChecksum {
fmt.Println("Checksum found 3 periods ago")
fmt.Println("Stasis with 3-period oscillator(s)!")
os.Exit(0)
}
pushChecksum(curChecksum, checksums)
if *mutate && generations%2 == 0 {
game.Mutate() game.Mutate()
} }
generations++ time.Sleep(sleepInterval)
} }
} }

View File

@ -117,3 +117,86 @@ func (game *GameOfLife) ImportRandomState() error {
func (game *GameOfLife) String() string { func (game *GameOfLife) String() string {
return fmt.Sprintf("%s\n", game.State) return fmt.Sprintf("%s\n", game.State)
} }
func (game *GameOfLife) emitGenerations(genTicks chan *GenerationTick) {
defer close(genTicks)
n := 0
checksums := make([]string, 4)
checksums[0], checksums[1], checksums[2], checksums[3] = "foo", "bar", "baz", "qwx"
ck, err := game.Checksum()
if err != nil {
genTicks <- &GenerationTick{
N: n,
Error: err,
Message: "NAY NAY",
}
}
pushChecksum(ck, checksums)
for {
game.EvaluateGeneration()
curChecksum, err := game.Checksum()
if err != nil {
genTicks <- &GenerationTick{
N: n,
Error: err,
Message: "Failed to calculate current game checksum",
}
break
}
if checksums[0] == curChecksum || checksums[1] == curChecksum {
genTicks <- &GenerationTick{
N: n,
Error: nil,
Message: "Stasis!",
}
break
}
if checksums[2] == curChecksum {
genTicks <- &GenerationTick{
N: n,
Error: nil,
Message: "Stasis with 2-period oscillator(s)!",
}
break
}
if checksums[3] == curChecksum {
genTicks <- &GenerationTick{
N: n,
Error: nil,
Message: "Stasis with 3-period oscillator(s)!",
}
break
}
pushChecksum(curChecksum, checksums)
genTicks <- &GenerationTick{
N: n,
Error: nil,
Message: "",
}
n++
}
}
func (game *GameOfLife) Generations() (<-chan *GenerationTick, error) {
genTicks := make(chan *GenerationTick)
go game.emitGenerations(genTicks)
return (<-chan *GenerationTick)(genTicks), nil
}
func pushChecksum(checksum string, checksums []string) {
head := make([]string, 3)
copy(head, checksums[:3])
checksums[0] = checksum
checksums[1] = head[0]
checksums[2] = head[1]
checksums[3] = head[2]
}

View File

@ -0,0 +1,7 @@
package conway
type GenerationTick struct {
N int
Error error
Message string
}