Files
gl01/internal/work/worker.go
2025-12-19 21:41:58 +08:00

123 lines
2.4 KiB
Go

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
}