Too much crap for one commit

Breaking out console runner into its own file, adding an empty web
runner, and starting to test that games and game states are able to
represent themselves as images.
This commit is contained in:
Dan Buch 2012-12-16 17:59:54 -05:00
parent 3bfa23fff2
commit 3e013ce1a5
6 changed files with 114 additions and 46 deletions

47
conway/console.go Normal file
View File

@ -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
}

View File

@ -91,7 +91,7 @@ func TestDeadCellWithExactlyThreeLiveNeighborsBecomesAlive(t *testing.T) {
} }
} }
func TestGameOfLifeCanDisplayItself(t *testing.T) { func TestGameOfLifeCanDisplayItselfAsAString(t *testing.T) {
game := newTestGameOfLife() game := newTestGameOfLife()
grid := fmt.Sprintf("%s\n", game) 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) { func TestNewGameOfLifeHasCorrectDimensions(t *testing.T) {
game := newTestGameOfLife() game := newTestGameOfLife()
@ -172,7 +176,7 @@ func TestGameOfLifeCanImportRandomState(t *testing.T) {
} }
} }
func TestGameStateCanDisplayItself(t *testing.T) { func TestGameStateCanDisplayItselfAsAString(t *testing.T) {
state := newTestGameState() state := newTestGameState()
grid := fmt.Sprintf("%s\n", state) 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) { func TestNewGameStatesAreAllDead(t *testing.T) {
state := NewGameState(4, 4) state := NewGameState(4, 4)
for x := 0; x < 3; x++ { for x := 0; x < 3; x++ {

View File

@ -14,6 +14,7 @@ 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") 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, sleepMs = flag.Int("sleep.ms", 200,
"Millisecond sleep interval per generation") "Millisecond sleep interval per generation")
) )
@ -21,9 +22,21 @@ var (
func main() { func main() {
flag.Parse() flag.Parse()
retCode, err := RunConsoleGame(*height, *width, *sleepMs, *mutate) var (
if err != nil { retCode int
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) 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) os.Exit(retCode)

View File

@ -3,54 +3,14 @@ package conway
import ( import (
"errors" "errors"
"fmt" "fmt"
"image"
"math/rand" "math/rand"
"time"
) )
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
type GameOfLife struct { type GameOfLife struct {
State *GameState 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() { func (game *GameOfLife) Mutate() {
game.State.Mutate() game.State.Mutate()
} }
@ -142,6 +102,10 @@ func (game *GameOfLife) String() string {
return fmt.Sprintf("%s\n", game.State) 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) { func (game *GameOfLife) emitGenerations(genTicks chan *GenerationTick) {
defer close(genTicks) defer close(genTicks)
n := 0 n := 0

View File

@ -4,6 +4,7 @@ import (
"crypto/sha1" "crypto/sha1"
"errors" "errors"
"fmt" "fmt"
"image"
"math" "math"
"math/rand" "math/rand"
"strings" "strings"
@ -173,3 +174,7 @@ func (state *GameState) String() string {
} }
return strings.Join(rows, "\n") return strings.Join(rows, "\n")
} }
func (state *GameState) Image(xMult, yMult int) (*image.Gray16, error) {
return nil, errors.New("Not implemented!")
}

14
conway/web.go Normal file
View File

@ -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
}