Removing now-extracted conway subtree
This commit is contained in:
parent
e427f23c90
commit
4107485591
1
conway/.gitignore
vendored
1
conway/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/web_assets/web_assets
|
@ -1,24 +0,0 @@
|
||||
LIBS := \
|
||||
github.com/meatballhat/box-o-sand/conway
|
||||
TARGETS := \
|
||||
$(LIBS) \
|
||||
github.com/meatballhat/box-o-sand/conway/conways-game-of-life
|
||||
|
||||
all: test
|
||||
|
||||
test: build
|
||||
go test -x -v -test.parallel=4 $(LIBS)
|
||||
|
||||
build: web_assets.go deps
|
||||
go install -x $(TARGETS)
|
||||
|
||||
web_assets.go: $(wildcard web_assets/*.*)
|
||||
./gen-web-assets
|
||||
|
||||
clean:
|
||||
go clean -x -i $(TARGETS)
|
||||
|
||||
deps:
|
||||
go get -n -x $(TARGETS)
|
||||
|
||||
.PHONY: all build clean deps test
|
@ -1,47 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,593 +0,0 @@
|
||||
package conway_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"image/png"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
import (
|
||||
. "github.com/meatballhat/box-o-sand/conway"
|
||||
)
|
||||
|
||||
var TEST_SIMPLE_INITIAL_STATE = NewGameState(16, 16)
|
||||
|
||||
func init() {
|
||||
s := TEST_SIMPLE_INITIAL_STATE
|
||||
s.Set(0, 0, 1)
|
||||
s.Set(0, 1, 1)
|
||||
s.Set(0, 2, 1)
|
||||
s.Set(1, 0, 1)
|
||||
s.Set(1, 1, 1)
|
||||
s.Set(2, 2, 1)
|
||||
s.Set(3, 0, 1)
|
||||
s.Set(3, 2, 1)
|
||||
s.Set(13, 13, 1)
|
||||
s.Set(13, 14, 1)
|
||||
s.Set(14, 14, 1)
|
||||
s.Set(14, 15, 1)
|
||||
s.Set(15, 13, 1)
|
||||
s.Set(15, 15, 1)
|
||||
}
|
||||
|
||||
func newTestGameState() *GameState {
|
||||
state := NewGameState(16, 16)
|
||||
state.Import(TEST_SIMPLE_INITIAL_STATE)
|
||||
return state
|
||||
}
|
||||
|
||||
func newTestGameOfLife() *GameOfLife {
|
||||
game := NewGameOfLife(16, 16)
|
||||
game.State.Import(TEST_SIMPLE_INITIAL_STATE)
|
||||
return game
|
||||
}
|
||||
|
||||
func TestLiveCellWithFewerThanTwoLiveNeighborsDies(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
game.EvaluateGeneration()
|
||||
|
||||
cell := game.State.Get(3, 2)
|
||||
if cell.Value != 0 {
|
||||
t.Errorf("%v != 0", cell.Value)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestLiveCellWithTwoOrThreeLiveNeighborsLivesOn(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
game.EvaluateGeneration()
|
||||
|
||||
cell := game.State.Get(0, 2)
|
||||
if cell.Value != 1 {
|
||||
t.Errorf("%v != 1", cell.Value)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestLiveCellWithMoreThanThreeLiveNeighborsDies(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
game.EvaluateGeneration()
|
||||
|
||||
cell := game.State.Get(0, 1)
|
||||
if cell.Value != 0 {
|
||||
t.Errorf("%v != 0", cell.Value)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeadCellWithExactlyThreeLiveNeighborsBecomesAlive(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
game.EvaluateGeneration()
|
||||
|
||||
cell := game.State.Get(3, 1)
|
||||
if cell.Value != 1 {
|
||||
t.Errorf("%v != 1", cell.Value)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameOfLifeCanDisplayItselfAsAString(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
grid := fmt.Sprintf("%s\n", game)
|
||||
|
||||
gridLen := len(grid)
|
||||
if gridLen < 256 {
|
||||
t.Errorf("%v < 256", gridLen)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameOfLifeCanDisplayItselfAsAnImage(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
img, err := game.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 TestNewGameOfLifeHasCorrectDimensions(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
if game.State.Height() != 16 || game.State.Width() != 16 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewGameOfLifeHasGameStateOfSameDimensions(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
if len(game.State.Rows) < 16 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if len(game.State.Rows[0].Cells) < 16 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameStateCanImportState(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
if game.State.Get(0, 0).Value != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if game.State.Get(1, 0).Value != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if game.State.Get(0, 1).Value != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if game.State.Get(1, 1).Value != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if game.State.Get(2, 2).Value != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameOfLifeCanImportRandomState(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
err := game.ImportRandomState()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
zeroCount := 0
|
||||
|
||||
for y := 0; y < 16; y++ {
|
||||
for x := 0; x < 16; x++ {
|
||||
cell := game.State.Get(x, y)
|
||||
if cell.Value == 0 {
|
||||
zeroCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if zeroCount == 256 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameStateCanDisplayItselfAsAString(t *testing.T) {
|
||||
state := newTestGameState()
|
||||
|
||||
grid := fmt.Sprintf("%s\n", state)
|
||||
lenGrid := len(grid)
|
||||
|
||||
if lenGrid < 256 {
|
||||
t.Errorf("%v < 256", lenGrid)
|
||||
return
|
||||
}
|
||||
|
||||
nLines := strings.Count(grid, "\n")
|
||||
if nLines < 16 {
|
||||
t.Errorf("%v < 16 (lines)", nLines)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
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++ {
|
||||
for y := 0; y < 3; y++ {
|
||||
if state.Get(x, y).Value != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameStateCanGetCellValueByCoords(t *testing.T) {
|
||||
state := NewGameState(8, 8)
|
||||
if state.Get(2, 2).Value != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameStateCanSetCellValueByCoords(t *testing.T) {
|
||||
state := NewGameState(8, 8)
|
||||
state.Set(2, 5, 1)
|
||||
|
||||
if state.Get(2, 5).Value != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameStateCanEnlivenCellsByCoords(t *testing.T) {
|
||||
state := NewGameState(8, 8)
|
||||
state.Enliven(0, 1)
|
||||
|
||||
if state.Get(0, 1).Value != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameStateCanDeadenCellsByCoords(t *testing.T) {
|
||||
state := NewGameState(8, 8)
|
||||
|
||||
state.Enliven(0, 1)
|
||||
|
||||
if state.Get(0, 1).Value != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
state.Deaden(0, 1)
|
||||
|
||||
if state.Get(0, 1).Value != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewGenerationScoreCardIsAllZeros(t *testing.T) {
|
||||
gen := NewGenerationScoreCard(4, 4)
|
||||
|
||||
for y := 0; y < gen.Height(); y++ {
|
||||
for x := 0; x < gen.Width(); x++ {
|
||||
if gen.Get(x, y).Value != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerationScoreCardCalculateResultsInCorrectNeighborCounts(t *testing.T) {
|
||||
genScore := NewGenerationScoreCard(16, 16)
|
||||
|
||||
state := newTestGameState()
|
||||
|
||||
genScore.Calculate(state)
|
||||
|
||||
cell := genScore.Get(0, 0)
|
||||
if cell.Value != 4 {
|
||||
t.Errorf("[0, 0] value %v != 4", cell.Value)
|
||||
return
|
||||
}
|
||||
|
||||
cell = genScore.Get(3, 2)
|
||||
if cell.Value != 1 {
|
||||
t.Errorf("[3, 2] value %d != 1", cell.Value)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateCanMutate(t *testing.T) {
|
||||
state := newTestGameState()
|
||||
|
||||
curCksum, err := state.Checksum()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
state.Mutate()
|
||||
|
||||
newCksum, err := state.Checksum()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if curCksum == newCksum {
|
||||
t.Errorf("Checksum did not change! %v", newCksum)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateProvidesCellIteratorChannel(t *testing.T) {
|
||||
state := newTestGameState()
|
||||
|
||||
cells, err := state.Cells()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
cellCount := 0
|
||||
for _ = range cells {
|
||||
cellCount++
|
||||
}
|
||||
|
||||
if cellCount != 256 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameStateCellsCanHaveTheirValueSet(t *testing.T) {
|
||||
state := newTestGameState()
|
||||
|
||||
cells, err := state.Cells()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
for cell := range cells {
|
||||
cell.Value = 1
|
||||
}
|
||||
|
||||
cells, err = state.Cells()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
for cell := range cells {
|
||||
if cell.Value != 1 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameStateCellsCanBeFetchedByXAndYCoords(t *testing.T) {
|
||||
state := newTestGameState()
|
||||
|
||||
if state.Get(3, 4) == nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameOfLifeEmitsGenerationTicksUntilStasis(t *testing.T) {
|
||||
game := newTestGameOfLife()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGameStateCoordsAreNeverOutOfBounds(t *testing.T) {
|
||||
state := newTestGameState()
|
||||
|
||||
oobX, oobY := state.Width()+rand.Intn(99), state.Height()+rand.Intn(99)
|
||||
|
||||
newVal := rand.Intn(9999)
|
||||
|
||||
state.Set(oobX, oobY, newVal)
|
||||
cell := state.Get(oobX, oobY)
|
||||
|
||||
if cell == nil {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if cell.Value != newVal {
|
||||
t.Errorf("(%d, %d) != %d: %d", oobX, oobY, newVal, cell.Value)
|
||||
}
|
||||
}
|
||||
|
||||
type testResponseWriter struct {
|
||||
Status int
|
||||
Headers http.Header
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func (w *testResponseWriter) WriteHeader(status int) {
|
||||
w.Status = status
|
||||
}
|
||||
|
||||
func (w *testResponseWriter) Header() http.Header {
|
||||
return w.Headers
|
||||
}
|
||||
|
||||
func (w *testResponseWriter) Write(bytes []byte) (int, error) {
|
||||
w.Body = append(w.Body, bytes[:]...)
|
||||
return len(bytes), nil
|
||||
}
|
||||
|
||||
func newTestResponseWriter() *testResponseWriter {
|
||||
return &testResponseWriter{
|
||||
Body: []byte(""),
|
||||
Headers: make(map[string][]string),
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleWebGameRootReturnsIndexPageForGET(t *testing.T) {
|
||||
req, err := http.NewRequest("GET", "http://localhost:9775/", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
w := newTestResponseWriter()
|
||||
HandleWebGameRoot(w, req)
|
||||
|
||||
if w.Status != http.StatusOK {
|
||||
t.Errorf("response status != %d: %d", http.StatusOK, w.Status)
|
||||
return
|
||||
}
|
||||
|
||||
matched, err := regexp.MatchString("<h1>Conway's Game of Life</h1>", string(w.Body))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !matched {
|
||||
t.Errorf("Body did not match expected <h1> element")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleWebGameRootReturns405ForNonGET(t *testing.T) {
|
||||
req, err := http.NewRequest("OPTIONS", "http://localhost:9775/", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
w := newTestResponseWriter()
|
||||
HandleWebGameRoot(w, req)
|
||||
|
||||
if w.Status != http.StatusMethodNotAllowed {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
matched, err := regexp.MatchString("Nope", string(w.Body))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if !matched {
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleWebGameStateGETReturnsRandomImage(t *testing.T) {
|
||||
req, err := http.NewRequest("GET", "http://localhost:9775/state", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
w := newTestResponseWriter()
|
||||
HandleWebGameState(w, req)
|
||||
|
||||
if w.Status != http.StatusOK {
|
||||
t.Errorf("status != %d: %d", http.StatusOK, w.Status)
|
||||
return
|
||||
}
|
||||
|
||||
webState := &WebGameState{}
|
||||
err = json.Unmarshal(w.Body, webState)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
imgB64 := []byte(webState.Img)
|
||||
imgBytes := make([]byte, len(imgB64))
|
||||
|
||||
_, err = base64.StdEncoding.Decode(imgBytes, imgB64)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
img, err := png.Decode(bytes.NewBuffer(imgBytes))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
bounds := img.Bounds()
|
||||
|
||||
if bounds.Max.Y < 80 || bounds.Max.X < 80 {
|
||||
t.Errorf("Image has incorrect bounds: %+v", bounds)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleWebGameStatePOSTWithStateReturnsNextGeneration(t *testing.T) {
|
||||
state := newTestGameState()
|
||||
webGameState := &WebGameState{State: state, Img: ""}
|
||||
|
||||
stateJson, err := json.Marshal(webGameState)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
reqBuf := bytes.NewBuffer(stateJson)
|
||||
|
||||
req, err := http.NewRequest("POST", "http://localhost:9975/state", reqBuf)
|
||||
if err != nil {
|
||||
t.Errorf("err != nil: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
w := newTestResponseWriter()
|
||||
HandleWebGameState(w, req)
|
||||
|
||||
if w.Status != http.StatusCreated {
|
||||
t.Errorf("response status != %d: %d", http.StatusCreated, w.Status)
|
||||
return
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
import (
|
||||
. "github.com/meatballhat/box-o-sand/conway"
|
||||
)
|
||||
|
||||
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 a web-based game.")
|
||||
addr = flag.String("addr", ":9775",
|
||||
"Address for server of web-based game (ignored if running a console game.)")
|
||||
sleepMs = flag.Int("sleep.ms", 200,
|
||||
"Millisecond sleep interval per generation")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
var (
|
||||
retCode int
|
||||
err error
|
||||
)
|
||||
|
||||
if *web {
|
||||
retCode, err = RunWebGame(*addr, *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)
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
/*
|
||||
Conway's Game of Life in Go (console and web.)
|
||||
*/
|
||||
package conway
|
@ -1,190 +0,0 @@
|
||||
package conway
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
type GameOfLife struct {
|
||||
State *GameState
|
||||
}
|
||||
|
||||
func (game *GameOfLife) Mutate() {
|
||||
game.State.Mutate()
|
||||
}
|
||||
|
||||
func (game *GameOfLife) Checksum() (string, error) {
|
||||
return game.State.Checksum()
|
||||
}
|
||||
|
||||
func NewGameOfLife(height, width int) *GameOfLife {
|
||||
return &GameOfLife{
|
||||
State: NewGameState(height, width),
|
||||
}
|
||||
}
|
||||
|
||||
func (game *GameOfLife) EvaluateGeneration() error {
|
||||
height, width := game.State.Height(), game.State.Width()
|
||||
|
||||
genScore := NewGenerationScoreCard(height, width)
|
||||
genScore.Calculate(game.State)
|
||||
|
||||
cells, err := genScore.Cells()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for cell := range cells {
|
||||
score := cell.Value
|
||||
|
||||
cell := game.State.Get(cell.X, cell.Y)
|
||||
|
||||
if cell.Value == 1 {
|
||||
if score < 2 {
|
||||
game.State.Deaden(cell.X, cell.Y)
|
||||
continue
|
||||
}
|
||||
|
||||
if score == 2 || score == 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
if score > 3 {
|
||||
game.State.Deaden(cell.X, cell.Y)
|
||||
continue
|
||||
}
|
||||
} else if cell.Value == 0 {
|
||||
|
||||
if score == 3 {
|
||||
game.State.Enliven(cell.X, cell.Y)
|
||||
continue
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (game *GameOfLife) ImportState(state *GameState) {
|
||||
game.State.Import(state)
|
||||
}
|
||||
|
||||
func (game *GameOfLife) ImportRandomState() error {
|
||||
height := game.State.Height()
|
||||
width := game.State.Width()
|
||||
|
||||
if height < 0 || width < 0 {
|
||||
errStr := fmt.Sprintf("current game has invalid dimensions! %vx%v",
|
||||
height, width)
|
||||
return errors.New(errStr)
|
||||
}
|
||||
|
||||
randState := NewGameState(height, width)
|
||||
|
||||
cells, err := randState.Cells()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for cell := range cells {
|
||||
cell.Value = rand.Intn(2)
|
||||
}
|
||||
|
||||
game.ImportState(randState)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (game *GameOfLife) String() string {
|
||||
return fmt.Sprintf("%s\n", game.State)
|
||||
}
|
||||
|
||||
func (game *GameOfLife) Image(xMult, yMult int) (*image.Gray, error) {
|
||||
return game.State.Image(xMult, yMult)
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
@ -1,206 +0,0 @@
|
||||
package conway
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
deadCell = "■"
|
||||
liveCell = " "
|
||||
)
|
||||
|
||||
type GameStateCell struct {
|
||||
Value int `json:"v"`
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
}
|
||||
|
||||
type GameStateRow struct {
|
||||
Y int `json:"y"`
|
||||
Cells []*GameStateCell `json:"c"`
|
||||
}
|
||||
|
||||
type GameState struct {
|
||||
Rows []*GameStateRow `json:"r"`
|
||||
}
|
||||
|
||||
func NewGameState(height, width int) *GameState {
|
||||
state := &GameState{}
|
||||
for i := 0; i < height; i++ {
|
||||
row := &GameStateRow{Y: i}
|
||||
for j := 0; j < width; j++ {
|
||||
row.Cells = append(row.Cells, &GameStateCell{
|
||||
Value: 0,
|
||||
X: j,
|
||||
Y: i,
|
||||
})
|
||||
}
|
||||
state.Rows = append(state.Rows, row)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func (state *GameState) Height() int {
|
||||
return len(state.Rows)
|
||||
}
|
||||
|
||||
func (state *GameState) Width() int {
|
||||
if len(state.Rows) < 1 {
|
||||
return -1
|
||||
}
|
||||
return len(state.Rows[0].Cells)
|
||||
}
|
||||
|
||||
func (state *GameState) GetRow(y int) *GameStateRow {
|
||||
lenRows := len(state.Rows)
|
||||
|
||||
if y < 0 {
|
||||
return state.GetRow(lenRows + y)
|
||||
}
|
||||
|
||||
if y+1 > lenRows {
|
||||
return state.GetRow(y % lenRows)
|
||||
}
|
||||
|
||||
return state.Rows[y]
|
||||
}
|
||||
|
||||
func (state *GameState) Set(x, y, value int) {
|
||||
cell := state.Get(x, y)
|
||||
cell.Value = value
|
||||
}
|
||||
|
||||
func (state *GameState) Get(x, y int) *GameStateCell {
|
||||
row := state.GetRow(y)
|
||||
lenCells := len(row.Cells)
|
||||
|
||||
if x < 0 {
|
||||
return state.Get(lenCells+x, row.Y)
|
||||
}
|
||||
|
||||
if x+1 > lenCells {
|
||||
return state.Get(x%lenCells, row.Y)
|
||||
}
|
||||
|
||||
return row.Cells[x]
|
||||
}
|
||||
|
||||
func (state *GameState) Enliven(x, y int) {
|
||||
state.Set(x, y, 1)
|
||||
}
|
||||
|
||||
func (state *GameState) Deaden(x, y int) {
|
||||
state.Set(x, y, 0)
|
||||
}
|
||||
|
||||
func (state *GameState) Import(other *GameState) {
|
||||
for y, row := range other.Rows {
|
||||
for x, cell := range row.Cells {
|
||||
state.Set(x, y, cell.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (state *GameState) Cells() (<-chan *GameStateCell, error) {
|
||||
height := state.Height()
|
||||
width := state.Width()
|
||||
|
||||
if height < 0 || width < 0 {
|
||||
return nil, errors.New("state has invalid dimensions!")
|
||||
}
|
||||
|
||||
cells := make(chan *GameStateCell)
|
||||
|
||||
go func(state *GameState, c chan *GameStateCell) {
|
||||
defer close(c)
|
||||
height := state.Height()
|
||||
width := state.Width()
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
c <- state.Get(x, y)
|
||||
}
|
||||
}
|
||||
}(state, cells)
|
||||
|
||||
return (<-chan *GameStateCell)(cells), nil
|
||||
}
|
||||
|
||||
func (state *GameState) Mutate() {
|
||||
randX := rand.Intn(state.Width())
|
||||
randY := rand.Intn(state.Height())
|
||||
|
||||
cell := state.Get(randX, randY)
|
||||
state.Set(randX, randY, int(math.Abs(float64(cell.Value-1))))
|
||||
}
|
||||
|
||||
func (state *GameState) Checksum() (string, error) {
|
||||
ck := sha1.New()
|
||||
cells, err := state.Cells()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for cell := range cells {
|
||||
fmt.Fprintf(ck, "%v", cell.Value)
|
||||
}
|
||||
return fmt.Sprintf("%x", ck.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func (state *GameState) String() string {
|
||||
var rows []string
|
||||
|
||||
height := state.Height()
|
||||
width := state.Width()
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
var cells []string
|
||||
for x := 0; x < width; x++ {
|
||||
stringVal := deadCell
|
||||
|
||||
cell := state.Get(x, y)
|
||||
if cell.Value == 1 {
|
||||
stringVal = liveCell
|
||||
}
|
||||
cells = append(cells, stringVal)
|
||||
}
|
||||
rows = append(rows, strings.Join(cells, ""))
|
||||
}
|
||||
return strings.Join(rows, "\n")
|
||||
}
|
||||
|
||||
func (state *GameState) Image(xMult, yMult int) (*image.Gray, error) {
|
||||
img := image.NewGray(image.Rect(0, 0,
|
||||
(state.Height()*xMult)+1, (state.Width()*yMult)+1))
|
||||
draw.Draw(img, img.Bounds(), &image.Uniform{color.Gray16{0xff}},
|
||||
image.ZP, draw.Src)
|
||||
|
||||
cells, err := state.Cells()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
black := &image.Uniform{color.Black}
|
||||
white := &image.Uniform{color.White}
|
||||
|
||||
for cell := range cells {
|
||||
color := white
|
||||
if cell.Value == 1 {
|
||||
color = black
|
||||
}
|
||||
|
||||
square := image.Rect((cell.X*xMult)+1, (cell.Y*yMult)+1,
|
||||
(cell.X*xMult)+xMult, (cell.Y*yMult)+yMult)
|
||||
draw.Draw(img, square, color, image.ZP, draw.Src)
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
"shell")
|
||||
cat > _tmp.go <<EOWEBASSETSGO
|
||||
// WARNING: GENERATED FILE, NERDS! $(date)
|
||||
package conway
|
||||
|
||||
const (
|
||||
gameOfLifeIndexHtml = \`
|
||||
$(cat web_assets/index.html | gzip -9 | base64)\`
|
||||
normalizeCss = \`
|
||||
$(curl -s http://necolas.github.com/normalize.css/2.0.1/normalize.css | gzip -9 | base64)\`
|
||||
jqueryMinJs = \`
|
||||
$(curl -s http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js | gzip -9 | base64)\`
|
||||
)
|
||||
EOWEBASSETSGO
|
||||
cat _tmp.go | gofmt > web_assets.go
|
||||
rm -v _tmp.go
|
||||
;;
|
||||
*)
|
||||
cd web_assets
|
||||
go build -x .
|
||||
./web_assets index.html > _tmp.go
|
||||
gofmt < _tmp.go > ../web_assets.go
|
||||
rm -vf _tmp.go
|
||||
;;
|
||||
esac
|
@ -1,62 +0,0 @@
|
||||
package conway
|
||||
|
||||
var (
|
||||
neighbors = []neighbor{
|
||||
neighbor{-1, -1},
|
||||
neighbor{-1, 0},
|
||||
neighbor{-1, 1},
|
||||
neighbor{0, -1},
|
||||
neighbor{0, 1},
|
||||
neighbor{1, -1},
|
||||
neighbor{1, 0},
|
||||
neighbor{1, 1},
|
||||
}
|
||||
)
|
||||
|
||||
type GenerationScoreCard struct {
|
||||
GameState
|
||||
}
|
||||
|
||||
type neighbor struct {
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func NewGenerationScoreCard(height, width int) *GenerationScoreCard {
|
||||
genScore := &GenerationScoreCard{}
|
||||
for i := 0; i < height; i++ {
|
||||
row := &GameStateRow{Y: i}
|
||||
for j := 0; j < width; j++ {
|
||||
row.Cells = append(row.Cells, &GameStateCell{
|
||||
Value: 0,
|
||||
X: j,
|
||||
Y: i,
|
||||
})
|
||||
}
|
||||
genScore.Rows = append(genScore.Rows, row)
|
||||
}
|
||||
return genScore
|
||||
}
|
||||
|
||||
func (genScore *GenerationScoreCard) Calculate(state *GameState) error {
|
||||
stateCells, err := state.Cells()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for stateCell := range stateCells {
|
||||
if stateCell.Value == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, neighbor := range neighbors {
|
||||
xTarget := stateCell.X + neighbor.X
|
||||
yTarget := stateCell.Y + neighbor.Y
|
||||
|
||||
cell := genScore.Get(xTarget, yTarget)
|
||||
genScore.Set(xTarget, yTarget, cell.Value+1)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package conway
|
||||
|
||||
type GenerationTick struct {
|
||||
N int
|
||||
Error error
|
||||
Message string
|
||||
}
|
272
conway/web.go
272
conway/web.go
@ -1,272 +0,0 @@
|
||||
package conway
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/png"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WebGameParams struct {
|
||||
Height int
|
||||
Width int
|
||||
Xmul int
|
||||
Ymul int
|
||||
}
|
||||
|
||||
type WebGameState struct {
|
||||
State *GameState `json:"s"`
|
||||
Img string `json:"i"`
|
||||
}
|
||||
|
||||
type webAssetStrings struct {
|
||||
IndexHTML []byte
|
||||
NormalizeCSS []byte
|
||||
JqueryMinJS []byte
|
||||
}
|
||||
|
||||
var WebAssets webAssetStrings
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
idxHt, err := fromGzB64(gameOfLifeIndexHtml)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to decode internal index.html: ", err)
|
||||
}
|
||||
|
||||
WebAssets.IndexHTML = idxHt
|
||||
|
||||
normCss, err := fromGzB64(normalizeCss)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to decode internal normalize.css: ", err)
|
||||
}
|
||||
WebAssets.NormalizeCSS = normCss
|
||||
|
||||
jqmin, err := fromGzB64(jqueryMinJs)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to decode internal jquery.min.js: ", err)
|
||||
}
|
||||
WebAssets.JqueryMinJS = jqmin
|
||||
}
|
||||
|
||||
func fromGzB64(input string) ([]byte, error) {
|
||||
decoded, err := base64.StdEncoding.DecodeString(input)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(decoded)
|
||||
zReader, err := gzip.NewReader(buf)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
|
||||
defer zReader.Close()
|
||||
|
||||
gunzipped, err := ioutil.ReadAll(zReader)
|
||||
if err != nil {
|
||||
return []byte(""), err
|
||||
}
|
||||
|
||||
return gunzipped, nil
|
||||
}
|
||||
|
||||
func NewWebGameParams(q url.Values) *WebGameParams {
|
||||
params := &WebGameParams{
|
||||
Height: 50,
|
||||
Width: 50,
|
||||
Xmul: 10,
|
||||
Ymul: 10,
|
||||
}
|
||||
|
||||
h := q.Get("h")
|
||||
if len(h) > 0 {
|
||||
if i, err := strconv.Atoi(h); err == nil {
|
||||
params.Height = i
|
||||
}
|
||||
}
|
||||
|
||||
w := q.Get("w")
|
||||
if len(w) > 0 {
|
||||
if i, err := strconv.Atoi(w); err == nil {
|
||||
params.Width = i
|
||||
}
|
||||
}
|
||||
|
||||
xm := q.Get("xm")
|
||||
if len(xm) > 0 {
|
||||
if i, err := strconv.Atoi(xm); err == nil {
|
||||
params.Xmul = i
|
||||
}
|
||||
}
|
||||
|
||||
ym := q.Get("ym")
|
||||
if len(ym) > 0 {
|
||||
if i, err := strconv.Atoi(ym); err == nil {
|
||||
params.Ymul = i
|
||||
}
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
func handle405(method, uri string, w http.ResponseWriter) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
w.Write([]byte(fmt.Sprintf("Nope. %v not allowed at %v\n", method, uri)))
|
||||
}
|
||||
|
||||
func handle500(err error, w http.ResponseWriter) {
|
||||
log.Println("ERROR:", err)
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(fmt.Sprintf("We exploded!: %v\n", err)))
|
||||
}
|
||||
|
||||
func HandleWebGameRoot(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != "GET" {
|
||||
handle405(req.Method, req.RequestURI, w)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(WebAssets.IndexHTML)
|
||||
return
|
||||
}
|
||||
|
||||
func HandleWebGameStatic(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != "GET" {
|
||||
handle405(req.Method, req.RequestURI, w)
|
||||
return
|
||||
}
|
||||
|
||||
if req.URL.Path == "/static/normalize.css" {
|
||||
w.Header().Set("Content-Type", "text/css")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(WebAssets.NormalizeCSS)
|
||||
return
|
||||
}
|
||||
|
||||
if req.URL.Path == "/static/jquery.min.js" {
|
||||
w.Header().Set("Content-Type", "text/javascript")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(WebAssets.JqueryMinJS)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte(fmt.Sprintf("Don't have: %v\n", req.URL.Path)))
|
||||
}
|
||||
|
||||
func HandleWebGameState(w http.ResponseWriter, req *http.Request) {
|
||||
switch req.Method {
|
||||
case "GET":
|
||||
handleWebGameStateGET(w, req)
|
||||
return
|
||||
case "POST":
|
||||
handleWebGameStatePOST(w, req)
|
||||
return
|
||||
default:
|
||||
handle405(req.Method, req.RequestURI, w)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func handleWebGameStateGET(w http.ResponseWriter, req *http.Request) {
|
||||
q := req.URL.Query()
|
||||
params := NewWebGameParams(q)
|
||||
|
||||
game := NewGameOfLife(params.Height, params.Width)
|
||||
err := game.ImportRandomState()
|
||||
if err != nil {
|
||||
handle500(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
sendWebGameStateJSONPayload(w, http.StatusOK, game, params)
|
||||
}
|
||||
|
||||
func handleWebGameStatePOST(w http.ResponseWriter, req *http.Request) {
|
||||
q := req.URL.Query()
|
||||
params := NewWebGameParams(q)
|
||||
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r != nil {
|
||||
handle500(errors.New(fmt.Sprintf("OH NOES! %v", r)), w)
|
||||
}
|
||||
}()
|
||||
|
||||
body, err := ioutil.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
handle500(err, w)
|
||||
}
|
||||
|
||||
webGameState := &WebGameState{}
|
||||
err = json.Unmarshal(body, webGameState)
|
||||
if err != nil {
|
||||
handle500(err, w)
|
||||
}
|
||||
|
||||
height, width := webGameState.State.Height(), webGameState.State.Width()
|
||||
game := NewGameOfLife(height, width)
|
||||
game.ImportState(webGameState.State)
|
||||
|
||||
game.EvaluateGeneration()
|
||||
|
||||
sendWebGameStateJSONPayload(w, http.StatusCreated, game, params)
|
||||
}
|
||||
|
||||
func sendWebGameStateJSONPayload(w http.ResponseWriter, status int, game *GameOfLife, params *WebGameParams) {
|
||||
img, err := game.Image(params.Xmul, params.Ymul)
|
||||
|
||||
if err != nil {
|
||||
handle500(err, w)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("Serving state image.")
|
||||
|
||||
var pngBuf bytes.Buffer
|
||||
err = png.Encode(&pngBuf, img)
|
||||
if err != nil {
|
||||
handle500(err, w)
|
||||
}
|
||||
|
||||
imgB64 := base64.StdEncoding.EncodeToString(pngBuf.Bytes())
|
||||
webGameState := &WebGameState{State: game.State, Img: imgB64}
|
||||
wgsJson, err := json.Marshal(webGameState)
|
||||
|
||||
if err != nil {
|
||||
handle500(err, w)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
w.Write(wgsJson)
|
||||
}
|
||||
|
||||
func RunWebGame(address string, height, width, sleepMs int, mutate bool) (int, error) {
|
||||
http.HandleFunc("/", HandleWebGameRoot)
|
||||
http.HandleFunc("/state", HandleWebGameState)
|
||||
http.HandleFunc("/static/", HandleWebGameStatic)
|
||||
|
||||
fmt.Printf("Serving on %v\n", address)
|
||||
err := http.ListenAndServe(address, nil)
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
return 0, nil
|
||||
}
|
@ -1,646 +0,0 @@
|
||||
package conway
|
||||
|
||||
// WARNING: GENERATED FILE, NERDS! 2012-12-26 10:57:04.843003 -0500 EST
|
||||
|
||||
const (
|
||||
gameOfLifeIndexHtml = `
|
||||
H4sIAAAJbogC/5RV32/bNhB+719xUwJIxlQpCboBsRW/dMOWYWiDxAO2p4GRzjJdilTJU1ov8P8+
|
||||
Ur8tu0HjB1ni3X3f3cfjMfnhl4/vV//c/QobKsTyTdL8ASQbZJl7sa/ESeDyvZJf2M438BsrENQa
|
||||
/uRrTOLG2DgKLj8B7Uq88Qi/Upwa44FGceMZ2gk0G0TyYKNxfePFhhjxNJZKF0zw/zCqveMWyqSa
|
||||
lzQG27In1qx6YHQ6IGw/V6h3UcFltDXeMokbr+8BanwA0ko/WDCEG3jeL4bF2yK3S563eNOurSuZ
|
||||
ElcSSlVWwkbcSk6ciTo6mMFz6wdwHuVIfzx8/BD4daLohxY7BCXv2tB7NKWSBmcd4f6IJVcr9cHm
|
||||
3MDXMCEIpcpDplIZCvpvgJ5xtOZSiQxpLnO+3gXPZg61k01JVkKEcDUbu3cpBBkjFgK1SVQmhO3n
|
||||
v3+/Hyfgfk9MN3hWr+MSv4myOADhawim1TU/g7TiBaqKgj4z6/WCQAuwlf10cTGh2I++9uOC/a1R
|
||||
0u8XXtiUV5R3sEvWijILul4LwUVFZpRg33G1hQ8Gp+55XV1jPw/8s/rzX17k/gjBKdg7RgJlThtI
|
||||
4PJQ0QlUYkGAZ+6UtpDuHPqziJWlzXilgoEvVZIYl6j92Yh2UHUgZ0Q68O1JtY3vu4LmvGA5xqXM
|
||||
F4/M4M/vQh9+BJSpyvCv+9ugKXoMq5EqLVudjjbk/KAV+qDTJ3MAbWrB0taXCp5+eqmhur1y3TSB
|
||||
KIUdhq+AsO2hq0Og7m06sdysnI7RblI9qmw3KtbZ39rxmcs5pCgJ9ZFMZ/2WjeIKpnNuYy6AVaSG
|
||||
yr7wjDZzuLy4eld+XZykEbimY5JJdxxRvSVVzuHqcoxasiyz46gxXY8tj0pnqBuDDQGjBM/g7Pr6
|
||||
emBulXNi1RdW3N1YidOo1TLjT3Vn94n1Qiaby29dadbSOY3jtRLDPjiaisiOA2d2zeAt7+wziZvl
|
||||
036u77zlg31O/ZLYUh3RTlT1Tnj3rxaxrtvmX9/h/wcAAP//rQ2TxtsHAAA=`
|
||||
normalizeCss = `
|
||||
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`
|
||||
jqueryMinJs = `
|
||||
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
|
||||
f8vzG5z8/wAAAP//TQkipcVtAQA=`
|
||||
)
|
@ -1,183 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
const b64Width = 76
|
||||
|
||||
var (
|
||||
webAssetsTmpl = template.Must(template.New("web_assets").Parse("" +
|
||||
"package conway\n" +
|
||||
"// WARNING: GENERATED FILE, NERDS! {{.Now}}\n" +
|
||||
"\n" +
|
||||
"const (\n" +
|
||||
" gameOfLifeIndexHtml = `{{.IndexHTML}}`\n" +
|
||||
" normalizeCss = `{{.NormalizeCSS}}`\n" +
|
||||
" jqueryMinJs = `{{.JqueryMinJS}}`\n" +
|
||||
")\n"))
|
||||
normalizeCssUrl = "http://necolas.github.com/normalize.css/2.0.1/normalize.css"
|
||||
jqueryMinJsUrl = "http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"
|
||||
)
|
||||
|
||||
type webAssetStrings struct {
|
||||
IndexHTML string
|
||||
NormalizeCSS string
|
||||
JqueryMinJS string
|
||||
Now time.Time
|
||||
}
|
||||
|
||||
func die(err error) {
|
||||
log.Fatal("CRUD:", err)
|
||||
}
|
||||
|
||||
func toB64(input []byte) string {
|
||||
var (
|
||||
err error
|
||||
out bytes.Buffer
|
||||
)
|
||||
encoded := base64.StdEncoding.EncodeToString(input)
|
||||
lenEncoded := len(encoded)
|
||||
|
||||
outbuf := bufio.NewWriter(&out)
|
||||
inbuf := strings.NewReader(encoded)
|
||||
|
||||
outbuf.WriteByte('\n')
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
nWritten := 0
|
||||
for {
|
||||
for n := 0; n < b64Width; n++ {
|
||||
c, err := inbuf.ReadByte()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
err = outbuf.WriteByte(c)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
nWritten++
|
||||
}
|
||||
|
||||
_, err := inbuf.ReadByte()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
err = inbuf.UnreadByte()
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
err = outbuf.WriteByte('\n')
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
}
|
||||
|
||||
if nWritten != lenEncoded {
|
||||
die(errors.New(fmt.Sprintf("base64-encoded length = %d, but wrote %d",
|
||||
lenEncoded, nWritten)))
|
||||
}
|
||||
|
||||
outbuf.Flush()
|
||||
return string(out.Bytes())
|
||||
}
|
||||
|
||||
func toGz(input []byte) []byte {
|
||||
var buf bytes.Buffer
|
||||
|
||||
zwriter, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
zbuf := bufio.NewWriter(zwriter)
|
||||
|
||||
toWrite := len(input)
|
||||
for written := 0; written < toWrite; {
|
||||
n, err := zbuf.Write(input[written:])
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
written += n
|
||||
}
|
||||
|
||||
zbuf.Flush()
|
||||
zwriter.Close()
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
func fetchUrl(url string) []byte {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func fetchIndexHtml(indexHtmlPath string) []byte {
|
||||
fd, err := os.Open(indexHtmlPath)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(fd)
|
||||
if err != nil {
|
||||
die(err)
|
||||
}
|
||||
|
||||
return body
|
||||
}
|
||||
|
||||
func toB64Gz(input []byte) string {
|
||||
return string(toB64(toGz(input)))
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
die(errors.New(fmt.Sprintf("Usage: %s <index.html-path>", os.Args[0])))
|
||||
}
|
||||
|
||||
assets := &webAssetStrings{
|
||||
IndexHTML: toB64Gz(fetchIndexHtml(os.Args[1])),
|
||||
NormalizeCSS: toB64Gz(fetchUrl(normalizeCssUrl)),
|
||||
JqueryMinJS: toB64Gz(fetchUrl(jqueryMinJsUrl)),
|
||||
Now: time.Now(),
|
||||
}
|
||||
|
||||
webAssetsTmpl.Execute(os.Stdout, assets)
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Conway's Game of Life</title>
|
||||
<link type="text/css" rel="stylesheet" href="/static/normalize.css" />
|
||||
<script type="text/javascript" src="/static/jquery.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
curState = {};
|
||||
curImg = "";
|
||||
|
||||
function populateInitialState() {
|
||||
$.getJSON('/state', {}, onPopulateResponse);
|
||||
}
|
||||
|
||||
function goToNextState(state, loop) {
|
||||
$.post(
|
||||
'/state',
|
||||
JSON.stringify({s: state}, null, 2),
|
||||
function(data, textStatus, jqXHR) {
|
||||
var state = onPopulateResponse(data, textStatus, jqXHR);
|
||||
if (loop) {
|
||||
setTimeout(function() { goToNextState(state, loop); }, 500);
|
||||
}
|
||||
},
|
||||
'json'
|
||||
);
|
||||
}
|
||||
|
||||
function onPopulateResponse(data, textStatus, jqXHR) {
|
||||
$.extend(curState, data.s);
|
||||
curImg = data.i;
|
||||
var $stateImg = $('#state_img');
|
||||
if ($stateImg.length < 1) {
|
||||
$stateImg = $('<img id="state_img" />').appendTo($('#state_container'));
|
||||
}
|
||||
$stateImg.attr('src', 'data:image/png;base64,' + encodeURI(data.i));
|
||||
return data.s;
|
||||
}
|
||||
|
||||
$(function() {
|
||||
populateInitialState();
|
||||
$('#step').click(function() { goToNextState(curState); });
|
||||
$('#play').click(function() { goToNextState(curState, true); });
|
||||
});
|
||||
</script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#container {
|
||||
margin: 0 auto;
|
||||
width: 1024px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#state_container {
|
||||
margin-top: 21px;
|
||||
padding-top: 9px;
|
||||
border-top: 1px solid #999;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<h1>Conway's Game of Life</h1>
|
||||
<div id="controls">
|
||||
<button id="play">Play</button>
|
||||
<button id="step">Step</button>
|
||||
</div>
|
||||
<div id="state_container">
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user