examples/life: Refactoring

This commit is contained in:
Hajime Hoshi 2018-01-28 22:47:35 +09:00
parent 80596820cf
commit 2f0909e705

View File

@ -36,25 +36,36 @@ import (
// World represents the game state. // World represents the game state.
type World struct { type World struct {
area [][]bool area [][]bool
rnd *rand.Rand }
func newArea(width, height int) [][]bool {
a := make([][]bool, height)
for i := 0; i < height; i++ {
a[i] = make([]bool, width)
}
return a
} }
// NewWorld creates a new world. // NewWorld creates a new world.
func NewWorld(width, height int) *World { func NewWorld(width, height int, maxInitLiveCells int) *World {
world := World{ w := &World{
area: makeArea(width, height), area: newArea(width, height),
rnd: rand.New(rand.NewSource(time.Now().UnixNano())),
} }
return &world w.init(maxInitLiveCells)
return w
} }
// RandomSeed inits world with a random state. func init() {
func (w *World) RandomSeed(limit int) { rand.Seed(time.Now().UnixNano())
}
// init inits world with a random state.
func (w *World) init(maxLiveCells int) {
height := len(w.area) height := len(w.area)
width := len(w.area[0]) width := len(w.area[0])
for i := 0; i < limit; i++ { for i := 0; i < maxLiveCells; i++ {
x := w.rnd.Intn(width) x := rand.Intn(width)
y := w.rnd.Intn(height) y := rand.Intn(height)
w.area[y][x] = true w.area[y][x] = true
} }
} }
@ -63,7 +74,7 @@ func (w *World) RandomSeed(limit int) {
func (w *World) Update() { func (w *World) Update() {
height := len(w.area) height := len(w.area)
width := len(w.area[0]) width := len(w.area[0])
next := makeArea(width, height) next := newArea(width, height)
for y := 0; y < height; y++ { for y := 0; y < height; y++ {
for x := 0; x < width; x++ { for x := 0; x < width; x++ {
pop := neighbourCount(w.area, x, y) pop := neighbourCount(w.area, x, y)
@ -93,66 +104,63 @@ func (w *World) Update() {
w.area = next w.area = next
} }
// DrawImage paints current game state // Draw paints current game state.
func (w *World) DrawImage(pix []byte) { func (w *World) Draw(pix []byte) {
height := len(w.area) height := len(w.area)
width := len(w.area[0]) width := len(w.area[0])
for y := 0; y < height; y++ { for y := 0; y < height; y++ {
for x := 0; x < width; x++ { for x := 0; x < width; x++ {
pos := 4*y*width + 4*x idx := 4*y*width + 4*x
if w.area[y][x] { if w.area[y][x] {
pix[pos] = 0xff pix[idx] = 0xff
pix[pos+1] = 0xff pix[idx+1] = 0xff
pix[pos+2] = 0xff pix[idx+2] = 0xff
pix[pos+3] = 0xff pix[idx+3] = 0xff
} else { } else {
pix[pos] = 0 pix[idx] = 0
pix[pos+1] = 0 pix[idx+1] = 0
pix[pos+2] = 0 pix[idx+2] = 0
pix[pos+3] = 0 pix[idx+3] = 0
} }
} }
} }
} }
// neighbourCount calculates the Moore neighborhood of (x, y) func max(a, b int) int {
if a < b {
return b
}
return a
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
// neighbourCount calculates the Moore neighborhood of (x, y).
func neighbourCount(a [][]bool, x, y int) int { func neighbourCount(a [][]bool, x, y int) int {
height := len(a) w := len(a[0])
width := len(a[0]) h := len(a)
lowX := 0 minI := max(x-1, 0)
if x > 0 { minJ := max(y-1, 0)
lowX = x - 1 maxI := min(x+1, w-1)
} maxJ := min(y+1, h-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 c := 0
for j := minJ; j <= maxJ; j++ {
for i := minI; i <= maxI; i++ {
if i == x && j == y {
continue
} }
if a[j][i] {
func makeArea(width, height int) [][]bool { c++
area := make([][]bool, height)
for i := 0; i < height; i++ {
area[i] = make([]bool, width)
} }
return area }
}
return c
} }
const ( const (
@ -161,23 +169,24 @@ const (
) )
var ( var (
world = NewWorld(screenWidth, screenHeight) world = NewWorld(screenWidth, screenHeight, int((screenWidth*screenHeight)/10))
pixels = make([]byte, screenWidth*screenHeight*4) pixels = make([]byte, screenWidth*screenHeight*4)
) )
func update(screen *ebiten.Image) error { func update(screen *ebiten.Image) error {
world.Update() world.Update()
if ebiten.IsRunningSlowly() { if ebiten.IsRunningSlowly() {
return nil return nil
} }
world.DrawImage(pixels)
world.Draw(pixels)
screen.ReplacePixels(pixels) screen.ReplacePixels(pixels)
return nil return nil
} }
func main() { func main() {
world.RandomSeed(int((screenWidth * screenHeight) / 10)) if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Game of Life (Ebiten Demo)"); err != nil {
if err := ebiten.Run(update, screenWidth, screenHeight, 2.0, "Game of Life (Ebiten Demo)"); err != nil {
log.Fatal(err) log.Fatal(err)
} }
} }