From 3fc443a28c5c205cfecd0e8253c717d1354f5c38 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 3 Sep 2016 02:44:29 +0900 Subject: [PATCH] doc: Add an example life --- _docs/gen.go | 1 + docs/examples/life.content.html | 24 ++++ docs/examples/life.html | 231 ++++++++++++++++++++++++++++++++ docs/images/examples/life.png | Bin 0 -> 4837 bytes docs/index.html | 2 + 5 files changed, 258 insertions(+) create mode 100644 docs/examples/life.content.html create mode 100644 docs/examples/life.html create mode 100644 docs/images/examples/life.png diff --git a/_docs/gen.go b/_docs/gen.go index 306570555..f29d094d2 100644 --- a/_docs/gen.go +++ b/_docs/gen.go @@ -174,6 +174,7 @@ var examples = []example{ {"hue", 320, 240}, {"gamepad", 320, 240}, {"keyboard", 320, 240}, + {"life", 320, 240}, {"masking", 320, 240}, {"mosaic", 320, 240}, {"noise", 320, 240}, diff --git a/docs/examples/life.content.html b/docs/examples/life.content.html new file mode 100644 index 000000000..483689b36 --- /dev/null +++ b/docs/examples/life.content.html @@ -0,0 +1,24 @@ + + diff --git a/docs/examples/life.html b/docs/examples/life.html new file mode 100644 index 000000000..25f62caea --- /dev/null +++ b/docs/examples/life.html @@ -0,0 +1,231 @@ + + + + +Ebiten example - life + + + + + + + +
+ +

Ebiten example - life

+ +
// +build example
+
+package main
+
+import (
+        "image"
+        "log"
+        "math/rand"
+        "time"
+
+        "github.com/hajimehoshi/ebiten"
+
+        "os"
+        "image/png"
+)
+
+var (
+        randSource = rand.NewSource(time.Now().UnixNano())
+        rnd        = rand.New(randSource)
+)
+
+// World represents the game state
+type World struct {
+        area [][]bool
+}
+
+// NewWorld creates a new world
+func NewWorld(width, height int) *World {
+        world := World{}
+        world.area = makeArea(width, height)
+        return &world
+}
+
+// RandomSeed inits world with a random state
+func (w *World) RandomSeed(limit int) {
+        height := len(w.area)
+        width := len(w.area[0])
+
+        for i := 0; i < limit; i++ {
+                x := rnd.Intn(width)
+                y := rnd.Intn(height)
+                w.area[y][x] = true
+        }
+}
+
+// Progress game state by one tick
+func (w *World) Progress() {
+        height := len(w.area)
+        width := len(w.area[0])
+
+        next := makeArea(width, height)
+
+        for y := 0; y < height; y++ {
+                for x := 0; x < width; x++ {
+
+                        pop := neighbourCount(w.area, x, y)
+                        switch {
+                        case pop < 2:
+                                // rule 1. Any live cell with fewer than two live neighbours
+                                // dies, as if caused by under-population.
+                                next[y][x] = false
+
+                        case (pop == 2 || pop == 3) && w.area[y][x]:
+                                // rule 2. Any live cell with two or three live neighbours
+                                // lives on to the next generation.
+                                next[y][x] = true
+
+                        case pop > 3:
+                                // rule 3. Any live cell with more than three live neighbours
+                                // dies, as if by over-population.
+                                next[y][x] = false
+
+                        case pop == 3:
+                                // rule 4. Any dead cell with exactly three live neighbours
+                                // becomes a live cell, as if by reproduction.
+                                next[y][x] = true
+                        }
+                }
+        }
+        w.area = next
+}
+
+// DrawImage paints current game state
+func (w *World) DrawImage(img *image.RGBA) {
+        height := len(w.area)
+        width := len(w.area[0])
+
+        for y := 0; y < height; y++ {
+                for x := 0; x < width; x++ {
+                        pos := 4*y*width + 4*x
+                        if w.area[y][x] {
+                                img.Pix[pos] = 0xff
+                                img.Pix[pos+1] = 0xff
+                                img.Pix[pos+2] = 0xff
+                                img.Pix[pos+3] = 0xff
+                        } else {
+                                img.Pix[pos] = 0
+                                img.Pix[pos+1] = 0
+                                img.Pix[pos+2] = 0
+                                img.Pix[pos+3] = 0
+                        }
+                }
+        }
+}
+
+// neighbourCount calculates the Moore neighborhood of x, y
+func neighbourCount(a [][]bool, x, y int) int {
+        height := len(a)
+        width := len(a[0])
+
+        lowX := 0
+        if x > 0 {
+                lowX = x - 1
+        }
+
+        lowY := 0
+        if y > 0 {
+                lowY = y - 1
+        }
+
+        highX := width - 1
+        if x < width-1 {
+                highX = x + 1
+        }
+
+        highY := height - 1
+        if y < height-1 {
+                highY = y + 1
+        }
+
+        near := 0
+        for pY := lowY; pY <= highY; pY++ {
+                for pX := lowX; pX <= highX; pX++ {
+                        if !(pX == x && pY == y) && a[pY][pX] {
+                                near++
+                        }
+                }
+        }
+
+        return near
+}
+
+func makeArea(width, height int) [][]bool {
+        area := make([][]bool, height)
+        for i := 0; i < height; i++ {
+                area[i] = make([]bool, width)
+        }
+        return area
+}
+
+const (
+        screenWidth  = 320
+        screenHeight = 240
+)
+
+var (
+        world      *World
+        noiseImage *image.RGBA
+)
+
+func update(screen *ebiten.Image) error {
+        world.Progress()
+        world.DrawImage(noiseImage)
+        if err := screen.ReplacePixels(noiseImage.Pix); err != nil {
+                return err
+        }
+        if ebiten.IsKeyPressed(ebiten.KeyQ) {
+                f, err := os.Create("screenshot.png")
+                if err != nil {
+                        return err
+                }
+                defer f.Close()
+                if err := png.Encode(f, screen); err != nil {
+                        return err
+                }
+                os.Exit(0)
+        }
+        return nil
+}
+
+func main() {
+        population := int((screenWidth * screenHeight) / 10)
+        scale := 2.0
+
+        world = NewWorld(screenWidth, screenHeight)
+        world.RandomSeed(population)
+
+        noiseImage = image.NewRGBA(image.Rect(0, 0, screenWidth, screenHeight))
+        if err := ebiten.Run(update, screenWidth, screenHeight, scale, "Game of Life (Ebiten Demo)"); err != nil {
+                log.Fatal(err)
+        }
+}
+
+ +
+ + + + + diff --git a/docs/images/examples/life.png b/docs/images/examples/life.png new file mode 100644 index 0000000000000000000000000000000000000000..17d7ac61ae6eaa57bde04503508fabe932cf7951 GIT binary patch literal 4837 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 example: gamepad
Ebiten example: keyboard +
+ Ebiten example: life
Ebiten example: masking