diff --git a/conway/console.go b/conway/console.go new file mode 100644 index 0000000..57a1673 --- /dev/null +++ b/conway/console.go @@ -0,0 +1,47 @@ +package conway + +import ( + "fmt" + "math/rand" + "time" +) + +func init() { + rand.Seed(time.Now().UTC().UnixNano()) +} + +func RunConsoleGame(height, width, sleepMs int, mutate bool) (int, error) { + sleepInterval := time.Duration(sleepMs * 1000 * 1000) + + game := NewGameOfLife(height, width) + err := game.ImportRandomState() + if err != nil { + return 2, err + } + + genTicks, err := game.Generations() + if err != nil { + return 3, err + } + + for genTick := range genTicks { + fmt.Printf("\nGeneration %v\n%v\n", genTick.N, time.Now()) + fmt.Println(game) + + if genTick.Error != nil { + return 4, genTick.Error + } + + if len(genTick.Message) > 0 { + fmt.Println(genTick.Message) + } + + if mutate && genTick.N%2 == 0 { + game.Mutate() + } + + time.Sleep(sleepInterval) + } + + return 0, nil +} diff --git a/conway/conway_test.go b/conway/conway_test.go index f8cd8f2..0bf5c3c 100644 --- a/conway/conway_test.go +++ b/conway/conway_test.go @@ -91,7 +91,7 @@ func TestDeadCellWithExactlyThreeLiveNeighborsBecomesAlive(t *testing.T) { } } -func TestGameOfLifeCanDisplayItself(t *testing.T) { +func TestGameOfLifeCanDisplayItselfAsAString(t *testing.T) { game := newTestGameOfLife() grid := fmt.Sprintf("%s\n", game) @@ -103,6 +103,10 @@ func TestGameOfLifeCanDisplayItself(t *testing.T) { } } +func TestGameOfLifeCanDisplayItselfAsAnImage(t *testing.T) { + t.Fail() +} + func TestNewGameOfLifeHasCorrectDimensions(t *testing.T) { game := newTestGameOfLife() @@ -172,7 +176,7 @@ func TestGameOfLifeCanImportRandomState(t *testing.T) { } } -func TestGameStateCanDisplayItself(t *testing.T) { +func TestGameStateCanDisplayItselfAsAString(t *testing.T) { state := newTestGameState() grid := fmt.Sprintf("%s\n", state) @@ -190,6 +194,27 @@ func TestGameStateCanDisplayItself(t *testing.T) { } } +func TestGameStateCanDisplayItselfAsAnImage(t *testing.T) { + state := newTestGameState() + + img, err := state.Image(1, 1) + if err != nil { + t.Error(err) + return + } + + bounds := img.Bounds() + if bounds.Max.Y < 16 { + t.Errorf("image.Max.Y < 16!: %d", bounds.Max.Y) + return + } + + if bounds.Max.X < 16 { + t.Errorf("image.Max.X < 16!: %d", bounds.Max.X) + return + } +} + func TestNewGameStatesAreAllDead(t *testing.T) { state := NewGameState(4, 4) for x := 0; x < 3; x++ { diff --git a/conway/conways-game-of-life/main.go b/conway/conways-game-of-life/main.go index bc0bc01..8aef411 100644 --- a/conway/conways-game-of-life/main.go +++ b/conway/conways-game-of-life/main.go @@ -14,6 +14,7 @@ var ( height = flag.Int("height", 40, "Game height") width = flag.Int("width", 80, "Game width") mutate = flag.Bool("mutate", false, "Mutate every other generation") + web = flag.Bool("web", false, "Run server for web-based game") sleepMs = flag.Int("sleep.ms", 200, "Millisecond sleep interval per generation") ) @@ -21,9 +22,21 @@ var ( func main() { flag.Parse() - retCode, err := RunConsoleGame(*height, *width, *sleepMs, *mutate) - if err != nil { - fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) + var ( + retCode int + err error + ) + + if *web { + retCode, err = RunWebGame(*height, *width, *sleepMs, *mutate) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) + } + } else { + retCode, err = RunConsoleGame(*height, *width, *sleepMs, *mutate) + if err != nil { + fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) + } } os.Exit(retCode) diff --git a/conway/game_of_life.go b/conway/game_of_life.go index 8b85256..b6acbe8 100644 --- a/conway/game_of_life.go +++ b/conway/game_of_life.go @@ -3,54 +3,14 @@ package conway import ( "errors" "fmt" + "image" "math/rand" - "time" ) -func init() { - rand.Seed(time.Now().UTC().UnixNano()) -} - type GameOfLife struct { State *GameState } -func RunConsoleGame(height, width, sleepMs int, mutate bool) (int, error) { - sleepInterval := time.Duration(sleepMs * 1000 * 1000) - - game := NewGameOfLife(height, width) - err := game.ImportRandomState() - if err != nil { - return 2, err - } - - genTicks, err := game.Generations() - if err != nil { - return 3, err - } - - for genTick := range genTicks { - fmt.Printf("\nGeneration %v\n%v\n", genTick.N, time.Now()) - fmt.Println(game) - - if genTick.Error != nil { - return 4, genTick.Error - } - - if len(genTick.Message) > 0 { - fmt.Println(genTick.Message) - } - - if mutate && genTick.N%2 == 0 { - game.Mutate() - } - - time.Sleep(sleepInterval) - } - - return 0, nil -} - func (game *GameOfLife) Mutate() { game.State.Mutate() } @@ -142,6 +102,10 @@ func (game *GameOfLife) String() string { return fmt.Sprintf("%s\n", game.State) } +func (game *GameOfLife) Image(xMult, yMult int) (*image.Gray16, error) { + return game.State.Image(xMult, yMult) +} + func (game *GameOfLife) emitGenerations(genTicks chan *GenerationTick) { defer close(genTicks) n := 0 diff --git a/conway/game_state.go b/conway/game_state.go index d281be3..5d86872 100644 --- a/conway/game_state.go +++ b/conway/game_state.go @@ -4,6 +4,7 @@ import ( "crypto/sha1" "errors" "fmt" + "image" "math" "math/rand" "strings" @@ -173,3 +174,7 @@ func (state *GameState) String() string { } return strings.Join(rows, "\n") } + +func (state *GameState) Image(xMult, yMult int) (*image.Gray16, error) { + return nil, errors.New("Not implemented!") +} diff --git a/conway/web.go b/conway/web.go new file mode 100644 index 0000000..a08cb7d --- /dev/null +++ b/conway/web.go @@ -0,0 +1,14 @@ +package conway + +import ( + "math/rand" + "time" +) + +func init() { + rand.Seed(time.Now().UTC().UnixNano()) +} + +func RunWebGame(height, width, sleepMs int, mutate bool) (int, error) { + return -1, nil +}