Stableish- Prey-Predator Dynamics
This commit is contained in:
parent
fe96374bee
commit
64431203bf
|
@ -4,7 +4,7 @@ type Environment struct {
|
|||
width, height int
|
||||
state map[string][][]float32
|
||||
value [][]bool
|
||||
col [][]bool
|
||||
col [][]*Turtle
|
||||
}
|
||||
|
||||
func (e *Environment) Width() int {
|
||||
|
@ -29,9 +29,9 @@ func NewEnvironment(width int, height int) *Environment {
|
|||
env.height = height
|
||||
env.state = make(map[string][][]float32)
|
||||
|
||||
env.col = make([][]bool, width)
|
||||
env.col = make([][]*Turtle, width)
|
||||
for x := range env.col {
|
||||
env.col[x] = make([]bool, height)
|
||||
env.col[x] = make([]*Turtle, height)
|
||||
}
|
||||
|
||||
env.value = make([][]bool, width)
|
||||
|
@ -54,16 +54,20 @@ func (e *Environment) Mark(pheromone string, x, y int, amount float32) {
|
|||
}
|
||||
}
|
||||
|
||||
func (e Environment) Occupy(x, y int) {
|
||||
e.col[x][y] = true
|
||||
func (e Environment) Occupy(turtle *Turtle, x, y int) {
|
||||
e.col[x][y] = turtle
|
||||
}
|
||||
|
||||
func (e Environment) Check(x, y int) bool {
|
||||
func (e Environment) Get(x, y int) *Turtle {
|
||||
return e.col[x][y]
|
||||
}
|
||||
|
||||
func (e Environment) Check(x, y int) bool {
|
||||
return e.col[x][y] != nil
|
||||
}
|
||||
|
||||
func (e Environment) Leave(x, y int) {
|
||||
e.col[x][y] = false
|
||||
e.col[x][y] = nil
|
||||
}
|
||||
|
||||
func (e Environment) HasValue(x, y int) bool {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
|
@ -9,6 +10,8 @@ type Turtle struct {
|
|||
heading int
|
||||
actor Actor
|
||||
width, height int
|
||||
col color.RGBA
|
||||
atts map[string]string
|
||||
}
|
||||
|
||||
type NilActor struct {
|
||||
|
@ -20,22 +23,36 @@ func (NilActor) Setup(*Environment, *Turtle) {
|
|||
func (NilActor) Run(*Environment, *Turtle) {
|
||||
}
|
||||
|
||||
func (t *Turtle) GetActor() Actor {
|
||||
return t.actor
|
||||
}
|
||||
|
||||
func NewTurtle(env *Environment, actor Actor) *Turtle {
|
||||
for {
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
turtle := new(Turtle)
|
||||
turtle.width = env.width
|
||||
turtle.height = env.height
|
||||
turtle.xpos = rand.Intn(env.width)
|
||||
turtle.ypos = rand.Intn(env.height)
|
||||
turtle.actor = actor
|
||||
turtle.atts = make(map[string]string)
|
||||
if env.Check(turtle.xpos, turtle.ypos) == false {
|
||||
actor.Setup(env, turtle)
|
||||
env.Occupy(turtle.xpos, turtle.ypos)
|
||||
env.Occupy(turtle, turtle.xpos, turtle.ypos)
|
||||
turtle.setRandomHeading()
|
||||
return turtle
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Turtle) GetColor() color.RGBA {
|
||||
return t.col
|
||||
}
|
||||
|
||||
func (t *Turtle) SetColor(col color.RGBA) {
|
||||
t.col = col
|
||||
}
|
||||
|
||||
func (t *Turtle) Pos() (int, int) {
|
||||
|
@ -75,6 +92,14 @@ func (t *Turtle) Wiggle() {
|
|||
t.heading = h
|
||||
}
|
||||
|
||||
func (t *Turtle) GetAttribute(name string) string {
|
||||
return t.atts[name]
|
||||
}
|
||||
|
||||
func (t *Turtle) SetAttribute(name, val string) {
|
||||
t.atts[name] = val
|
||||
}
|
||||
|
||||
func (t *Turtle) TurnAround() {
|
||||
t.heading = (t.heading + 4) % 8
|
||||
}
|
||||
|
@ -206,6 +231,22 @@ func (t *Turtle) FollowGradient(env *Environment, distance int, threshold float3
|
|||
}
|
||||
}
|
||||
|
||||
func (t *Turtle) Check(env *Environment) *Turtle {
|
||||
dx := headings[t.heading][0]
|
||||
dy := headings[t.heading][1]
|
||||
|
||||
xpos := (t.xpos + dx) % (env.width)
|
||||
if xpos < 0 {
|
||||
xpos = env.width - 1
|
||||
}
|
||||
ypos := (t.ypos + dy) % (env.height)
|
||||
if ypos < 0 {
|
||||
ypos = env.height - 1
|
||||
}
|
||||
|
||||
return env.Get(xpos, ypos)
|
||||
}
|
||||
|
||||
func (t *Turtle) Step(env *Environment) bool {
|
||||
dx := headings[t.heading][0]
|
||||
dy := headings[t.heading][1]
|
||||
|
@ -228,7 +269,7 @@ func (t *Turtle) Step(env *Environment) bool {
|
|||
t.ypos = oy
|
||||
success = false
|
||||
}
|
||||
env.Occupy(t.xpos, t.ypos)
|
||||
env.Occupy(t, t.xpos, t.ypos)
|
||||
return success
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ type Experiment struct {
|
|||
turtles []*core.Turtle
|
||||
graphics *graphics.Graphics
|
||||
initializedTurtles int
|
||||
OnStep func(*core.Environment, []*core.Turtle, int)
|
||||
}
|
||||
|
||||
func (e *Experiment) InitializeExperiment() {
|
||||
|
@ -46,7 +47,7 @@ func (e *Experiment) InitializeExperiment() {
|
|||
}
|
||||
|
||||
e.env = core.NewEnvironment(*width, *height)
|
||||
e.turtles = make([]*core.Turtle, *numTurtles)
|
||||
e.turtles = make([]*core.Turtle, 0)
|
||||
e.graphics = graphics.NewGraphics(int32(*width), int32(*height), int32(*pxsize))
|
||||
}
|
||||
|
||||
|
@ -65,10 +66,15 @@ func (e *Experiment) InitEnvironment(f func(environment *core.Environment)) {
|
|||
}
|
||||
|
||||
func (e *Experiment) InitNTurtles(f func() core.Actor, num int) {
|
||||
numSuccess := 0
|
||||
for i := e.initializedTurtles; i < e.initializedTurtles+num; i++ {
|
||||
e.turtles[i] = core.NewTurtle(e.env, f())
|
||||
t := core.NewTurtle(e.env, f())
|
||||
if t != nil {
|
||||
e.turtles = append(e.turtles, t)
|
||||
numSuccess++
|
||||
}
|
||||
}
|
||||
e.initializedTurtles += num
|
||||
e.initializedTurtles += numSuccess
|
||||
}
|
||||
|
||||
func (e *Experiment) InitTurtles(f func() core.Actor) {
|
||||
|
@ -81,8 +87,24 @@ func (e *Experiment) Run() {
|
|||
running := true
|
||||
wait.Add(1)
|
||||
go func() {
|
||||
step := 0
|
||||
for running {
|
||||
e.graphics.Render(e.env, e.turtles)
|
||||
e.OnStep(e.env, e.turtles, step)
|
||||
|
||||
newTurtles := make([]*core.Turtle, 0)
|
||||
deleted := 0
|
||||
for _, t := range e.turtles {
|
||||
if t.GetAttribute("status") != "dead" {
|
||||
newTurtles = append(newTurtles, t)
|
||||
} else {
|
||||
e.env.Leave(t.Pos()) // Dead turtles occupy no space
|
||||
deleted++
|
||||
}
|
||||
}
|
||||
|
||||
e.turtles = newTurtles
|
||||
step++
|
||||
}
|
||||
wait.Done()
|
||||
}()
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"git.openprivacy.ca/sarah/microworlds/core"
|
||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
||||
"image/color"
|
||||
"math"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
var numPrey = flag.Int("numPrey", 600, "the number of prey")
|
||||
var numPred = flag.Int("numPred", 60, "the number of predators")
|
||||
|
||||
type Predator struct {
|
||||
Steps int
|
||||
Energy int
|
||||
}
|
||||
|
||||
func (sm *Predator) Setup(env *core.Environment, t *core.Turtle) {
|
||||
// Do nothing
|
||||
t.SetAttribute("type", "predator")
|
||||
t.SetColor(color.RGBA{255, 200, 0, 0})
|
||||
sm.Energy = 50
|
||||
}
|
||||
|
||||
func (sm *Predator) Run(env *core.Environment, t *core.Turtle) {
|
||||
sm.Steps++
|
||||
|
||||
if sm.Steps == 30 {
|
||||
t.SetAttribute("status", "dead")
|
||||
return
|
||||
}
|
||||
sm.Energy--
|
||||
if sm.Energy == 0 {
|
||||
t.SetAttribute("status", "dead")
|
||||
return
|
||||
}
|
||||
t.Wiggle()
|
||||
prey := t.Check(env)
|
||||
if prey != nil {
|
||||
if prey.GetAttribute("type") == "prey" && prey.GetAttribute("status") != "dead" {
|
||||
prey.SetAttribute("status", "dead")
|
||||
sm.Energy = int(math.Max(float64(sm.Energy)+10, 120))
|
||||
}
|
||||
}
|
||||
t.FollowGradient(env, 1, 3, "scent")
|
||||
t.Step(env)
|
||||
}
|
||||
|
||||
type Prey struct {
|
||||
Steps int
|
||||
Energy int
|
||||
}
|
||||
|
||||
func (sm *Prey) Setup(env *core.Environment, t *core.Turtle) {
|
||||
// Do nothing
|
||||
t.SetAttribute("type", "prey")
|
||||
t.SetColor(color.RGBA{100, 0, 100, 0})
|
||||
sm.Steps = 0
|
||||
sm.Energy = 25
|
||||
}
|
||||
|
||||
func (sm *Prey) Run(env *core.Environment, t *core.Turtle) {
|
||||
sm.Steps++
|
||||
sm.Energy--
|
||||
|
||||
if sm.Steps >= 20 || sm.Energy == 0 {
|
||||
t.SetAttribute("status", "dead")
|
||||
return
|
||||
}
|
||||
t.Wiggle()
|
||||
t.Drop(env, 1, "scent")
|
||||
t.Step(env)
|
||||
if env.HasValue(t.Pos()) {
|
||||
env.TakeValue(t.Pos())
|
||||
sm.Energy += 1
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
experiment := new(experiments.Experiment)
|
||||
experiment.InitializeExperiment()
|
||||
experiment.InitEnvironment(func(env *core.Environment) {
|
||||
for i := 0; i < 600; i++ {
|
||||
x := rand.Intn(env.Width())
|
||||
y := rand.Intn(env.Height())
|
||||
env.PutValue(x, y)
|
||||
}
|
||||
})
|
||||
experiment.InitNTurtles(func() core.Actor {
|
||||
sm := new(Predator)
|
||||
return sm
|
||||
}, *numPred)
|
||||
experiment.InitNTurtles(func() core.Actor {
|
||||
sm := new(Prey)
|
||||
return sm
|
||||
}, *numPrey)
|
||||
experiment.InitPheromone("scent", color.RGBA{0x80, 0xFF, 0x00, 0x00})
|
||||
experiment.OnStep = func(env *core.Environment, turtles []*core.Turtle, step int) {
|
||||
alive := 0
|
||||
predalive := 0
|
||||
|
||||
// Grow Grass
|
||||
x := rand.Intn(env.Width())
|
||||
y := rand.Intn(env.Height())
|
||||
env.PutValue(x, y)
|
||||
|
||||
for _, turtle := range turtles {
|
||||
if turtle.GetAttribute("type") == "prey" && turtle.GetAttribute("status") != "dead" {
|
||||
alive++
|
||||
prey := turtle.GetActor().(*Prey)
|
||||
if prey.Steps > 10 && prey.Energy > 5 && rand.Intn(5) == 1 {
|
||||
experiment.InitNTurtles(func() core.Actor {
|
||||
sm := new(Prey)
|
||||
return sm
|
||||
}, 1)
|
||||
alive++
|
||||
}
|
||||
}
|
||||
if turtle.GetAttribute("type") == "predator" && turtle.GetAttribute("status") != "dead" {
|
||||
predalive++
|
||||
|
||||
if turtle.GetAttribute("type") == "predator" {
|
||||
pred := turtle.GetActor().(*Predator)
|
||||
if pred.Energy >= 80 && rand.Intn(16) == 1 {
|
||||
experiment.InitNTurtles(func() core.Actor {
|
||||
sm := new(Predator)
|
||||
return sm
|
||||
}, 1)
|
||||
predalive++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if step%10 == 0 {
|
||||
fmt.Printf("Prey Alive: %v | Pred Alive: %v \n", alive, predalive)
|
||||
}
|
||||
}
|
||||
experiment.Run()
|
||||
}
|
|
@ -7,7 +7,7 @@ import (
|
|||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
//"strconv"
|
||||
// "strconv"
|
||||
)
|
||||
|
||||
type Graphics struct {
|
||||
|
@ -87,16 +87,20 @@ func (g *Graphics) Render(env *core.Environment, turtles []*core.Turtle) {
|
|||
}
|
||||
}
|
||||
|
||||
g.renderer.SetDrawColor(0xF3, 0x81, 0, 0x00)
|
||||
for _, t := range turtles {
|
||||
if t.GetAttribute("status") == "dead" {
|
||||
continue
|
||||
}
|
||||
x, y := t.Pos()
|
||||
col := t.GetColor()
|
||||
g.renderer.SetDrawColor(col.R, col.G, col.B, col.A)
|
||||
g.DrawTileColor(int32(x), int32(y))
|
||||
t.Run(env)
|
||||
}
|
||||
|
||||
// TODO: Move this into an environment specification
|
||||
for name := range g.colorMap {
|
||||
env.Evaporate(0.99, name)
|
||||
env.Evaporate(0.95, name)
|
||||
}
|
||||
|
||||
g.renderer.Present()
|
||||
|
|
Loading…
Reference in New Issue