mirror of
https://codeberg.org/scip/golsky.git
synced 2025-12-16 20:20:57 +01:00
146 lines
2.3 KiB
Go
146 lines
2.3 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"log"
|
||
|
|
"math/rand"
|
||
|
|
"os"
|
||
|
|
"runtime/pprof"
|
||
|
|
|
||
|
|
"github.com/mlange-42/arche/ecs"
|
||
|
|
"github.com/mlange-42/arche/generic"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
max int = 1500
|
||
|
|
loops int = 5000
|
||
|
|
density int = 8
|
||
|
|
debug bool = false
|
||
|
|
)
|
||
|
|
|
||
|
|
// components
|
||
|
|
type Pos struct {
|
||
|
|
X, Y, GridX, GridY int
|
||
|
|
}
|
||
|
|
|
||
|
|
type Cell struct {
|
||
|
|
State bool
|
||
|
|
Neighbors [8]ecs.Entity
|
||
|
|
}
|
||
|
|
|
||
|
|
type ECS struct {
|
||
|
|
World *ecs.World
|
||
|
|
Filter *generic.Filter2[Pos, Cell]
|
||
|
|
Map *generic.Map2[Pos, Cell]
|
||
|
|
}
|
||
|
|
|
||
|
|
func (cell *Cell) NeighborCount(ECS *ECS) int {
|
||
|
|
sum := 0
|
||
|
|
|
||
|
|
for _, neighbor := range cell.Neighbors {
|
||
|
|
if ECS.World.Alive(neighbor) {
|
||
|
|
_, cel := ECS.Map.Get(neighbor)
|
||
|
|
if cel.State {
|
||
|
|
sum++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return sum
|
||
|
|
}
|
||
|
|
|
||
|
|
func Loop(ECS *ECS) {
|
||
|
|
c := 0
|
||
|
|
|
||
|
|
for i := 0; i < loops; i++ {
|
||
|
|
query := ECS.Filter.Query(ECS.World)
|
||
|
|
|
||
|
|
for query.Next() {
|
||
|
|
_, cel := query.Get()
|
||
|
|
if cel.State && cel.NeighborCount(ECS) > 1 {
|
||
|
|
c = 1
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if c > 1 {
|
||
|
|
c = 0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func SetupWorld() *ECS {
|
||
|
|
world := ecs.NewWorld()
|
||
|
|
|
||
|
|
builder := generic.NewMap2[Pos, Cell](&world)
|
||
|
|
|
||
|
|
// we need a temporary grid in order to find out neighbors
|
||
|
|
grid := [max][max]ecs.Entity{}
|
||
|
|
|
||
|
|
// setup entities
|
||
|
|
for y := 0; y < max; y++ {
|
||
|
|
for x := 0; x < max; x++ {
|
||
|
|
e := builder.New()
|
||
|
|
pos, cell := builder.Get(e)
|
||
|
|
pos.X = x
|
||
|
|
pos.Y = y // pos.GridX = x*cellsize
|
||
|
|
|
||
|
|
cell.State = false
|
||
|
|
if rand.Intn(density) == 1 {
|
||
|
|
cell.State = true
|
||
|
|
}
|
||
|
|
|
||
|
|
// store to tmp grid
|
||
|
|
grid[y][x] = e
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// global filter
|
||
|
|
filter := generic.NewFilter2[Pos, Cell]()
|
||
|
|
|
||
|
|
query := filter.Query(&world)
|
||
|
|
|
||
|
|
for query.Next() {
|
||
|
|
pos, cel := query.Get()
|
||
|
|
|
||
|
|
n := 0
|
||
|
|
for x := -1; x < 2; x++ {
|
||
|
|
for y := -1; y < 2; y++ {
|
||
|
|
XX := pos.X + x
|
||
|
|
YY := pos.Y + y
|
||
|
|
if XX < 0 || XX >= max || YY < 0 || YY >= max {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
if pos.X != XX || pos.Y != YY {
|
||
|
|
cel.Neighbors[n] = grid[XX][YY]
|
||
|
|
n++
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return &ECS{World: &world, Filter: filter, Map: &builder}
|
||
|
|
}
|
||
|
|
|
||
|
|
func main() {
|
||
|
|
// enable cpu profiling. Do NOT use q to stop the game but
|
||
|
|
// close the window to get a profile
|
||
|
|
fd, err := os.Create("cpu.profile")
|
||
|
|
if err != nil {
|
||
|
|
log.Fatal(err)
|
||
|
|
}
|
||
|
|
defer fd.Close()
|
||
|
|
|
||
|
|
pprof.StartCPUProfile(fd)
|
||
|
|
defer pprof.StopCPUProfile()
|
||
|
|
|
||
|
|
// init
|
||
|
|
fmt.Print("Setup ... ")
|
||
|
|
ECS := SetupWorld()
|
||
|
|
fmt.Println("done")
|
||
|
|
fmt.Println(ECS.World.Stats())
|
||
|
|
|
||
|
|
// main loop
|
||
|
|
Loop(ECS)
|
||
|
|
}
|