using go-routines (one per row), makes it faster

This commit is contained in:
2024-06-15 11:42:41 +02:00
committed by T.v.Dein
parent 7b0a74fb93
commit 861ba86b0c

View File

@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"image" "image"
"log" "log"
"sync"
"unsafe" "unsafe"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
@@ -21,6 +22,21 @@ const (
DEBUG_FORMAT = "FPS: %0.2f, TPG: %d, M: %0.2fMB, Generations: %d\nScale: %.02f, Zoom: %d, Cam: %.02f,%.02f Cursor: %d,%d %s" DEBUG_FORMAT = "FPS: %0.2f, TPG: %d, M: %0.2fMB, Generations: %d\nScale: %.02f, Zoom: %d, Cam: %.02f,%.02f Cursor: %d,%d %s"
) )
type History struct {
Age [][]int64
}
func NewHistory(height, width int) History {
hist := History{}
hist.Age = make([][]int64, height)
for y := 0; y < height; y++ {
hist.Age[y] = make([]int64, width)
}
return hist
}
type ScenePlay struct { type ScenePlay struct {
Game *Game Game *Game
Config *Config Config *Config
@@ -31,7 +47,7 @@ type ScenePlay struct {
Clear bool Clear bool
Grids []*Grid // 2 grids: one current, one next Grids []*Grid // 2 grids: one current, one next
History [][]int64 // holds state of past dead cells for evolution traces History History // holds state of past dead cells for evolution traces
Index int // points to current grid Index int // points to current grid
Generations int64 // Stats Generations int64 // Stats
TicksElapsed int // tick counter for game speed TicksElapsed int // tick counter for game speed
@@ -116,30 +132,40 @@ func (scene *ScenePlay) UpdateCells() {
// next grid index, we just xor 0|1 to 1|0 // next grid index, we just xor 0|1 to 1|0
next := scene.Index ^ 1 next := scene.Index ^ 1
var wg sync.WaitGroup
wg.Add(scene.Config.Height)
// compute life status of cells // compute life status of cells
for y := 0; y < scene.Config.Height; y++ { for y := 0; y < scene.Config.Height; y++ {
for x := 0; x < scene.Config.Width; x++ {
state := scene.Grids[scene.Index].Data[y][x].State // 0|1 == dead or alive
neighbors := scene.Grids[scene.Index].CountNeighbors(x, y)
// actually apply the current rules go func() {
nextstate := scene.CheckRule(state, neighbors) defer wg.Done()
// change state of current cell in next grid for x := 0; x < scene.Config.Width; x++ {
scene.Grids[next].Data[y][x].State = nextstate state := scene.Grids[scene.Index].Data[y][x].State // 0|1 == dead or alive
neighbors := scene.Grids[scene.Index].CountNeighbors(x, y)
if scene.Config.ShowEvolution { // actually apply the current rules
// set history to current generation so we can infer the nextstate := scene.CheckRule(state, neighbors)
// age of the cell's state during rendering and use it to
// deduce the color to use if evolution tracing is enabled // change state of current cell in next grid
// 60FPS: scene.Grids[next].Data[y][x].State = nextstate
if state != nextstate {
scene.History[y][x] = scene.Generations if scene.Config.ShowEvolution {
// set history to current generation so we can infer the
// age of the cell's state during rendering and use it to
// deduce the color to use if evolution tracing is enabled
// 60FPS:
if state != nextstate {
scene.History.Age[y][x] = scene.Generations
}
} }
} }
} }()
} }
wg.Wait()
// switch grid for rendering // switch grid for rendering
scene.Index ^= 1 scene.Index ^= 1
@@ -427,7 +453,7 @@ func (scene *ScenePlay) ToggleCellOnCursorPos(alive bool) {
if x > -1 && y > -1 && x < scene.Config.Width && y < scene.Config.Height { if x > -1 && y > -1 && x < scene.Config.Width && y < scene.Config.Height {
scene.Grids[scene.Index].Data[y][x].State = alive scene.Grids[scene.Index].Data[y][x].State = alive
scene.History[y][x] = 1 scene.History.Age[y][x] = 1
} }
} }
@@ -467,7 +493,7 @@ func (scene *ScenePlay) Draw(screen *ebiten.Image) {
} }
func (scene *ScenePlay) DrawEvolution(screen *ebiten.Image, x, y int, op *ebiten.DrawImageOptions) { func (scene *ScenePlay) DrawEvolution(screen *ebiten.Image, x, y int, op *ebiten.DrawImageOptions) {
age := scene.Generations - scene.History[y][x] age := scene.Generations - scene.History.Age[y][x]
switch scene.Grids[scene.Index].Data[y][x].State { switch scene.Grids[scene.Index].Data[y][x].State {
case Alive: case Alive:
@@ -478,7 +504,7 @@ func (scene *ScenePlay) DrawEvolution(screen *ebiten.Image, x, y int, op *ebiten
} }
case Dead: case Dead:
// only draw dead cells in case evolution trace is enabled // only draw dead cells in case evolution trace is enabled
if scene.History[y][x] > 1 && scene.Config.ShowEvolution { if age > 1 && scene.Config.ShowEvolution {
switch { switch {
case age < 10: case age < 10:
scene.World.DrawImage(scene.Theme.Tile(ColAge1), op) scene.World.DrawImage(scene.Theme.Tile(ColAge1), op)
@@ -588,10 +614,7 @@ func (scene *ScenePlay) InitGrid() {
gridb, gridb,
} }
scene.History = make([][]int64, scene.Config.Height) scene.History = NewHistory(scene.Config.Height, scene.Config.Width)
for y := 0; y < scene.Config.Height; y++ {
scene.History[y] = make([]int64, scene.Config.Width)
}
} }
func (scene *ScenePlay) Init() { func (scene *ScenePlay) Init() {