Compare commits
2 Commits
b20abbe803
...
igexp_gene
| Author | SHA1 | Date | |
|---|---|---|---|
| 105515277f | |||
| afc9904651 |
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
|||||||
module edgaru089.ink/go/gl01
|
module edgaru089.ink/go/gl01
|
||||||
|
|
||||||
go 1.17
|
go 1.25
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aquilax/go-perlin v1.1.0
|
github.com/aquilax/go-perlin v1.1.0
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"edgaru089.ink/go/gl01/internal/io"
|
"edgaru089.ink/go/gl01/internal/io"
|
||||||
"edgaru089.ink/go/gl01/internal/util"
|
"edgaru089.ink/go/gl01/internal/util"
|
||||||
"edgaru089.ink/go/gl01/internal/util/itype"
|
"edgaru089.ink/go/gl01/internal/util/itype"
|
||||||
|
"edgaru089.ink/go/gl01/internal/work"
|
||||||
"github.com/go-gl/glfw/v3.3/glfw"
|
"github.com/go-gl/glfw/v3.3/glfw"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -110,9 +111,9 @@ func (g *Game) Init(win *glfw.Window) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
work.Init()
|
||||||
|
|
||||||
const airAccel = 0.1
|
}
|
||||||
|
|
||||||
// Update updates the game state, not necessarily in the main thread.
|
// Update updates the game state, not necessarily in the main thread.
|
||||||
func (g *Game) Update(win *glfw.Window, delta time.Duration) {
|
func (g *Game) Update(win *glfw.Window, delta time.Duration) {
|
||||||
@@ -121,6 +122,8 @@ func (g *Game) Update(win *glfw.Window, delta time.Duration) {
|
|||||||
|
|
||||||
clock := util.NewClock()
|
clock := util.NewClock()
|
||||||
|
|
||||||
|
work.Update(delta)
|
||||||
|
|
||||||
io.Diagnostics.Times.Logic = clock.Restart()
|
io.Diagnostics.Times.Logic = clock.Restart()
|
||||||
|
|
||||||
g.imgui()
|
g.imgui()
|
||||||
|
|||||||
@@ -28,4 +28,6 @@ var (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StepFactors []float64
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ func NewClock() (c *Clock) {
|
|||||||
// Restart resets the start time.
|
// Restart resets the start time.
|
||||||
// It also returns the elapsed time.
|
// It also returns the elapsed time.
|
||||||
func (c *Clock) Restart() (t time.Duration) {
|
func (c *Clock) Restart() (t time.Duration) {
|
||||||
t = time.Since(c.t)
|
now := time.Now()
|
||||||
c.t = time.Now()
|
t = now.Sub(c.t)
|
||||||
|
c.t = now
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
9
internal/util/slice.go
Normal file
9
internal/util/slice.go
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
func Slice2Float32[T int | float64](s []T) (sf []float32) {
|
||||||
|
sf = make([]float32, len(s))
|
||||||
|
for i := range s {
|
||||||
|
sf[i] = float32(s[i])
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
144
internal/work/work.go
Normal file
144
internal/work/work.go
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
package work
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"slices"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"edgaru089.ink/go/gl01/internal/igwrap"
|
||||||
|
"edgaru089.ink/go/gl01/internal/io"
|
||||||
|
"github.com/inkyblackness/imgui-go/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
var state struct {
|
||||||
|
inst [2000]*WorkerInstance
|
||||||
|
buf []*WorkerInstance
|
||||||
|
|
||||||
|
steps int
|
||||||
|
|
||||||
|
first_step int
|
||||||
|
|
||||||
|
iter_disabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type iter_info struct {
|
||||||
|
first_step, last_step int
|
||||||
|
step_count int
|
||||||
|
|
||||||
|
max_score float64
|
||||||
|
|
||||||
|
factor float64
|
||||||
|
}
|
||||||
|
|
||||||
|
var stats []iter_info
|
||||||
|
|
||||||
|
func Init() {
|
||||||
|
for i := range state.inst {
|
||||||
|
inst := RandomInstance()
|
||||||
|
state.inst[i] = &inst
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Update(delta time.Duration) {
|
||||||
|
state.steps++
|
||||||
|
|
||||||
|
for i := range state.inst {
|
||||||
|
state.inst[i].Step(state.steps)
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.SortFunc(state.inst[:], func(x, y *WorkerInstance) int {
|
||||||
|
if x.score > y.score {
|
||||||
|
return -1
|
||||||
|
} else if x.score == y.score && x.pos.Sub(x.target).Len() < y.pos.Sub(y.target).Len() {
|
||||||
|
return -1
|
||||||
|
} else {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if imgui.Checkbox("Disable Iteration", &state.iter_disabled) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if !state.iter_disabled && (imgui.Button("Iterate") || state.inst[50].score > 0) {
|
||||||
|
|
||||||
|
factor := 0.0
|
||||||
|
for _, f := range io.StepFactors {
|
||||||
|
factor += f
|
||||||
|
}
|
||||||
|
factor /= float64(len(io.StepFactors))
|
||||||
|
io.StepFactors = io.StepFactors[0:0]
|
||||||
|
|
||||||
|
// push stats
|
||||||
|
stats = append(stats, iter_info{
|
||||||
|
first_step: state.first_step,
|
||||||
|
last_step: state.steps,
|
||||||
|
step_count: state.steps - state.first_step,
|
||||||
|
max_score: state.inst[0].score,
|
||||||
|
factor: factor,
|
||||||
|
})
|
||||||
|
state.first_step = state.steps
|
||||||
|
|
||||||
|
state.buf = state.buf[:0]
|
||||||
|
for i := range 50 {
|
||||||
|
state.inst[i].score = 0
|
||||||
|
state.buf = append(state.buf, state.inst[i])
|
||||||
|
for range 2000/50 - 1 {
|
||||||
|
inst := state.inst[i].Offspring()
|
||||||
|
inst.step0 = state.steps
|
||||||
|
state.buf = append(state.buf, &inst)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
copy(state.inst[:], state.buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range 20 {
|
||||||
|
igwrap.Text("Score: %f\n", state.inst[i].score)
|
||||||
|
}
|
||||||
|
|
||||||
|
if igwrap.Begin("Graph", nil, 0) {
|
||||||
|
imgui.PushItemWidth(-math.SmallestNonzeroFloat32)
|
||||||
|
s := make([]float32, len(stats))
|
||||||
|
if len(stats) < 1 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, st := range stats {
|
||||||
|
s[i] = float32(st.step_count)
|
||||||
|
}
|
||||||
|
if len(s) > 400 {
|
||||||
|
s = s[len(s)-400:]
|
||||||
|
}
|
||||||
|
imgui.PlotLinesV(
|
||||||
|
"##Step Count",
|
||||||
|
s,
|
||||||
|
0,
|
||||||
|
"",
|
||||||
|
math.MaxFloat32,
|
||||||
|
math.MaxFloat32,
|
||||||
|
imgui.Vec2{0, 200},
|
||||||
|
)
|
||||||
|
|
||||||
|
s = make([]float32, len(stats))
|
||||||
|
for i, st := range stats {
|
||||||
|
s[i] = float32(st.factor)
|
||||||
|
}
|
||||||
|
if len(s) > 400 {
|
||||||
|
s = s[len(s)-400:]
|
||||||
|
}
|
||||||
|
imgui.PlotLinesV(
|
||||||
|
"##Factor",
|
||||||
|
s,
|
||||||
|
0,
|
||||||
|
"",
|
||||||
|
math.MaxFloat32,
|
||||||
|
math.MaxFloat32,
|
||||||
|
imgui.Vec2{0, 200},
|
||||||
|
)
|
||||||
|
|
||||||
|
err:
|
||||||
|
imgui.PopItemWidth()
|
||||||
|
imgui.End()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
122
internal/work/worker.go
Normal file
122
internal/work/worker.go
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package work
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
"edgaru089.ink/go/gl01/internal/io"
|
||||||
|
"github.com/go-gl/mathgl/mgl64"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Worker struct {
|
||||||
|
t1, t2 mgl64.Mat4
|
||||||
|
t3 mgl64.Mat2x4
|
||||||
|
}
|
||||||
|
|
||||||
|
func randomSlice64(s []float64) {
|
||||||
|
for i := range s {
|
||||||
|
s[i] = rand.NormFloat64()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomWorker generates a random worker.
|
||||||
|
func RandomWorker() (w Worker) {
|
||||||
|
randomSlice64(w.t1[:])
|
||||||
|
randomSlice64(w.t2[:])
|
||||||
|
randomSlice64(w.t3[:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func mutateSlice64(s []float64, stddev float64) {
|
||||||
|
for i := range s {
|
||||||
|
s[i] = rand.NormFloat64()*stddev + s[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offspring generates an offspring with the given variance.
|
||||||
|
func (w *Worker) Offspring(stddev float64) (s Worker) {
|
||||||
|
s = *w
|
||||||
|
mutateSlice64(s.t1[:], stddev)
|
||||||
|
mutateSlice64(s.t2[:], stddev)
|
||||||
|
mutateSlice64(s.t3[:], stddev)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate runs a Vec4 through the Worker.
|
||||||
|
func (w *Worker) Calculate(input mgl64.Vec4) (output mgl64.Vec2) {
|
||||||
|
imm1 := w.t1.Mul4x1(input)
|
||||||
|
imm2 := w.t2.Mul4x1(imm1)
|
||||||
|
output = w.t3.Mul4x1(imm2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// WorkerInstance is a instance of a worker.
|
||||||
|
type WorkerInstance struct {
|
||||||
|
worker Worker
|
||||||
|
pos mgl64.Vec2
|
||||||
|
target mgl64.Vec2
|
||||||
|
|
||||||
|
score float64
|
||||||
|
|
||||||
|
distance float64
|
||||||
|
step0 int
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
Radius float64 = 10 // Radius of all worker instances
|
||||||
|
Step float64 = 1 // Move length of a advance step
|
||||||
|
|
||||||
|
OffspringStdVar float64 = 0.5
|
||||||
|
|
||||||
|
Score float64 = 1
|
||||||
|
|
||||||
|
TargetAreaSize = mgl64.Vec2{750, 750}
|
||||||
|
)
|
||||||
|
|
||||||
|
func randomTarget() (t mgl64.Vec2) {
|
||||||
|
return mgl64.Vec2{
|
||||||
|
TargetAreaSize[0] * (rand.Float64() - .5),
|
||||||
|
TargetAreaSize[1] * (rand.Float64() - .5),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *WorkerInstance) Step(step_num int) {
|
||||||
|
output := i.worker.Calculate(mgl64.Vec4{
|
||||||
|
i.pos[0],
|
||||||
|
i.pos[1],
|
||||||
|
i.target[0],
|
||||||
|
i.target[1],
|
||||||
|
})
|
||||||
|
|
||||||
|
direction := mgl64.Vec2{output[0], output[1]}.Normalize()
|
||||||
|
step := direction.Mul(Step)
|
||||||
|
|
||||||
|
i.pos = i.pos.Add(step)
|
||||||
|
if i.pos.Sub(i.target).Len() < Radius {
|
||||||
|
// Score!
|
||||||
|
i.score += Score
|
||||||
|
|
||||||
|
io.StepFactors = append(io.StepFactors, (float64(step_num-i.step0)*Step)/i.distance)
|
||||||
|
|
||||||
|
i.target = randomTarget()
|
||||||
|
i.step0 = step_num
|
||||||
|
i.distance = i.pos.Sub(i.target).Len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *WorkerInstance) Offspring() (it WorkerInstance) {
|
||||||
|
it.pos = randomTarget()
|
||||||
|
it.target = randomTarget()
|
||||||
|
it.distance = it.pos.Sub(it.target).Len()
|
||||||
|
it.score = 0
|
||||||
|
it.worker = i.worker.Offspring(OffspringStdVar)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandomInstance() (i WorkerInstance) {
|
||||||
|
i.worker = RandomWorker()
|
||||||
|
i.pos = randomTarget()
|
||||||
|
i.target = randomTarget()
|
||||||
|
i.distance = i.pos.Sub(i.target).Len()
|
||||||
|
i.score = 0
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -2,6 +2,6 @@
|
|||||||
"WindowWidth": 1024,
|
"WindowWidth": 1024,
|
||||||
"WindowHeight": 768,
|
"WindowHeight": 768,
|
||||||
|
|
||||||
"FramerateLimit": 100
|
"FramerateLimit": 4000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
6
main.go
6
main.go
@@ -8,6 +8,7 @@ import (
|
|||||||
"edgaru089.ink/go/gl01/internal/game"
|
"edgaru089.ink/go/gl01/internal/game"
|
||||||
gio "edgaru089.ink/go/gl01/internal/io"
|
gio "edgaru089.ink/go/gl01/internal/io"
|
||||||
_ "edgaru089.ink/go/gl01/internal/render/gpu_preference"
|
_ "edgaru089.ink/go/gl01/internal/render/gpu_preference"
|
||||||
|
"edgaru089.ink/go/gl01/internal/util"
|
||||||
"edgaru089.ink/go/gl01/internal/util/itype"
|
"edgaru089.ink/go/gl01/internal/util/itype"
|
||||||
"github.com/go-gl/gl/all-core/gl"
|
"github.com/go-gl/gl/all-core/gl"
|
||||||
"github.com/go-gl/glfw/v3.3/glfw"
|
"github.com/go-gl/glfw/v3.3/glfw"
|
||||||
@@ -70,15 +71,14 @@ func main() {
|
|||||||
gl.ClearColor(gio.ClearColor[0], gio.ClearColor[1], gio.ClearColor[2], gio.ClearColor[3])
|
gl.ClearColor(gio.ClearColor[0], gio.ClearColor[1], gio.ClearColor[2], gio.ClearColor[3])
|
||||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||||
win.SwapBuffers()
|
win.SwapBuffers()
|
||||||
winClock := time.Now()
|
winClock := util.NewClock()
|
||||||
|
|
||||||
fpsClock := time.Now()
|
fpsClock := time.Now()
|
||||||
fpsCounter := 0
|
fpsCounter := 0
|
||||||
|
|
||||||
for !win.ShouldClose() {
|
for !win.ShouldClose() {
|
||||||
|
|
||||||
deltaTime := time.Since(winClock)
|
deltaTime := winClock.Restart()
|
||||||
winClock = time.Now()
|
|
||||||
game.Update(win, deltaTime)
|
game.Update(win, deltaTime)
|
||||||
|
|
||||||
gl.ClearColor(gio.ClearColor[0], gio.ClearColor[1], gio.ClearColor[2], gio.ClearColor[3])
|
gl.ClearColor(gio.ClearColor[0], gio.ClearColor[1], gio.ClearColor[2], gio.ClearColor[3])
|
||||||
|
|||||||
Reference in New Issue
Block a user