From 353b59b30329fe84e4ada1f07ce4f0f3803f8a9e Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Tue, 11 Dec 2012 23:35:49 -0500 Subject: [PATCH] Extracting and testing generation emit and checksumming bits --- conway/conway_test.go | 28 ++++++++++ conway/conways-game-of-life/main.go | 51 ++++-------------- conway/game_of_life.go | 83 +++++++++++++++++++++++++++++ conway/generation_tick.go | 7 +++ 4 files changed, 129 insertions(+), 40 deletions(-) create mode 100644 conway/generation_tick.go diff --git a/conway/conway_test.go b/conway/conway_test.go index d6c3e89..7ca2094 100644 --- a/conway/conway_test.go +++ b/conway/conway_test.go @@ -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) + } +} diff --git a/conway/conways-game-of-life/main.go b/conway/conways-game-of-life/main.go index f8bb76a..269c82d 100644 --- a/conway/conways-game-of-life/main.go +++ b/conway/conways-game-of-life/main.go @@ -19,15 +19,6 @@ var ( "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() { flag.Parse() @@ -38,52 +29,32 @@ func main() { os.Exit(2) } - checksums := make([]string, 4) - checksums[0], checksums[1], checksums[2], checksums[3] = "foo", "bar", "baz", "qwx" - ck, err := game.Checksum() + genTicks, err := game.Generations() if err != nil { - fmt.Fprintf(os.Stderr, "NAY NAY: %v\n", err) + fmt.Fprintf(os.Stderr, "No generations?: %v\n", err) os.Exit(3) } - pushChecksum(ck, checksums) - ticks := time.Tick(time.Duration(*sleepMs) * time.Millisecond) - generations := 0 - for now := range ticks { - fmt.Printf("\nGeneration %v\n%v\n", generations, now) + sleepInterval := time.Duration(*sleepMs * 1000 * 1000) + for genTick := range genTicks { + fmt.Printf("\nGeneration %v\n%v\n", genTick.N, time.Now()) fmt.Println(game) game.EvaluateGeneration() - curChecksum, err := game.Checksum() - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to calculate current game checksum: %v\n", err) + if genTick.Error != nil { + fmt.Fprintf(os.Stderr, "%s: %s\n", genTick.Message, genTick.Error) os.Exit(4) } - if checksums[0] == curChecksum || checksums[1] == curChecksum { - fmt.Println("Stasis!") - os.Exit(0) - } - - if checksums[2] == curChecksum { - fmt.Println("Checksum found 2 periods ago") - fmt.Println("Stasis with 2-period oscillator(s)!") - os.Exit(0) + if len(genTick.Message) > 0 { + fmt.Println(genTick.Message) } - 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 { + if *mutate && genTick.N%2 == 0 { game.Mutate() } - generations++ + time.Sleep(sleepInterval) } } diff --git a/conway/game_of_life.go b/conway/game_of_life.go index 841545b..e8cd891 100644 --- a/conway/game_of_life.go +++ b/conway/game_of_life.go @@ -117,3 +117,86 @@ func (game *GameOfLife) ImportRandomState() error { func (game *GameOfLife) String() string { 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] +} diff --git a/conway/generation_tick.go b/conway/generation_tick.go new file mode 100644 index 0000000..af25e9e --- /dev/null +++ b/conway/generation_tick.go @@ -0,0 +1,7 @@ +package conway + +type GenerationTick struct { + N int + Error error + Message string +}