123 lines
2.4 KiB
Go
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
|
|
}
|