Compare commits
No commits in common. "master" and "master" have entirely different histories.
|
@ -1,10 +1,8 @@
|
||||||
/vendor/
|
|
||||||
# ---> Go
|
# ---> Go
|
||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
*.o
|
*.o
|
||||||
*.a
|
*.a
|
||||||
*.so
|
*.so
|
||||||
*csv
|
|
||||||
|
|
||||||
# Folders
|
# Folders
|
||||||
_obj
|
_obj
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
package actors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.openprivacy.ca/sarah/microworlds/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Ant struct {
|
||||||
|
SniffDistance int
|
||||||
|
Carrying bool
|
||||||
|
DropSize float32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Ant) Setup(env *core.Environment, t *core.Turtle) {
|
||||||
|
//t.SetXY(150,150)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Ant) Run(env *core.Environment, t *core.Turtle) {
|
||||||
|
if a.Carrying == false {
|
||||||
|
if env.HasValue(t.Pos()) {
|
||||||
|
env.TakeValue(t.Pos())
|
||||||
|
a.Carrying = true
|
||||||
|
a.DropSize = 100
|
||||||
|
t.TurnAround()
|
||||||
|
} else {
|
||||||
|
t.Wiggle()
|
||||||
|
t.FollowGradient(env, a.SniffDistance, 5, "food")
|
||||||
|
}
|
||||||
|
t.Step(env)
|
||||||
|
} else if a.Carrying == true {
|
||||||
|
a.DropSize -= 0.6
|
||||||
|
t.Drop(env, a.DropSize, "food")
|
||||||
|
t.Wiggle()
|
||||||
|
t.Step(env)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package actors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.openprivacy.ca/sarah/microworlds/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SlimeMold struct {
|
||||||
|
SniffDistance int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *SlimeMold) Setup(env *core.Environment, t *core.Turtle) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sm *SlimeMold) Run(env *core.Environment, t *core.Turtle) {
|
||||||
|
t.Wiggle()
|
||||||
|
t.FollowGradient(env, sm.SniffDistance, 2, "trail")
|
||||||
|
t.Step(env)
|
||||||
|
t.Drop(env, 1, "trail")
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package actors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.openprivacy.ca/sarah/microworlds/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type WoodChips struct {
|
||||||
|
SniffDistance int
|
||||||
|
Carrying bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WoodChips) Setup(env *core.Environment, t *core.Turtle) {
|
||||||
|
//t.SetXY(150,150)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *WoodChips) Run(env *core.Environment, t *core.Turtle) {
|
||||||
|
if a.Carrying {
|
||||||
|
if env.HasValue(t.Pos()) {
|
||||||
|
for {
|
||||||
|
t.Wiggle()
|
||||||
|
t.Step(env)
|
||||||
|
if !env.HasValue(t.Pos()) {
|
||||||
|
env.PutValue(t.Pos())
|
||||||
|
a.Carrying = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if env.HasValue(t.Pos()) {
|
||||||
|
env.TakeValue(t.Pos())
|
||||||
|
a.Carrying = true
|
||||||
|
t.TurnAround()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Wiggle()
|
||||||
|
t.Step(env)
|
||||||
|
}
|
|
@ -1,61 +1,20 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/foolusion/quadtree"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Environment struct {
|
type Environment struct {
|
||||||
width, height int
|
width, height int
|
||||||
state map[string][][]float32
|
state map[string][][]float32
|
||||||
value [][]bool
|
value [][]bool
|
||||||
col [][]*Turtle
|
col [][]bool
|
||||||
Step int
|
|
||||||
quadtree *quadtree.QuadTree
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Environment) Width() int {
|
func (e *Environment) Width() int {
|
||||||
return e.width
|
return e.width
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Environment) GetNearestNeighbours(bounding *quadtree.AABB, num int) (turtles []*Turtle) {
|
|
||||||
points := e.quadtree.SearchArea(bounding)
|
|
||||||
// fmt.Printf("Found X neighbours %v\n",len(points))
|
|
||||||
for _, point := range points {
|
|
||||||
if len(turtles) < num+1 {
|
|
||||||
x, y := point.X, point.Y
|
|
||||||
|
|
||||||
if e.Get(int(x), int(y)) != nil { // WHY DOES THIS HAPPEN?!?!
|
|
||||||
turtles = append(turtles, e.Get(int(x), int(y)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Environment) InsertIntoQuadTree(turtle *Turtle) {
|
|
||||||
e.quadtree.Insert(quadtree.NewXY(float64(turtle.xpos), float64(turtle.ypos)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Environment) ResetQuadtree() {
|
|
||||||
center := quadtree.NewXY(150, 150)
|
|
||||||
area := quadtree.NewAABB(*center, *center)
|
|
||||||
e.quadtree = quadtree.New(*area, 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Environment) Height() int {
|
func (e *Environment) Height() int {
|
||||||
return e.height
|
return e.height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Environment) GetPheromones() []string {
|
|
||||||
keys := make([]string, len(e.state))
|
|
||||||
i := 0
|
|
||||||
for k := range e.state {
|
|
||||||
keys[i] = k
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return keys
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Environment) InitPheromone(name string) {
|
func (e *Environment) InitPheromone(name string) {
|
||||||
state := make([][]float32, e.width)
|
state := make([][]float32, e.width)
|
||||||
for x := range state {
|
for x := range state {
|
||||||
|
@ -70,9 +29,9 @@ func NewEnvironment(width int, height int) *Environment {
|
||||||
env.height = height
|
env.height = height
|
||||||
env.state = make(map[string][][]float32)
|
env.state = make(map[string][][]float32)
|
||||||
|
|
||||||
env.col = make([][]*Turtle, width)
|
env.col = make([][]bool, width)
|
||||||
for x := range env.col {
|
for x := range env.col {
|
||||||
env.col[x] = make([]*Turtle, height)
|
env.col[x] = make([]bool, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
env.value = make([][]bool, width)
|
env.value = make([][]bool, width)
|
||||||
|
@ -95,21 +54,16 @@ func (e *Environment) Mark(pheromone string, x, y int, amount float32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Environment) Occupy(turtle *Turtle, x, y int) {
|
func (e Environment) Occupy(x, y int) {
|
||||||
e.col[x][y] = turtle
|
e.col[x][y] = true
|
||||||
}
|
|
||||||
|
|
||||||
func (e Environment) Get(x, y int) *Turtle {
|
|
||||||
return e.col[x][y]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Environment) Check(x, y int) bool {
|
func (e Environment) Check(x, y int) bool {
|
||||||
x, y = e.normXY(x, y)
|
return e.col[x][y]
|
||||||
return e.col[x][y] != nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Environment) Leave(x, y int) {
|
func (e Environment) Leave(x, y int) {
|
||||||
e.col[x][y] = nil
|
e.col[x][y] = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Environment) HasValue(x, y int) bool {
|
func (e Environment) HasValue(x, y int) bool {
|
||||||
|
@ -145,19 +99,20 @@ func (e *Environment) normXY(x int, y int) (int, int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Environment) Evaporate(rate float32, pheromone string) {
|
func (e *Environment) Evaporate(rate float32, pheromone string) {
|
||||||
for x := 0; x < e.width; x++ {
|
//log.Debugf("Evap")
|
||||||
for y := 0; y < e.height; y++ {
|
|
||||||
e.state[pheromone][x][y] = e.state[pheromone][x][y] * rate
|
_, exists := e.state[pheromone]
|
||||||
}
|
if !exists {
|
||||||
}
|
e.InitPheromone(pheromone)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Environment) EvaporateAndDiffuse(rate float32, pheromone string) {
|
|
||||||
pheromoneprev := pheromone + "prev"
|
pheromoneprev := pheromone + "prev"
|
||||||
|
|
||||||
e.state[pheromoneprev] = make([][]float32, e.width)
|
e.state[pheromoneprev] = make([][]float32, e.width)
|
||||||
for x := range e.state[pheromoneprev] {
|
for x := range e.state[pheromoneprev] {
|
||||||
e.state[pheromoneprev][x] = make([]float32, e.height)
|
e.state[pheromoneprev][x] = make([]float32, e.height)
|
||||||
|
}
|
||||||
|
for x := 0; x < e.width; x++ {
|
||||||
for y := 0; y < e.height; y++ {
|
for y := 0; y < e.height; y++ {
|
||||||
e.state[pheromoneprev][x][y] = e.state[pheromone][x][y] * rate
|
e.state[pheromoneprev][x][y] = e.state[pheromone][x][y] * rate
|
||||||
}
|
}
|
||||||
|
@ -176,33 +131,6 @@ func (e *Environment) EvaporateAndDiffuse(rate float32, pheromone string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Environment) Diffuse(pheromone string) {
|
|
||||||
pheromoneprev := pheromone + "prev"
|
|
||||||
|
|
||||||
e.state[pheromoneprev] = make([][]float32, e.width)
|
|
||||||
for x := range e.state[pheromoneprev] {
|
|
||||||
e.state[pheromoneprev][x] = make([]float32, e.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
for x := 0; x < e.width; x++ {
|
|
||||||
for y := 0; y < e.height; y++ {
|
|
||||||
e.state[pheromoneprev][x][y] = e.state[pheromone][x][y]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pheromoneMap := e.state[pheromoneprev]
|
|
||||||
for x := 0; x < e.width; x++ {
|
|
||||||
for y := 0; y < e.height; y++ {
|
|
||||||
amount := e.state[pheromoneprev][x][y]
|
|
||||||
|
|
||||||
totalAmount := amount + e.sniffNormalized(x-1, y-1, pheromoneMap) + e.sniffNormalized(x, y-1, pheromoneMap) + e.sniffNormalized(x+1, y-1, pheromoneMap) + e.sniffNormalized(x-1, y, pheromoneMap) + e.sniffNormalized(x+1, y, pheromoneMap)
|
|
||||||
totalAmount += e.sniffNormalized(x-1, y+1, pheromoneMap) + e.sniffNormalized(x, y+1, pheromoneMap) + e.sniffNormalized(x+1, y+1, pheromoneMap)
|
|
||||||
|
|
||||||
e.state[pheromone][x][y] = totalAmount / 9
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Internal optimaization to avoid slow map access
|
// Internal optimaization to avoid slow map access
|
||||||
func (e *Environment) sniffNormalized(x int, y int, pheromonemap [][]float32) float32 {
|
func (e *Environment) sniffNormalized(x int, y int, pheromonemap [][]float32) float32 {
|
||||||
x, y = e.normXY(x, y)
|
x, y = e.normXY(x, y)
|
||||||
|
|
285
core/turtle.go
285
core/turtle.go
|
@ -1,8 +1,6 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"image/color"
|
|
||||||
"math"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -10,9 +8,6 @@ type Turtle struct {
|
||||||
xpos, ypos int
|
xpos, ypos int
|
||||||
heading int
|
heading int
|
||||||
actor Actor
|
actor Actor
|
||||||
width, height int
|
|
||||||
col color.RGBA
|
|
||||||
atts map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type NilActor struct {
|
type NilActor struct {
|
||||||
|
@ -24,40 +19,20 @@ func (NilActor) Setup(*Environment, *Turtle) {
|
||||||
func (NilActor) Run(*Environment, *Turtle) {
|
func (NilActor) Run(*Environment, *Turtle) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Turtle) GetActor() Actor {
|
|
||||||
return t.actor
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Turtle) Heading() int {
|
|
||||||
return t.heading
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTurtle(env *Environment, actor Actor) *Turtle {
|
func NewTurtle(env *Environment, actor Actor) *Turtle {
|
||||||
|
for {
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
turtle := new(Turtle)
|
turtle := new(Turtle)
|
||||||
turtle.width = env.width
|
|
||||||
turtle.height = env.height
|
|
||||||
turtle.xpos = rand.Intn(env.width)
|
turtle.xpos = rand.Intn(env.width)
|
||||||
turtle.ypos = rand.Intn(env.height)
|
turtle.ypos = rand.Intn(env.height)
|
||||||
turtle.actor = actor
|
turtle.actor = actor
|
||||||
turtle.atts = make(map[string]string)
|
if env.Check(turtle.xpos, turtle.ypos) == false {
|
||||||
if env.Check(turtle.xpos, turtle.ypos) == false && env.HasValue(turtle.xpos, turtle.ypos) == false {
|
|
||||||
turtle.setRandomHeading()
|
|
||||||
actor.Setup(env, turtle)
|
actor.Setup(env, turtle)
|
||||||
env.Occupy(turtle, turtle.xpos, turtle.ypos)
|
env.Occupy(turtle.xpos, turtle.ypos)
|
||||||
|
turtle.setRandomHeading()
|
||||||
return turtle
|
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) {
|
func (t *Turtle) Pos() (int, int) {
|
||||||
|
@ -71,19 +46,6 @@ func (t *Turtle) setRandomHeading() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Turtle) SetXY(x, y int) {
|
func (t *Turtle) SetXY(x, y int) {
|
||||||
|
|
||||||
if x < 0 {
|
|
||||||
x = (t.width - 1)
|
|
||||||
} else if x >= t.width {
|
|
||||||
x = x % (t.width)
|
|
||||||
}
|
|
||||||
|
|
||||||
if y < 0 {
|
|
||||||
y = (t.height - 1)
|
|
||||||
} else if y >= t.height {
|
|
||||||
y = y % (t.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.xpos = x
|
t.xpos = x
|
||||||
t.ypos = y
|
t.ypos = y
|
||||||
}
|
}
|
||||||
|
@ -97,18 +59,6 @@ func (t *Turtle) Wiggle() {
|
||||||
t.heading = h
|
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) SetHeading(heading int) {
|
|
||||||
t.heading = heading
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Turtle) TurnAround() {
|
func (t *Turtle) TurnAround() {
|
||||||
t.heading = (t.heading + 4) % 8
|
t.heading = (t.heading + 4) % 8
|
||||||
}
|
}
|
||||||
|
@ -117,98 +67,6 @@ func (t *Turtle) Drop(env *Environment, amount float32, pheromone string) {
|
||||||
env.Mark(pheromone, t.xpos, t.ypos, amount)
|
env.Mark(pheromone, t.xpos, t.ypos, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Turtle) AmountAll(env *Environment, distance int, pheromone string) float32 {
|
|
||||||
total := float32(0)
|
|
||||||
for i := 0; i < 8; i++ {
|
|
||||||
dx0 := headings[i][0] * distance
|
|
||||||
dy0 := headings[i][1] * distance
|
|
||||||
|
|
||||||
x0 := (t.xpos + dx0)
|
|
||||||
y0 := (t.ypos + dy0)
|
|
||||||
|
|
||||||
total += env.SniffNormalized(x0, y0, pheromone)
|
|
||||||
}
|
|
||||||
|
|
||||||
return total
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Turtle) Amount(env *Environment, distance int, pheromone string) float32 {
|
|
||||||
h0 := t.heading - 1
|
|
||||||
if h0 < 0 {
|
|
||||||
h0 = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
dx0 := headings[h0][0] * distance
|
|
||||||
dy0 := headings[h0][1] * distance
|
|
||||||
|
|
||||||
x0 := (t.xpos + dx0)
|
|
||||||
y0 := (t.ypos + dy0)
|
|
||||||
|
|
||||||
dx := headings[t.heading][0] * distance
|
|
||||||
dy := headings[t.heading][1] * distance
|
|
||||||
|
|
||||||
x := (t.xpos + dx)
|
|
||||||
y := (t.ypos + dy)
|
|
||||||
|
|
||||||
h1 := (t.heading + 1) % 8
|
|
||||||
dx1 := headings[h1][0] * distance
|
|
||||||
dy1 := headings[h1][1] * distance
|
|
||||||
|
|
||||||
x1 := (t.xpos + dx1)
|
|
||||||
y1 := (t.ypos + dy1)
|
|
||||||
|
|
||||||
as0 := env.SniffNormalized(x0, y0, pheromone)
|
|
||||||
as := env.SniffNormalized(x, y, pheromone)
|
|
||||||
as1 := env.SniffNormalized(x1, y1, pheromone)
|
|
||||||
return as0 + as + as1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Turtle) Near(env *Environment, distance int, threshold float32, pheromone string) bool {
|
|
||||||
h0 := t.heading - 1
|
|
||||||
if h0 < 0 {
|
|
||||||
h0 = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
dx0 := headings[h0][0] * distance
|
|
||||||
dy0 := headings[h0][1] * distance
|
|
||||||
|
|
||||||
x0 := (t.xpos + dx0)
|
|
||||||
y0 := (t.ypos + dy0)
|
|
||||||
|
|
||||||
dx := headings[t.heading][0] * distance
|
|
||||||
dy := headings[t.heading][1] * distance
|
|
||||||
|
|
||||||
x := (t.xpos + dx)
|
|
||||||
y := (t.ypos + dy)
|
|
||||||
|
|
||||||
h1 := (t.heading + 1) % 8
|
|
||||||
dx1 := headings[h1][0] * distance
|
|
||||||
dy1 := headings[h1][1] * distance
|
|
||||||
|
|
||||||
x1 := (t.xpos + dx1)
|
|
||||||
y1 := (t.ypos + dy1)
|
|
||||||
|
|
||||||
as0 := env.SniffNormalized(x0, y0, pheromone)
|
|
||||||
if as0 < threshold {
|
|
||||||
as0 = 0
|
|
||||||
}
|
|
||||||
as := env.SniffNormalized(x, y, pheromone)
|
|
||||||
if as < threshold {
|
|
||||||
as = 0
|
|
||||||
}
|
|
||||||
as1 := env.SniffNormalized(x1, y1, pheromone)
|
|
||||||
if as1 < threshold {
|
|
||||||
as1 = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if as0 == 0 && as == 0 && as1 == 0 {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Turtle) FollowGradient(env *Environment, distance int, threshold float32, pheromone string) {
|
func (t *Turtle) FollowGradient(env *Environment, distance int, threshold float32, pheromone string) {
|
||||||
|
|
||||||
h0 := t.heading - 1
|
h0 := t.heading - 1
|
||||||
|
@ -255,139 +113,6 @@ func (t *Turtle) FollowGradient(env *Environment, distance int, threshold float3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Turtle) RejectGradient(env *Environment, distance int, pheromone string) {
|
|
||||||
|
|
||||||
h0 := t.heading - 1
|
|
||||||
if h0 < 0 {
|
|
||||||
h0 = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
dx0 := headings[h0][0] * distance
|
|
||||||
dy0 := headings[h0][1] * distance
|
|
||||||
|
|
||||||
x0 := (t.xpos + dx0)
|
|
||||||
y0 := (t.ypos + dy0)
|
|
||||||
|
|
||||||
dx := headings[t.heading][0] * distance
|
|
||||||
dy := headings[t.heading][1] * distance
|
|
||||||
|
|
||||||
x := (t.xpos + dx)
|
|
||||||
y := (t.ypos + dy)
|
|
||||||
|
|
||||||
h1 := (t.heading + 1) % 8
|
|
||||||
dx1 := headings[h1][0] * distance
|
|
||||||
dy1 := headings[h1][1] * distance
|
|
||||||
|
|
||||||
x1 := (t.xpos + dx1)
|
|
||||||
y1 := (t.ypos + dy1)
|
|
||||||
|
|
||||||
as0 := env.SniffNormalized(x0, y0, pheromone)
|
|
||||||
as := env.SniffNormalized(x, y, pheromone)
|
|
||||||
as1 := env.SniffNormalized(x1, y1, pheromone)
|
|
||||||
|
|
||||||
if as0 > as && as0 > as1 {
|
|
||||||
t.heading = h0
|
|
||||||
} else if as1 > as && as1 > as0 {
|
|
||||||
t.heading = h1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Turtle) AvoidAverageGradient(env *Environment, distance int, threshold float32, pheromone string) {
|
|
||||||
|
|
||||||
h0 := t.heading - 1
|
|
||||||
if h0 < 0 {
|
|
||||||
h0 = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
dx0 := headings[h0][0] * distance
|
|
||||||
dy0 := headings[h0][1] * distance
|
|
||||||
|
|
||||||
x0 := (t.xpos + dx0)
|
|
||||||
y0 := (t.ypos + dy0)
|
|
||||||
|
|
||||||
dx := headings[t.heading][0] * distance
|
|
||||||
dy := headings[t.heading][1] * distance
|
|
||||||
|
|
||||||
x := (t.xpos + dx)
|
|
||||||
y := (t.ypos + dy)
|
|
||||||
|
|
||||||
h1 := (t.heading + 1) % 8
|
|
||||||
dx1 := headings[h1][0] * distance
|
|
||||||
dy1 := headings[h1][1] * distance
|
|
||||||
|
|
||||||
x1 := (t.xpos + dx1)
|
|
||||||
y1 := (t.ypos + dy1)
|
|
||||||
|
|
||||||
as0 := env.SniffNormalized(x0, y0, pheromone)
|
|
||||||
as := env.SniffNormalized(x, y, pheromone)
|
|
||||||
as1 := env.SniffNormalized(x1, y1, pheromone)
|
|
||||||
|
|
||||||
avg := float64((1 * as0) + (2 * as) + (3*as1)/(as0+as+as1))
|
|
||||||
|
|
||||||
heading := math.Round(avg)
|
|
||||||
if heading < 1 && as0 > threshold {
|
|
||||||
t.heading = h1
|
|
||||||
} else if heading > 2 && as1 > threshold {
|
|
||||||
t.heading = h0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Turtle) FollowAverageGradient(env *Environment, distance int, threshold float32, pheromone string) {
|
|
||||||
|
|
||||||
h0 := t.heading - 1
|
|
||||||
if h0 < 0 {
|
|
||||||
h0 = 7
|
|
||||||
}
|
|
||||||
|
|
||||||
dx0 := headings[h0][0] * distance
|
|
||||||
dy0 := headings[h0][1] * distance
|
|
||||||
|
|
||||||
x0 := (t.xpos + dx0)
|
|
||||||
y0 := (t.ypos + dy0)
|
|
||||||
|
|
||||||
dx := headings[t.heading][0] * distance
|
|
||||||
dy := headings[t.heading][1] * distance
|
|
||||||
|
|
||||||
x := (t.xpos + dx)
|
|
||||||
y := (t.ypos + dy)
|
|
||||||
|
|
||||||
h1 := (t.heading + 1) % 8
|
|
||||||
dx1 := headings[h1][0] * distance
|
|
||||||
dy1 := headings[h1][1] * distance
|
|
||||||
|
|
||||||
x1 := (t.xpos + dx1)
|
|
||||||
y1 := (t.ypos + dy1)
|
|
||||||
|
|
||||||
as0 := env.SniffNormalized(x0, y0, pheromone)
|
|
||||||
as := env.SniffNormalized(x, y, pheromone)
|
|
||||||
as1 := env.SniffNormalized(x1, y1, pheromone)
|
|
||||||
|
|
||||||
avg := float64((1 * as0) + (2 * as) + (3*as1)/(as0+as+as1))
|
|
||||||
|
|
||||||
heading := math.Round(avg)
|
|
||||||
if heading < 1 && as0 > threshold {
|
|
||||||
t.heading = h0
|
|
||||||
} else if heading > 2 && as1 > threshold {
|
|
||||||
t.heading = h1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
func (t *Turtle) Step(env *Environment) bool {
|
||||||
dx := headings[t.heading][0]
|
dx := headings[t.heading][0]
|
||||||
dy := headings[t.heading][1]
|
dy := headings[t.heading][1]
|
||||||
|
@ -410,7 +135,7 @@ func (t *Turtle) Step(env *Environment) bool {
|
||||||
t.ypos = oy
|
t.ypos = oy
|
||||||
success = false
|
success = false
|
||||||
}
|
}
|
||||||
env.Occupy(t, t.xpos, t.ypos)
|
env.Occupy(t.xpos, t.ypos)
|
||||||
return success
|
return success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,376 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"github.com/wcharczuk/go-chart"
|
|
||||||
"image/color"
|
|
||||||
"math/rand"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"runtime/pprof"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Player struct {
|
|
||||||
dna [40]int
|
|
||||||
Team int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *Player) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
for i := 0; i < len(player.dna); i++ {
|
|
||||||
player.dna[i] = rand.Intn(NumGenes)
|
|
||||||
}
|
|
||||||
t.SetAttribute("team", strconv.Itoa(player.Team))
|
|
||||||
if player.Team == 1 {
|
|
||||||
t.SetColor(color.RGBA{0xFF, 0x00, 0x00, 0xFF})
|
|
||||||
} else {
|
|
||||||
t.SetColor(color.RGBA{0x00, 0x00, 0xFF, 0xFF})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
Wiggle = iota
|
|
||||||
FollowMyTeam
|
|
||||||
FollowOtherTeam
|
|
||||||
FollowBall
|
|
||||||
Drop
|
|
||||||
RetreatMyTeam
|
|
||||||
RetreatOtherTeam
|
|
||||||
RetreatBall
|
|
||||||
TurnAround
|
|
||||||
HeadTowardsOurGoal
|
|
||||||
HeadTowardsOtherGoal
|
|
||||||
)
|
|
||||||
|
|
||||||
var NumGenes = 11
|
|
||||||
|
|
||||||
func (player *Player) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
|
|
||||||
MyTeam := strconv.Itoa(player.Team)
|
|
||||||
OtherTeam := "1"
|
|
||||||
if player.Team == 1 {
|
|
||||||
OtherTeam = "2"
|
|
||||||
}
|
|
||||||
|
|
||||||
ahead := t.Check(env)
|
|
||||||
if ahead != nil {
|
|
||||||
ball, ok := ahead.GetActor().(*Ball)
|
|
||||||
if ok {
|
|
||||||
ahead.SetHeading(t.Heading())
|
|
||||||
if rand.Intn(5) == 0 {
|
|
||||||
ahead.Wiggle()
|
|
||||||
}
|
|
||||||
ahead.Step(env)
|
|
||||||
ball.Check(env, ahead)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Step(env)
|
|
||||||
|
|
||||||
for i := 0; i < len(player.dna); i++ {
|
|
||||||
switch player.dna[i] {
|
|
||||||
case TurnAround:
|
|
||||||
t.TurnAround()
|
|
||||||
case Wiggle:
|
|
||||||
t.Wiggle()
|
|
||||||
case FollowMyTeam:
|
|
||||||
if i+2 < len(player.dna) {
|
|
||||||
t.FollowGradient(env, player.dna[i+1], float32(player.dna[i+2]), MyTeam)
|
|
||||||
i += 2
|
|
||||||
}
|
|
||||||
case FollowOtherTeam:
|
|
||||||
if i+2 < len(player.dna) {
|
|
||||||
t.FollowGradient(env, player.dna[i+1], float32(player.dna[i+2]), OtherTeam)
|
|
||||||
i += 2
|
|
||||||
}
|
|
||||||
case FollowBall:
|
|
||||||
t.FollowGradient(env, 1, 0, "ball")
|
|
||||||
case Drop:
|
|
||||||
if i+1 < len(player.dna) {
|
|
||||||
t.Drop(env, float32(player.dna[i+1]), strconv.Itoa(player.Team))
|
|
||||||
}
|
|
||||||
case RetreatMyTeam:
|
|
||||||
if i+2 < len(player.dna) {
|
|
||||||
t.AvoidAverageGradient(env, player.dna[i+1], float32(player.dna[i+2]), MyTeam)
|
|
||||||
i += 2
|
|
||||||
}
|
|
||||||
case RetreatOtherTeam:
|
|
||||||
if i+2 < len(player.dna) {
|
|
||||||
t.AvoidAverageGradient(env, player.dna[i+1], float32(player.dna[i+2]), OtherTeam)
|
|
||||||
i += 2
|
|
||||||
}
|
|
||||||
case RetreatBall:
|
|
||||||
if i+2 < len(player.dna) {
|
|
||||||
t.AvoidAverageGradient(env, player.dna[i+1], float32(player.dna[i+2]), "ball")
|
|
||||||
i += 2
|
|
||||||
}
|
|
||||||
case HeadTowardsOurGoal:
|
|
||||||
x, _ := t.Pos()
|
|
||||||
if player.Team == 1 {
|
|
||||||
if x > 1 {
|
|
||||||
t.SetHeading(7)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if x < 299 {
|
|
||||||
t.SetHeading(3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case HeadTowardsOtherGoal:
|
|
||||||
x, _ := t.Pos()
|
|
||||||
if player.Team == 2 {
|
|
||||||
if x > 1 {
|
|
||||||
t.SetHeading(7)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if x < 299 {
|
|
||||||
t.SetHeading(3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *Player) Mutate() {
|
|
||||||
mutatePoint := rand.Intn(len(player.dna))
|
|
||||||
fmt.Printf("\t\t Mutating %v at %v\n", player.Team, mutatePoint)
|
|
||||||
player.dna[mutatePoint] = rand.Intn(NumGenes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (player *Player) Clone(parentA *Player, parentB *Player) {
|
|
||||||
fmt.Printf("\t\tCrossing Over team %v with:%v %v\n", player.Team, parentA.dna, parentB.dna)
|
|
||||||
crossoverPoint := rand.Intn(len(player.dna))
|
|
||||||
copy(player.dna[0:crossoverPoint], parentA.dna[0:crossoverPoint])
|
|
||||||
copy(player.dna[crossoverPoint:], parentB.dna[crossoverPoint:])
|
|
||||||
}
|
|
||||||
|
|
||||||
type Ball struct {
|
|
||||||
Team1Score int
|
|
||||||
Team2Score int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Ball) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.SetXY(50, 50)
|
|
||||||
t.SetColor(color.RGBA{0xFF, 0xFF, 0xFF, 0xFF})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Ball) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
b.Check(env, t)
|
|
||||||
t.Drop(env, 10, "ball")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Ball) Check(env *core.Environment, t *core.Turtle) {
|
|
||||||
x, _ := t.Pos()
|
|
||||||
if x > 98 {
|
|
||||||
fmt.Printf("\t\tTeam 1 Scored!!! %v\n", env.Step)
|
|
||||||
b.Reset(env, t)
|
|
||||||
b.Team1Score++
|
|
||||||
} else if x < 1 {
|
|
||||||
fmt.Printf("\t\tTeam 2 Scored!!! %v\n", env.Step)
|
|
||||||
b.Reset(env, t)
|
|
||||||
b.Team2Score++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Ball) Reset(env *core.Environment, t *core.Turtle) {
|
|
||||||
x, y := t.Pos()
|
|
||||||
t.SetHeading(rand.Intn(8))
|
|
||||||
env.Leave(x, y)
|
|
||||||
t.SetXY(50, 50)
|
|
||||||
env.Occupy(t, 50, 50)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
ball := new(Ball)
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
player := new(Player)
|
|
||||||
player.Team = 1
|
|
||||||
return player
|
|
||||||
}, 25)
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
player := new(Player)
|
|
||||||
player.Team = 2
|
|
||||||
return player
|
|
||||||
}, 25)
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
return ball
|
|
||||||
}, 1)
|
|
||||||
experiment.InitPheromone("1", color.RGBA{0xFF, 0x00, 0x00, 0x00})
|
|
||||||
experiment.InitPheromone("2", color.RGBA{0x00, 0x00, 0xFF, 0x00})
|
|
||||||
experiment.InitPheromone("ball", color.RGBA{0xff, 0xff, 0xff, 0xff})
|
|
||||||
|
|
||||||
x := []float64{-2}
|
|
||||||
team1 := []float64{0}
|
|
||||||
team2 := []float64{1}
|
|
||||||
|
|
||||||
var graph chart.Chart
|
|
||||||
experiment.AddPlot("Goals Scored", func(environment *core.Environment, turtles []*core.Turtle) *chart.Chart {
|
|
||||||
x = append(x, float64(environment.Step))
|
|
||||||
team1 = append(team1, float64(ball.Team1Score))
|
|
||||||
team2 = append(team2, float64(ball.Team2Score))
|
|
||||||
graph = chart.Chart{
|
|
||||||
Background: chart.Style{
|
|
||||||
Padding: chart.Box{
|
|
||||||
Top: 50,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
XAxis: chart.XAxis{Name: "Time Step", NameStyle: chart.Style{Show: true}, Style: chart.Style{Show: true, TextRotationDegrees: 90}, ValueFormatter: func(v interface{}) string {
|
|
||||||
return fmt.Sprintf("%d", int(v.(float64)))
|
|
||||||
}},
|
|
||||||
YAxis: chart.YAxis{Name: "Goals Scored", NameStyle: chart.Style{Show: true}, Style: chart.Style{Show: true}, ValueFormatter: func(v interface{}) string {
|
|
||||||
return fmt.Sprintf("%d", int(v.(float64)))
|
|
||||||
}},
|
|
||||||
Series: []chart.Series{
|
|
||||||
chart.ContinuousSeries{
|
|
||||||
XValues: x,
|
|
||||||
YValues: team1,
|
|
||||||
},
|
|
||||||
chart.ContinuousSeries{
|
|
||||||
XValues: x,
|
|
||||||
YValues: team2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return &graph
|
|
||||||
})
|
|
||||||
|
|
||||||
gamelengths := []int{}
|
|
||||||
gamewins := []int{}
|
|
||||||
gamescores := []int{}
|
|
||||||
lastGameStart := 0
|
|
||||||
|
|
||||||
experiment.OnStep = func(environment *core.Environment, turtles []*core.Turtle, i int) {
|
|
||||||
|
|
||||||
environment.EvaporateAndDiffuse(0.95, "ball")
|
|
||||||
environment.EvaporateAndDiffuse(0.95, "1")
|
|
||||||
environment.EvaporateAndDiffuse(0.95, "2")
|
|
||||||
|
|
||||||
if environment.Step-lastGameStart > 4000 {
|
|
||||||
fmt.Printf("Time!\n")
|
|
||||||
|
|
||||||
if ball.Team1Score == ball.Team2Score {
|
|
||||||
fmt.Printf("Draw!\n")
|
|
||||||
gamelengths = append(gamelengths, environment.Step-lastGameStart)
|
|
||||||
gamewins = append(gamewins, 0)
|
|
||||||
gamescores = append(gamescores, ball.Team1Score, ball.Team2Score)
|
|
||||||
lastGameStart = environment.Step
|
|
||||||
|
|
||||||
ball.Team2Score = 0
|
|
||||||
ball.Team1Score = 0
|
|
||||||
|
|
||||||
red, blue := GetTeams(turtles)
|
|
||||||
for _, r := range red {
|
|
||||||
player := r.GetActor().(*Player)
|
|
||||||
player.Mutate()
|
|
||||||
player.Mutate()
|
|
||||||
player.Mutate()
|
|
||||||
player.Mutate()
|
|
||||||
player.Mutate()
|
|
||||||
}
|
|
||||||
for _, b := range blue {
|
|
||||||
player := b.GetActor().(*Player)
|
|
||||||
player.Mutate()
|
|
||||||
player.Mutate()
|
|
||||||
player.Mutate()
|
|
||||||
player.Mutate()
|
|
||||||
player.Mutate()
|
|
||||||
|
|
||||||
}
|
|
||||||
for i, lengths := range gamelengths {
|
|
||||||
fmt.Printf("Generation: %v, %v time steps Team %v Won (%v - %v)\n", i, lengths, gamewins[i], gamescores[i*2], gamescores[(i*2)+1])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ball.Team1Score++
|
|
||||||
ball.Team2Score++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ball.Team1Score >= 3 && ball.Team2Score < 3 {
|
|
||||||
fmt.Printf("Team 1 Win")
|
|
||||||
red, blue := GetTeams(turtles)
|
|
||||||
for _, b := range blue {
|
|
||||||
player := b.GetActor().(*Player)
|
|
||||||
parentA := rand.Intn(len(red))
|
|
||||||
parentB := rand.Intn(len(red))
|
|
||||||
player.Clone(red[parentA].GetActor().(*Player), red[parentB].GetActor().(*Player))
|
|
||||||
player.Mutate()
|
|
||||||
}
|
|
||||||
adjust := 0
|
|
||||||
if environment.Step-lastGameStart > 4000 {
|
|
||||||
adjust = (environment.Step - lastGameStart) - 4000
|
|
||||||
}
|
|
||||||
|
|
||||||
gamelengths = append(gamelengths, environment.Step-lastGameStart)
|
|
||||||
gamewins = append(gamewins, 1)
|
|
||||||
gamescores = append(gamescores, ball.Team1Score-adjust, ball.Team2Score-adjust)
|
|
||||||
lastGameStart = environment.Step
|
|
||||||
|
|
||||||
for i, lengths := range gamelengths {
|
|
||||||
fmt.Printf("Generation: %v, %v time steps Team %v Won (%v - %v)\n", i, lengths, gamewins[i], gamescores[i*2], gamescores[(i*2)+1])
|
|
||||||
}
|
|
||||||
|
|
||||||
ball.Team2Score = 0
|
|
||||||
ball.Team1Score = 0
|
|
||||||
|
|
||||||
} else if ball.Team2Score >= 3 && ball.Team1Score < 3 {
|
|
||||||
fmt.Printf("Team 2 Win")
|
|
||||||
red, blue := GetTeams(turtles)
|
|
||||||
for _, r := range red {
|
|
||||||
player := r.GetActor().(*Player)
|
|
||||||
parentA := rand.Intn(len(blue))
|
|
||||||
parentB := rand.Intn(len(blue))
|
|
||||||
player.Clone(blue[parentA].GetActor().(*Player), blue[parentB].GetActor().(*Player))
|
|
||||||
player.Mutate()
|
|
||||||
}
|
|
||||||
|
|
||||||
adjust := 0
|
|
||||||
if environment.Step-lastGameStart > 4000 {
|
|
||||||
adjust = (environment.Step - lastGameStart) - 4000
|
|
||||||
}
|
|
||||||
|
|
||||||
gamelengths = append(gamelengths, environment.Step-lastGameStart)
|
|
||||||
gamewins = append(gamewins, 2)
|
|
||||||
gamescores = append(gamescores, ball.Team1Score-adjust, ball.Team2Score-adjust)
|
|
||||||
lastGameStart = environment.Step
|
|
||||||
|
|
||||||
ball.Team2Score = 0
|
|
||||||
ball.Team1Score = 0
|
|
||||||
|
|
||||||
for i, lengths := range gamelengths {
|
|
||||||
fmt.Printf("Generation: %v, %v time steps Team %v Won (%v - %v)\n", i, lengths, gamewins[i], gamescores[i*2], gamescores[(i*2)+1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
c := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(c, os.Interrupt)
|
|
||||||
go func() {
|
|
||||||
for sig := range c {
|
|
||||||
fmt.Printf("Got Signal %v", sig)
|
|
||||||
pprof.StopCPUProfile()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetTeams(turtles []*core.Turtle) (redTeam, blueTeam []*core.Turtle) {
|
|
||||||
for _, turtle := range turtles {
|
|
||||||
if turtle.GetAttribute("team") == "1" {
|
|
||||||
redTeam = append(redTeam, turtle)
|
|
||||||
} else if turtle.GetAttribute("team") == "2" {
|
|
||||||
blueTeam = append(blueTeam, turtle)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,160 +0,0 @@
|
||||||
package experiments
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/graphics"
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
|
||||||
"github.com/wcharczuk/go-chart"
|
|
||||||
"image/color"
|
|
||||||
"log"
|
|
||||||
"math/rand"
|
|
||||||
"os"
|
|
||||||
"runtime/pprof"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
|
|
||||||
var width = flag.Int("width", 300, "width of environment")
|
|
||||||
var height = flag.Int("height", 300, "height of environment")
|
|
||||||
var pxsize = flag.Int("pxsize", 1, "pixels per tile edge")
|
|
||||||
var numTurtles = flag.Int("numTurtles", 5000, "number of turtles")
|
|
||||||
|
|
||||||
type Experiment struct {
|
|
||||||
env *core.Environment
|
|
||||||
turtles []*core.Turtle
|
|
||||||
graphics *graphics.Graphics
|
|
||||||
initializedTurtles int
|
|
||||||
pheromones []string
|
|
||||||
OnStep func(*core.Environment, []*core.Turtle, int)
|
|
||||||
plots []*graphics.Plot
|
|
||||||
running bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) InitializeExperiment() {
|
|
||||||
// We don't need real randomness
|
|
||||||
rand.Seed(time.Now().Unix())
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
if *cpuprofile != "" {
|
|
||||||
f, err := os.Create(*cpuprofile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
pprof.StartCPUProfile(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
e.OnStep = func(env *core.Environment, turtles []*core.Turtle, i int) {
|
|
||||||
for _, name := range e.pheromones {
|
|
||||||
env.EvaporateAndDiffuse(0.95, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.env = core.NewEnvironment(*width, *height)
|
|
||||||
e.turtles = make([]*core.Turtle, 0)
|
|
||||||
e.graphics = graphics.NewGraphics(int32(*width), int32(*height), int32(*pxsize))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) GetNumTurtles() int {
|
|
||||||
return (*numTurtles)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) InitPheromone(name string, col color.Color) {
|
|
||||||
e.env.InitPheromone(name)
|
|
||||||
r, g, b, a := col.RGBA()
|
|
||||||
e.pheromones = append(e.pheromones, name)
|
|
||||||
e.graphics.ColorPheromone(name, [4]uint8{uint8(r), uint8(g), uint8(b), uint8(a)})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) InitEnvironment(f func(environment *core.Environment)) {
|
|
||||||
f(e.env)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) InitNTurtles(f func() core.Actor, num int) {
|
|
||||||
numSuccess := 0
|
|
||||||
for i := e.initializedTurtles; i < e.initializedTurtles+num; i++ {
|
|
||||||
t := core.NewTurtle(e.env, f())
|
|
||||||
if t != nil {
|
|
||||||
e.turtles = append(e.turtles, t)
|
|
||||||
numSuccess++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e.initializedTurtles += numSuccess
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) InitTurtles(f func() core.Actor) {
|
|
||||||
e.InitNTurtles(f, (*numTurtles))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) AddPlot(title string, plotfunc func(environment *core.Environment, turtles []*core.Turtle) *chart.Chart) {
|
|
||||||
plot := graphics.NewPlot(title, int32(*width), int32(*height), int32(*pxsize))
|
|
||||||
plot.GeneratePlot = plotfunc
|
|
||||||
go plot.RenderAsync()
|
|
||||||
e.plots = append(e.plots, plot)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) Stop() {
|
|
||||||
e.running = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) Restart() {
|
|
||||||
e.running = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Experiment) Run() {
|
|
||||||
wait := sync.WaitGroup{}
|
|
||||||
|
|
||||||
e.running = true
|
|
||||||
wait.Add(1)
|
|
||||||
e.env.ResetQuadtree()
|
|
||||||
go func() {
|
|
||||||
step := 0
|
|
||||||
for e.running {
|
|
||||||
e.env.Step = step
|
|
||||||
e.graphics.Render(e.env, e.turtles)
|
|
||||||
e.OnStep(e.env, e.turtles, step)
|
|
||||||
|
|
||||||
for _, plot := range e.plots {
|
|
||||||
plot.Render(e.env, e.turtles)
|
|
||||||
}
|
|
||||||
|
|
||||||
newTurtles := make([]*core.Turtle, 0)
|
|
||||||
|
|
||||||
for _, t := range e.turtles {
|
|
||||||
t.Run(e.env)
|
|
||||||
if t.GetAttribute("status") != "dead" {
|
|
||||||
newTurtles = append(newTurtles, t)
|
|
||||||
} else {
|
|
||||||
e.env.Leave(t.Pos()) // Dead turtles occupy no space
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.turtles = newTurtles
|
|
||||||
e.env.ResetQuadtree()
|
|
||||||
for _, t := range e.turtles {
|
|
||||||
e.env.InsertIntoQuadTree(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
step++
|
|
||||||
}
|
|
||||||
wait.Done()
|
|
||||||
}()
|
|
||||||
|
|
||||||
wait.Add(1)
|
|
||||||
for e.running {
|
|
||||||
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
|
||||||
switch event.(type) {
|
|
||||||
case *sdl.QuitEvent:
|
|
||||||
e.running = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wait.Done()
|
|
||||||
wait.Wait()
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"github.com/foolusion/quadtree"
|
|
||||||
"image/color"
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sniffDistance = flag.Int("sniffDistance", 3, "the distance a turtle can detect pheromone levels from")
|
|
||||||
|
|
||||||
var W = 1
|
|
||||||
var envmap = [][]int{
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, W, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, W, 0, 0, W, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, W, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, W, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bird struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Bird) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.SetColor(color.RGBA{100, 255, 10, 0})
|
|
||||||
t.SetHeading(rand.Intn(8 ))
|
|
||||||
}
|
|
||||||
|
|
||||||
var searchtree = quadtree.XY{4, 4}
|
|
||||||
|
|
||||||
func (sm *Bird) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
//t.Wiggle()
|
|
||||||
|
|
||||||
t.FollowAverageGradient(env, 50,0.1, "bird")
|
|
||||||
t.RejectGradient(env, 0, "bird")
|
|
||||||
|
|
||||||
if !t.Step(env) {
|
|
||||||
//t.TurnAround()
|
|
||||||
t.Wiggle()
|
|
||||||
t.Wiggle()
|
|
||||||
t.Wiggle()
|
|
||||||
}
|
|
||||||
|
|
||||||
x, y := t.Pos()
|
|
||||||
center := quadtree.NewXY(float64(x), float64(y))
|
|
||||||
neighbours := env.GetNearestNeighbours(quadtree.NewAABB(*center, searchtree), 3)
|
|
||||||
|
|
||||||
if len(neighbours) > 2 {
|
|
||||||
//t.SetHeading(avgHead % 8)
|
|
||||||
// t.Wiggle()
|
|
||||||
} else {
|
|
||||||
t.Wiggle()
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Drop(env, 1, "bird")
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
t := new(core.Turtle)
|
|
||||||
t.SetColor(color.RGBA{255, 0, 0, 255})
|
|
||||||
experiment.InitEnvironment(func(environment *core.Environment) {
|
|
||||||
// Create 2 food piles
|
|
||||||
|
|
||||||
for x := 0; x < 300; x++ {
|
|
||||||
for y := 0; y < 300; y++ {
|
|
||||||
if envmap[y/20][x/20] == 1 {
|
|
||||||
//if ((x %20 < 10) && (y% 20<10)) || x < 30 || y < 30 || y > 270 || x > 270 || (x <100 && y>200) || ((x>150 && x < 300) && (y > 150 && y<175)) || ((x>150 && x < 180) && (y > 100 && y<175)){
|
|
||||||
environment.Occupy(t, x, y)
|
|
||||||
environment.PutValue(x,y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(Bird)
|
|
||||||
|
|
||||||
return sm
|
|
||||||
},1000)
|
|
||||||
|
|
||||||
experiment.InitPheromone("bird", color.RGBA{0x80, 0xaa, 0x00, 0x00})
|
|
||||||
experiment.OnStep = func(environment *core.Environment, turtles []*core.Turtle, i int) {
|
|
||||||
environment.EvaporateAndDiffuse(0.90, "bird")
|
|
||||||
}
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sniffDistance = flag.Int("sniffDistance", 3, "the distance a turtle can detect pheromone levels from")
|
|
||||||
var defensiveDecentralization = flag.Bool("defensiveDecentralization", false, "if true, slime molds will break up if the concentration is too great")
|
|
||||||
|
|
||||||
type SlimeMold struct {
|
|
||||||
SniffDistance int
|
|
||||||
Age int
|
|
||||||
Stuck bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.SetColor(color.RGBA{100, 255, 10, 0})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
frac := float64(sm.Age) / math.Min(float64(env.Step+1), 255)
|
|
||||||
col := uint8(256 * frac)
|
|
||||||
if env.Step < 100 {
|
|
||||||
t.SetColor(color.RGBA{col, 0, col / 2, 0xf2})
|
|
||||||
} else {
|
|
||||||
t.SetColor(color.RGBA{col, 0, col, col})
|
|
||||||
}
|
|
||||||
if sm.Stuck == false {
|
|
||||||
sm.Age++
|
|
||||||
//t.Wiggle()
|
|
||||||
//t.Wiggle()
|
|
||||||
t.Wiggle()
|
|
||||||
t.Step(env)
|
|
||||||
c := t.Check(env)
|
|
||||||
|
|
||||||
if c != nil {
|
|
||||||
s := c.GetActor().(*SlimeMold)
|
|
||||||
if s.Stuck == true {
|
|
||||||
sm.Stuck = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
n := 0
|
|
||||||
experiment.InitTurtles(func() core.Actor {
|
|
||||||
n++
|
|
||||||
sm := new(SlimeMold)
|
|
||||||
if n == 1 {
|
|
||||||
sm.Stuck = true
|
|
||||||
}
|
|
||||||
return sm
|
|
||||||
})
|
|
||||||
experiment.InitPheromone("trail", color.RGBA{0x80, 0xFF, 0x00, 0x00})
|
|
||||||
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
"math/rand"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
var prob = flag.Float64("distribution", .51, "drives the probability of color assignment of turtles in consensus models, closer to .5 results in more even assignment, closer to 0 or 1 biases in favor of a color.")
|
|
||||||
var byzantineTurtles = flag.Int("byzantineTurtles", 50, "in consensus simlulations, the number of turtles who will always vote 2")
|
|
||||||
|
|
||||||
type Isolate struct {
|
|
||||||
color int
|
|
||||||
Probability float64
|
|
||||||
sureness float32
|
|
||||||
Byztantine bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Isolate) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
num := rand.Intn(100)
|
|
||||||
if num >= int(sm.Probability*100.0) {
|
|
||||||
sm.color = 2
|
|
||||||
} else {
|
|
||||||
sm.color = 1
|
|
||||||
}
|
|
||||||
sm.sureness = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Isolate) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
if sm.Byztantine {
|
|
||||||
t.Wiggle()
|
|
||||||
t.FollowGradient(env, 10, 0, "2")
|
|
||||||
t.Drop(env, 1, "2")
|
|
||||||
t.Step(env)
|
|
||||||
} else {
|
|
||||||
t.Wiggle()
|
|
||||||
am1 := t.Amount(env, 1, "1")
|
|
||||||
am2 := t.Amount(env, 1, "2")
|
|
||||||
|
|
||||||
if am1 > sm.sureness || am2 > sm.sureness {
|
|
||||||
if am1 > am2 {
|
|
||||||
if sm.color == 2 {
|
|
||||||
sm.sureness--
|
|
||||||
} else {
|
|
||||||
sm.sureness++
|
|
||||||
}
|
|
||||||
if sm.sureness == 0 {
|
|
||||||
sm.color = 1
|
|
||||||
}
|
|
||||||
} else if am2 > am1 {
|
|
||||||
if sm.color == 1 {
|
|
||||||
sm.sureness--
|
|
||||||
} else {
|
|
||||||
sm.sureness++
|
|
||||||
}
|
|
||||||
if sm.sureness == 0 {
|
|
||||||
sm.color = 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if sm.sureness > 1 {
|
|
||||||
t.Drop(env, 1, strconv.Itoa(sm.color))
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Step(env)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
honestTurtles := experiment.GetNumTurtles() - (*byzantineTurtles)
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(Isolate)
|
|
||||||
sm.Probability = *prob
|
|
||||||
return sm
|
|
||||||
}, honestTurtles)
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(Isolate)
|
|
||||||
sm.Probability = *prob
|
|
||||||
sm.Byztantine = true
|
|
||||||
return sm
|
|
||||||
}, (*byzantineTurtles))
|
|
||||||
experiment.InitPheromone("1", color.RGBA{0x00, 0xFF, 0x00, 0x00})
|
|
||||||
experiment.InitPheromone("2", color.RGBA{0xFF, 0x00, 0xFF, 0x00})
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,142 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"github.com/foolusion/quadtree"
|
|
||||||
"github.com/wcharczuk/go-chart"
|
|
||||||
"image/color"
|
|
||||||
"math/rand"
|
|
||||||
"os"
|
|
||||||
"os/signal"
|
|
||||||
"runtime/pprof"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sniffDistance = flag.Int("sniffDistance", 5, "the distance a turtle can detect pheromone levels from")
|
|
||||||
|
|
||||||
type LightningBug struct {
|
|
||||||
Timer int
|
|
||||||
HasReset bool
|
|
||||||
Num int
|
|
||||||
Threshold int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *LightningBug) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
// Do nothing
|
|
||||||
sm.Threshold = 35
|
|
||||||
sm.Timer = rand.Intn(sm.Threshold)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var searchtree = quadtree.XY{50, 50}
|
|
||||||
|
|
||||||
func (sm *LightningBug) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.Wiggle()
|
|
||||||
|
|
||||||
if sm.Timer > 3 {
|
|
||||||
t.Step(env)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.SetColor(color.RGBA{0x00, 0x1f, 0x00, 0xff})
|
|
||||||
if sm.Timer <= 3 {
|
|
||||||
t.SetColor(color.RGBA{0xff, 0xff, 0x00, 0xff})
|
|
||||||
}
|
|
||||||
|
|
||||||
sm.Timer++
|
|
||||||
|
|
||||||
if sm.Timer > 10 {
|
|
||||||
x, y := t.Pos()
|
|
||||||
center := quadtree.NewXY(float64(x), float64(y))
|
|
||||||
neighbours := env.GetNearestNeighbours(quadtree.NewAABB(*center, searchtree), 3)
|
|
||||||
|
|
||||||
for _, n := range neighbours {
|
|
||||||
if n.GetActor().(*LightningBug).Num != sm.Num && n.GetActor().(*LightningBug).Timer == 0 {
|
|
||||||
sm.Timer = 0
|
|
||||||
}
|
|
||||||
//sm.HasReset = true
|
|
||||||
//t.SetColor(color.RGBA{0x00,0x1f,0xff,0xff})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if sm.Timer > sm.Threshold {
|
|
||||||
sm.Timer = 0
|
|
||||||
sm.HasReset = false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
num := 0
|
|
||||||
experiment.InitTurtles(func() core.Actor {
|
|
||||||
sm := new(LightningBug)
|
|
||||||
sm.Num = num
|
|
||||||
num++
|
|
||||||
return sm
|
|
||||||
})
|
|
||||||
|
|
||||||
x := []float64{}
|
|
||||||
y := []float64{}
|
|
||||||
|
|
||||||
experiment.AddPlot("Flashing Bugs", func(environment *core.Environment, turtles []*core.Turtle) *chart.Chart {
|
|
||||||
numLight := 0.0
|
|
||||||
for _, t := range turtles {
|
|
||||||
lb := t.GetActor().(*LightningBug)
|
|
||||||
if lb.Timer == 0 {
|
|
||||||
numLight++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x = append(x, float64(environment.Step))
|
|
||||||
y = append(y, numLight)
|
|
||||||
|
|
||||||
graph := chart.Chart{
|
|
||||||
Width: 300,
|
|
||||||
Height: 300,
|
|
||||||
Background: chart.Style{
|
|
||||||
Padding: chart.Box{
|
|
||||||
Top: 50,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
XAxis: chart.XAxis{Name: "Time Step", NameStyle: chart.Style{Show: true}, Style: chart.Style{Show: true, TextRotationDegrees: 90}, ValueFormatter: func(v interface{}) string {
|
|
||||||
return fmt.Sprintf("%d", int(v.(float64)))
|
|
||||||
}},
|
|
||||||
YAxis: chart.YAxis{Name: "Number of Flashing Lightning Bugs", NameStyle: chart.Style{Show: true}, Style: chart.Style{Show: true}, ValueFormatter: func(v interface{}) string {
|
|
||||||
return fmt.Sprintf("%d", int(v.(float64)))
|
|
||||||
}},
|
|
||||||
Series: []chart.Series{
|
|
||||||
chart.ContinuousSeries{
|
|
||||||
XValues: x,
|
|
||||||
YValues: y,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return &graph
|
|
||||||
})
|
|
||||||
|
|
||||||
c := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(c, os.Interrupt)
|
|
||||||
go func() {
|
|
||||||
for sig := range c {
|
|
||||||
fmt.Printf("Got Signal %v", sig)
|
|
||||||
pprof.StopCPUProfile()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
experiment.OnStep = func(environment *core.Environment, turtles []*core.Turtle, i int) {
|
|
||||||
environment.Diffuse("light")
|
|
||||||
environment.Diffuse("light")
|
|
||||||
environment.Evaporate(0.99, "light")
|
|
||||||
}
|
|
||||||
experiment.InitPheromone("light", color.RGBA{0xff, 0xff, 0x00, 0x00})
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sniffDistance = flag.Int("sniffDistance", 5, "the distance a turtle can detect pheromone levels from")
|
|
||||||
|
|
||||||
type MazeGeneration struct {
|
|
||||||
SniffDistance int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *MazeGeneration) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *MazeGeneration) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.Wiggle()
|
|
||||||
t.FollowGradient(env, sm.SniffDistance, 0, "trail")
|
|
||||||
t.TurnAround() // Run away from the strongest trail
|
|
||||||
t.Step(env)
|
|
||||||
t.Drop(env, 1, "trail")
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
experiment.InitTurtles(func() core.Actor {
|
|
||||||
sm := new(MazeGeneration)
|
|
||||||
sm.SniffDistance = *sniffDistance
|
|
||||||
return sm
|
|
||||||
})
|
|
||||||
experiment.InitPheromone("trail", color.RGBA{0x81, 0x00, 0x81, 0x00})
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
# Predator Prey Model
|
|
||||||
|
|
||||||
Models interactions between prey who eat grass, and predators who eat prey.
|
|
||||||
|
|
||||||
![](oscillations.png)
|
|
Binary file not shown.
Before Width: | Height: | Size: 69 KiB |
|
@ -1,207 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"github.com/wcharczuk/go-chart"
|
|
||||||
"image/color"
|
|
||||||
"math"
|
|
||||||
"math/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
var numPrey = flag.Int("numPrey", 300, "the number of prey")
|
|
||||||
|
|
||||||
var initialPreyEnergy = flag.Int("initialPreyEnergy", 15, "initial prey energy")
|
|
||||||
var preyMaxLife = flag.Int("preyMaxLife", 25, "the max lifespan of prey (in simulation steps)")
|
|
||||||
var preyReproductiveAge = flag.Int("preyReproductiveAge", 4, "the age a prey might reproduce")
|
|
||||||
var preyReproductionEnergy = flag.Int("preyReproductionEnergy", 4, "energy required for prey reproduction")
|
|
||||||
var preyReproductionProbability = flag.Float64("preyReproductionProbability", 0.4, "preys probability of reproducing")
|
|
||||||
|
|
||||||
var numPred = flag.Int("numPred", 30, "the number of predators")
|
|
||||||
var initialPredatorEnergy = flag.Int("initialPredatorEnergy", 40, "initial predator energy")
|
|
||||||
var predatorMaxLife = flag.Int("predatorMaxLife", 60, "the max lifespan of predators (in simulation steps)")
|
|
||||||
var predatorMaxEnergy = flag.Int("predatorMaxEnergy", 30, "max amount of energy a predator can have")
|
|
||||||
var predatorReproductionEnergy = flag.Int("predatorReproductionEnergy", 50, "predator reproductive energy")
|
|
||||||
var predatorReproductionProbability = flag.Float64("predatorReproductionProbability", 0.05, "predators probability of reproducing")
|
|
||||||
|
|
||||||
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 = *initialPredatorEnergy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Predator) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
sm.Steps++
|
|
||||||
|
|
||||||
if sm.Steps == *predatorMaxLife {
|
|
||||||
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, float64(*predatorMaxEnergy)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.FollowGradient(env, 3, 1, "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 = *initialPreyEnergy
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Prey) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
sm.Steps++
|
|
||||||
sm.Energy--
|
|
||||||
|
|
||||||
if sm.Steps >= *preyMaxLife || 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 mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
experiment.InitEnvironment(func(env *core.Environment) {
|
|
||||||
for i := 0; i < 1200; 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)
|
|
||||||
|
|
||||||
x := []float64{}
|
|
||||||
pred := []float64{}
|
|
||||||
prey := []float64{}
|
|
||||||
|
|
||||||
experiment.AddPlot("Predators vs. Prey", func(environment *core.Environment, turtles []*core.Turtle) *chart.Chart {
|
|
||||||
preyalive := 0
|
|
||||||
predalive := 0
|
|
||||||
|
|
||||||
for _, turtle := range turtles {
|
|
||||||
if turtle.GetAttribute("type") == "prey" && turtle.GetAttribute("status") != "dead" {
|
|
||||||
preyalive++
|
|
||||||
prey := turtle.GetActor().(*Prey)
|
|
||||||
if prey.Steps > (*preyReproductiveAge) && prey.Energy > (*preyReproductionEnergy) && float64(rand.Intn(100)) < (100*(*preyReproductionProbability)) {
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(Prey)
|
|
||||||
return sm
|
|
||||||
}, 1)
|
|
||||||
preyalive++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if turtle.GetAttribute("type") == "predator" && turtle.GetAttribute("status") != "dead" {
|
|
||||||
predalive++
|
|
||||||
|
|
||||||
if turtle.GetAttribute("type") == "predator" {
|
|
||||||
pred := turtle.GetActor().(*Predator)
|
|
||||||
if pred.Energy >= (*predatorReproductionEnergy) && float64(rand.Intn(100)) < (100*(*predatorReproductionProbability)) {
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(Predator)
|
|
||||||
return sm
|
|
||||||
}, 1)
|
|
||||||
predalive++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x = append(x, float64(environment.Step))
|
|
||||||
prey = append(prey, 100*(float64(preyalive)/float64(environment.Width()*environment.Height())))
|
|
||||||
pred = append(pred, 100*(float64(predalive)/float64(environment.Width()*environment.Height())))
|
|
||||||
|
|
||||||
preypop := chart.ContinuousSeries{
|
|
||||||
Name: "Prey Population Density",
|
|
||||||
XValues: x,
|
|
||||||
YValues: prey,
|
|
||||||
}
|
|
||||||
|
|
||||||
predpop := chart.ContinuousSeries{
|
|
||||||
Name: "Predator Population Density",
|
|
||||||
XValues: x,
|
|
||||||
YValues: pred,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
graph := chart.Chart{
|
|
||||||
|
|
||||||
Background: chart.Style{
|
|
||||||
Padding: chart.Box{
|
|
||||||
Top: 50,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
XAxis: chart.XAxis{Name: "Time Step", NameStyle: chart.Style{Show: true}, Style: chart.Style{Show: true}, ValueFormatter: func(v interface{}) string {
|
|
||||||
return fmt.Sprintf("%d", int(v.(float64)))
|
|
||||||
}},
|
|
||||||
YAxis: chart.YAxis{Name: "Population", NameStyle: chart.Style{Show: true}, Style: chart.Style{Show: true,}, ValueFormatter: func(v interface{}) string {
|
|
||||||
return fmt.Sprintf("%d", int(v.(float64)))
|
|
||||||
}},
|
|
||||||
Series: []chart.Series{
|
|
||||||
preypop,
|
|
||||||
predpop,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return &graph
|
|
||||||
})
|
|
||||||
|
|
||||||
experiment.InitPheromone("scent", color.RGBA{0x80, 0xFF, 0x00, 0x00})
|
|
||||||
fmt.Printf("%v, %v,%v\n", "time step", "number of prey", "number of predators")
|
|
||||||
experiment.OnStep = func(env *core.Environment, turtles []*core.Turtle, step int) {
|
|
||||||
env.EvaporateAndDiffuse(0.95, "scent")
|
|
||||||
// Grow Grass
|
|
||||||
x := rand.Intn(env.Width())
|
|
||||||
y := rand.Intn(env.Height())
|
|
||||||
env.PutValue(x, y)
|
|
||||||
|
|
||||||
//if step == 0 {
|
|
||||||
//fmt.Printf("%v,%v,%v\n", step, alive, predalive)
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sniffDistance = flag.Int("sniffDistance", 3, "the distance a turtle can detect pheromone levels from")
|
|
||||||
var defensiveDecentralization = flag.Bool("defensiveDecentralization", false, "if true, slime molds will break up if the concentration is too great")
|
|
||||||
|
|
||||||
type SlimeMold struct {
|
|
||||||
SniffDistance int
|
|
||||||
StartX, StartY int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.SetColor(color.RGBA{100, 255, 10, 0})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.Wiggle()
|
|
||||||
if *defensiveDecentralization == false {
|
|
||||||
t.FollowGradient(env, sm.SniffDistance, 2, "trail")
|
|
||||||
} else if t.Amount(env, sm.SniffDistance, "trail") < 5.2 {
|
|
||||||
t.FollowGradient(env, sm.SniffDistance, 2, "trail")
|
|
||||||
} else {
|
|
||||||
//t.FollowGradient(env, sm.SniffDistance, 2, "trail")
|
|
||||||
//t.TurnAround()
|
|
||||||
}
|
|
||||||
t.Step(env)
|
|
||||||
t.Drop(env, 1, "trail")
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
experiment.InitTurtles(func() core.Actor {
|
|
||||||
sm := new(SlimeMold)
|
|
||||||
sm.SniffDistance = *sniffDistance
|
|
||||||
return sm
|
|
||||||
})
|
|
||||||
experiment.InitPheromone("trail", color.RGBA{0x80, 0xFF, 0x00, 0x00})
|
|
||||||
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/models"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
)
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
|
|
||||||
num := 0
|
|
||||||
|
|
||||||
experiment.InitEnvironment(func(environment *core.Environment) {
|
|
||||||
x, y := 120, 120
|
|
||||||
for i := 0; i < 20; i++ {
|
|
||||||
for j := 0; j < 20; j++ {
|
|
||||||
environment.PutValue(x+i, y+j)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x, y = 250, 120
|
|
||||||
for i := 0; i < 20; i++ {
|
|
||||||
for j := 0; j < 20; j++ {
|
|
||||||
environment.PutValue(x+i, y+j)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x, y = 160, 130
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
for j := 0; j < 10; j++ {
|
|
||||||
environment.PutValue(x+i, y+j)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(models.SlimeMold)
|
|
||||||
sm.Num = num
|
|
||||||
num++
|
|
||||||
return sm
|
|
||||||
}, 10000)
|
|
||||||
|
|
||||||
experiment.InitPheromone("slime", color.RGBA{0x80, 0xFF, 0x00, 0x00})
|
|
||||||
experiment.InitPheromone("food", color.RGBA{0xff, 0x00, 0x00, 0x00})
|
|
||||||
experiment.OnStep = func(environment *core.Environment, turtles []*core.Turtle, i int) {
|
|
||||||
environment.EvaporateAndDiffuse(0.99, "slime")
|
|
||||||
environment.EvaporateAndDiffuse(0.99, "food")
|
|
||||||
}
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
"math/rand"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
var prob = flag.Float64("distribution", .51, "drives the probability of color assignment of turtles in consensus models, closer to .5 results in more even assignment, closer to 0 or 1 biases in favor of a color.")
|
|
||||||
|
|
||||||
type Slush struct {
|
|
||||||
color int
|
|
||||||
Probability float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSlushTurtle() core.Actor {
|
|
||||||
turtle := new(Slush)
|
|
||||||
turtle.Probability = *prob
|
|
||||||
return turtle
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Slush) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
num := rand.Intn(100)
|
|
||||||
if num >= int(sm.Probability*100.0) {
|
|
||||||
sm.color = 2
|
|
||||||
} else {
|
|
||||||
sm.color = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Slush) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.Wiggle()
|
|
||||||
am1 := t.Amount(env, 1, "1")
|
|
||||||
am2 := t.Amount(env, 1, "2")
|
|
||||||
|
|
||||||
t.Drop(env, 1, strconv.Itoa(sm.color))
|
|
||||||
|
|
||||||
if am1 > 3 || am2 > 3 {
|
|
||||||
if am1 > am2 {
|
|
||||||
sm.color = 1
|
|
||||||
} else if am2 > am1 {
|
|
||||||
sm.color = 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Step(env)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
experiment.InitTurtles(NewSlushTurtle)
|
|
||||||
experiment.InitPheromone("1", color.RGBA{0x80, 0xFF, 0x00, 0x00})
|
|
||||||
experiment.InitPheromone("2", color.RGBA{0xFF, 0x00, 0xFF, 0x00})
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,198 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
"math/rand"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
var prob = flag.Float64("distribution", .51, "drives the probability of color assignment of turtles in consensus models, closer to .5 results in more even assignment, closer to 0 or 1 biases in favor of a color.")
|
|
||||||
var initialSureness = flag.Int("initialSureness", 2, "how sure an honest node is of their first received colour")
|
|
||||||
var byzantineTurtles = flag.Int("byzantineTurtles", 50, "in consensus simlulations, the number of turtles who will always vote 2")
|
|
||||||
var cleverByzantineTurtles = flag.Bool("cleverByzantineTurtles", true, "byzantine turtles try to find each other")
|
|
||||||
|
|
||||||
var isolate = flag.Bool("isolate", false, "also run the isolate algorithm")
|
|
||||||
|
|
||||||
var alpha = flag.Float64("alpha", 0.8, "the proportion of votes in a voting round that a color must have before it is considered a vote for that colour")
|
|
||||||
var beta = flag.Float64("beta", 100, "acceptance threshold, the number of steps of consistent votes after which a node will no longer change its opinon")
|
|
||||||
|
|
||||||
var vote1Ahead = false
|
|
||||||
|
|
||||||
type Snowball struct {
|
|
||||||
color int
|
|
||||||
Probability float64
|
|
||||||
sureness float32
|
|
||||||
Byztantine bool
|
|
||||||
colourCounts []int
|
|
||||||
accept bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Snowball) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
if sm.Byztantine {
|
|
||||||
sm.color = 1
|
|
||||||
} else {
|
|
||||||
sm.colourCounts = make([]int, 2)
|
|
||||||
num := rand.Intn(100)
|
|
||||||
if num >= int(sm.Probability*100.0) {
|
|
||||||
sm.color = 0
|
|
||||||
sm.colourCounts[0] = 1
|
|
||||||
} else {
|
|
||||||
sm.color = 1
|
|
||||||
sm.colourCounts[1] = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sm.sureness = float32(*initialSureness)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Snowball) GetColor() int {
|
|
||||||
return sm.color + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Snowball) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
if sm.Byztantine {
|
|
||||||
t.Wiggle()
|
|
||||||
am1 := t.AmountAll(env, 1, "1")
|
|
||||||
am2 := t.AmountAll(env, 1, "2")
|
|
||||||
k := float32(am1 + am2)
|
|
||||||
|
|
||||||
if *cleverByzantineTurtles == false {
|
|
||||||
if am1 > k*float32(*alpha) && am1 > am2 {
|
|
||||||
sm.color = 1
|
|
||||||
t.Drop(env, 1, "2")
|
|
||||||
} else if am2 > k*float32(*alpha) && am2 > am1 {
|
|
||||||
sm.color = 0
|
|
||||||
t.Drop(env, 1, "1")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if *isolate {
|
|
||||||
t.FollowGradient(env, 10, 0, "3")
|
|
||||||
t.Drop(env, 1, "3")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*isolate) && sm.sureness > 50 || (*isolate) == false {
|
|
||||||
if vote1Ahead {
|
|
||||||
sm.color = 1
|
|
||||||
t.Drop(env, 1, "2")
|
|
||||||
} else {
|
|
||||||
sm.color = 0
|
|
||||||
t.Drop(env, 1, "1")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sm.sureness++
|
|
||||||
t.Step(env)
|
|
||||||
|
|
||||||
t.SetColor(color.RGBA{255, 0, 0, 0})
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if sm.color == 1 {
|
|
||||||
t.SetColor(color.RGBA{0, 255, 0, 0})
|
|
||||||
} else {
|
|
||||||
t.SetColor(color.RGBA{255, 0, 255, 0})
|
|
||||||
}
|
|
||||||
t.Wiggle()
|
|
||||||
|
|
||||||
if !sm.accept {
|
|
||||||
am1 := t.AmountAll(env, 1, "1")
|
|
||||||
am2 := t.AmountAll(env, 1, "2")
|
|
||||||
k := float32(am1 + am2)
|
|
||||||
|
|
||||||
if am1 > k*float32(*alpha) && am1 > am2 {
|
|
||||||
sm.colourCounts[0]++
|
|
||||||
} else if am2 > k*float32(*alpha) && am2 > am1 {
|
|
||||||
sm.colourCounts[1]++
|
|
||||||
}
|
|
||||||
|
|
||||||
sm.sureness++
|
|
||||||
|
|
||||||
if sm.colourCounts[sm.color] < sm.colourCounts[(sm.color+1)%2] {
|
|
||||||
sm.color = (sm.color + 1) % 2
|
|
||||||
sm.sureness = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if sm.sureness > float32(*beta) {
|
|
||||||
sm.accept = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add a vote for our new colour if we are sure
|
|
||||||
if sm.sureness >= 1 {
|
|
||||||
t.Drop(env, 1, strconv.Itoa(sm.color+1))
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Step(env)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(Snowball)
|
|
||||||
sm.Probability = *prob
|
|
||||||
sm.Byztantine = true
|
|
||||||
return sm
|
|
||||||
}, (*byzantineTurtles))
|
|
||||||
experiment.InitPheromone("1", color.RGBA{0x00, 0xFF, 0x00, 0x00})
|
|
||||||
experiment.InitPheromone("2", color.RGBA{0xFF, 0x00, 0xFF, 0x00})
|
|
||||||
experiment.InitPheromone("3", color.RGBA{0xFF, 0x00, 0x00, 0x00})
|
|
||||||
fmt.Printf("Step, Votes for 1, Votes for 2, Honest Votes for 1, Honest Votes for 2, Byzantine Vots for 1, Byzantine Votes for 2\n")
|
|
||||||
experiment.OnStep = func(env *core.Environment, turtles []*core.Turtle, step int) {
|
|
||||||
num1 := 0
|
|
||||||
num2 := 0
|
|
||||||
bnum1 := 0
|
|
||||||
bnum2 := 0
|
|
||||||
|
|
||||||
env.EvaporateAndDiffuse(0.99, "1")
|
|
||||||
env.EvaporateAndDiffuse(0.99, "2")
|
|
||||||
env.EvaporateAndDiffuse(0.99, "3")
|
|
||||||
|
|
||||||
if (*isolate) && step == 50 || !(*isolate) && step == 0 {
|
|
||||||
honestTurtles := experiment.GetNumTurtles() - (*byzantineTurtles)
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(Snowball)
|
|
||||||
sm.Probability = *prob
|
|
||||||
return sm
|
|
||||||
}, honestTurtles)
|
|
||||||
} else {
|
|
||||||
for _, turtle := range turtles {
|
|
||||||
agent := turtle.GetActor().(*Snowball)
|
|
||||||
if agent.Byztantine == false {
|
|
||||||
if agent.GetColor() == 1 {
|
|
||||||
num1++
|
|
||||||
} else {
|
|
||||||
num2++
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if agent.GetColor() == 1 {
|
|
||||||
bnum1++
|
|
||||||
} else {
|
|
||||||
bnum2++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if num1 > num2 {
|
|
||||||
vote1Ahead = true
|
|
||||||
} else {
|
|
||||||
vote1Ahead = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//if step == 0 {
|
|
||||||
fmt.Printf("%v,%v,%v,%v,%v, %v,%v\n", step, num1+bnum1, num2+bnum2, num1, num2, bnum1, bnum2)
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,368 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/models"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sniffDistance = flag.Int("sniffDistance", 15, "the distance an ant can detect pheromone levels from")
|
|
||||||
var dropSize = flag.Float64("dropSize", 1.0, "the amount of pheromone an ants drops")
|
|
||||||
|
|
||||||
type Wall struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Wall) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.SetColor(color.RGBA{0x4b, 0x35, 0x57, 0xff})
|
|
||||||
}
|
|
||||||
func (a *Wall) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type SlimeMold struct {
|
|
||||||
Num int
|
|
||||||
StartX, StartY int
|
|
||||||
Energy float64
|
|
||||||
Count float32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.SetColor(color.RGBA{0x1f, 0xff, 0x00, 0xff})
|
|
||||||
//t.SetXY(sm.StartX, sm.StartY)
|
|
||||||
sm.Energy = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) CheckNeighbours(env *core.Environment, ox, oy int) int {
|
|
||||||
neighbours := 0
|
|
||||||
if env.Check(ox-1, oy-1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox, oy-1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox+1, oy-1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox-1, oy) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox+1, oy) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
|
|
||||||
if env.Check(ox-1, oy+1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox, oy+1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox+1, oy+1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
return neighbours
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
neighbour := t.Check(env)
|
|
||||||
if neighbour != nil {
|
|
||||||
n, ok := neighbour.GetActor().(*SlimeMold)
|
|
||||||
if ok && n.Energy > sm.Energy {
|
|
||||||
sm.Energy = (sm.Energy + n.Energy) * .5
|
|
||||||
n.Energy = (sm.Energy + n.Energy) * .5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move around the world, if there are too many slimes around us turn around, otherwise follow slimes and food.
|
|
||||||
t.Wiggle()
|
|
||||||
|
|
||||||
if t.Amount(env, 1, "slime") > 10 {
|
|
||||||
t.FollowGradient(env, 1, 10, "slime")
|
|
||||||
t.TurnAround()
|
|
||||||
}
|
|
||||||
t.FollowGradient(env, 1, .1, "food")
|
|
||||||
// If we have no neighbours we pretend we found some food so the others can find us.
|
|
||||||
t.Step(env)
|
|
||||||
ox, oy := t.Pos()
|
|
||||||
neighbours := sm.CheckNeighbours(env, ox, oy)
|
|
||||||
if neighbours > 2 {
|
|
||||||
sm.Count = 0
|
|
||||||
t.Drop(env, .1, "slime")
|
|
||||||
if neighbours >= 7 {
|
|
||||||
t.Wiggle()
|
|
||||||
t.Wiggle()
|
|
||||||
t.Wiggle()
|
|
||||||
t.Drop(env, 1, "slime")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sm.Count += 0.1
|
|
||||||
t.Drop(env, float32(math.Pow(2, float64(sm.Count))), "food")
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've found food, let's drop some chemical to tell others
|
|
||||||
if env.HasValue(t.Pos()) {
|
|
||||||
//env.TakeValue(t.Pos())
|
|
||||||
//env.TakeValue(t.Pos())
|
|
||||||
t.Drop(env, 255, "food")
|
|
||||||
sm.Energy = 256
|
|
||||||
}
|
|
||||||
|
|
||||||
if sm.Energy > 0 {
|
|
||||||
sm.Energy -= 2
|
|
||||||
if sm.Energy == 0 {
|
|
||||||
//t.SetAttribute("status","dead")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Drop(env, float32(sm.Energy), "food")
|
|
||||||
t.SetColor(color.RGBA{100, uint8(sm.Energy / 256), 10, 0})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var W = 1
|
|
||||||
|
|
||||||
var maze0 = [][]int{
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 0, 0, 3, 0, 3, 0, 3, 0, 0, 0, 3, 0, 3, W},
|
|
||||||
{W, 0, W, W, W, W, W, 3, W, 3, W, 0, W, 0, W},
|
|
||||||
{W, 0, W, 0, 3, 0, 3, 0, W, 0, W, 0, W, 3, W},
|
|
||||||
{W, 3, W, 3, W, W, W, W, W, 3, W, 3, W, 0, W},
|
|
||||||
{W, 0, W, 0, W, 0, 3, 0, 3, 0, W, 0, W, 3, W},
|
|
||||||
{W, 3, W, 3, W, 0, W, W, W, 3, W, 3, W, 0, W},
|
|
||||||
{2, 2, 3, 0, W, 3, 0, 0, W, 0, W, W, W, 0, W},
|
|
||||||
{2, 2, W, 0, W, W, 0, W, W, 3, W, 3, W, 3, W},
|
|
||||||
{2, 2, W, 0, W, 0, 3, W, 0, 0, W, 0, W, 0, W},
|
|
||||||
{2, 2, W, 3, W, W, 0, W, 3, W, W, 3, 0, 3, W},
|
|
||||||
{2, 2, W, 0, W, 0, 3, W, 0, 3, 0, 0, W, 0, W},
|
|
||||||
{2, 2, W, 3, W, 3, W, W, W, W, W, 3, W, 3, W},
|
|
||||||
{2, 2, W, 0, W, 0, 0, W, 2, 2, 2, 2, W, 0, W},
|
|
||||||
{W, W, W, W, W, W, W, W, 2, 2, 2, 2, W, W, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
var maze2 = [][]int{
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, 2, 2, 2, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, 2, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, 2, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, 2, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, 2, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, 3, 3, 3, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, 3, 3, 3, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
var logo = [][]int{
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 2, 2, 2, 2, 2, W, 2, W, 2, 2, W, 2, 2, W},
|
|
||||||
{W, 2, W, 2, W, 2, W, 2, W, 2, W, W, 2, W, W},
|
|
||||||
{W, 3, W, 2, W, 2, W, 3, W, 2, 3, W, 3, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 3, 2, 2, W, 3, W, W, W, 2, W, 3, 2, 2, W},
|
|
||||||
{W, 2, W, 2, W, 2, W, 2, W, 2, W, 2, W, 2, W},
|
|
||||||
{W, 2, 2, 2, W, 2, 2, 2, 2, 2, W, 2, 2, 2, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 2, 2, W, 2, W, W, 2, 2, W, W, 2, 5, W, W},
|
|
||||||
{W, 2, W, W, 2, W, W, 2, 4, 5, W, 2, W, W, W},
|
|
||||||
{W, 3, W, W, 2, 3, W, 3, 2, W, 4, 3, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
var maze = [][]int{
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, 0, 2, 2, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
var smallmaze = [][]int{
|
|
||||||
{W, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, W},
|
|
||||||
{W, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, W},
|
|
||||||
{W, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, 2, 2, W},
|
|
||||||
{W, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, W, W, W, W},
|
|
||||||
{W, 2, W, 2, 2, W, W, W, W, W, 2, 2, W, 0, W},
|
|
||||||
{W, 2, W, W, 2, W, 3, 3, 3, W, 2, 2, W, 0, W},
|
|
||||||
{W, 2, W, 2, 2, 2, 3, 0, 3, W, W, 0, W, 0, W},
|
|
||||||
{W, 2, W, W, W, W, 3, 0, 3, W, 0, 0, W, 0, W},
|
|
||||||
{W, 2, 2, 2, 2, W, 3, 3, 3, W, 0, 0, 0, 0, W},
|
|
||||||
{W, 2, 2, 2, 2, W, W, W, W, W, 0, 0, 0, 0, W},
|
|
||||||
{W, 2, 2, 2, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, W},
|
|
||||||
{W, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, W},
|
|
||||||
{W, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
var steiner2 = [][]int{
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 2, 2, 0, 0, 0, 0, 2, 2, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
var mazetest = [][]int{
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, W, W, W, W, W, 0, W, 0, W, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, W, 0, W, 0, W, 0, W, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, W, 3, W, 2, 2, 0, W, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, W, 0, 0, 2, 2, 2, 2, 2, 2, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, W, 2, 2, 0, 0, 0, 2, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, W, 0, 0, 0, 0, 0, 2, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, W, 0, 0, 0, 0, 0, 2, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 2, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
var mold = [][]int{
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, 0, 0, 0, 2, 2, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 2, 2, 0, 2, 2, 2, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
var utrap = [][]int{
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 2, W, 0, 2, 0, W, 2, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, W, 0, 0, 0, W, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 2, W, W, W, W, W, 2, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 2, 0, 3, 0, 0, 2, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, W},
|
|
||||||
{W, W, W, W, W, W, W, W, W, W, W, W, W, W, W},
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
|
|
||||||
//maze = maze0
|
|
||||||
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
t := new(core.Turtle)
|
|
||||||
t.SetColor(color.RGBA{255, 0, 0, 255})
|
|
||||||
experiment.InitEnvironment(func(environment *core.Environment) {
|
|
||||||
// Create 2 food piles
|
|
||||||
|
|
||||||
for x := 0; x < 300; x++ {
|
|
||||||
for y := 0; y < 300; y++ {
|
|
||||||
if maze[y/20][x/20] == 1 {
|
|
||||||
//if ((x %20 < 10) && (y% 20<10)) || x < 30 || y < 30 || y > 270 || x > 270 || (x <100 && y>200) || ((x>150 && x < 300) && (y > 150 && y<175)) || ((x>150 && x < 180) && (y > 100 && y<175)){
|
|
||||||
environment.Occupy(t, x, y)
|
|
||||||
} else if maze[y/20][x/20] == 2 {
|
|
||||||
environment.PutValue(x, y)
|
|
||||||
} else if maze[y/20][x/20] == 4 {
|
|
||||||
if x%20 > 10 {
|
|
||||||
environment.PutValue(x, y)
|
|
||||||
} else {
|
|
||||||
environment.Occupy(t, x, y)
|
|
||||||
}
|
|
||||||
} else if maze[y/20][x/20] == 5 {
|
|
||||||
if x%20 < 10 {
|
|
||||||
environment.PutValue(x, y)
|
|
||||||
} else {
|
|
||||||
environment.Occupy(t, x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
for x := 0; x < 300; x++ {
|
|
||||||
for y := 0; y < 300; y++ {
|
|
||||||
if maze[y/20][x/20] == 3 {
|
|
||||||
i := 0
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(models.NeoSlimeMold)
|
|
||||||
//sm.SniffDistance = *sniffDistance
|
|
||||||
sm.StartX, sm.StartY = x, y
|
|
||||||
sm.Num = i
|
|
||||||
i++
|
|
||||||
return sm
|
|
||||||
}, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
sm := new(models.NeoSlimeMold)
|
|
||||||
//sm.SniffDistance = *sniffDistance
|
|
||||||
return sm
|
|
||||||
}, 0)
|
|
||||||
|
|
||||||
experiment.InitPheromone("slime", color.RGBA{0x00, 0xfF, 0x00, 0xff})
|
|
||||||
experiment.InitPheromone("food", color.RGBA{0xff, 0xff, 0x00, 0xff})
|
|
||||||
experiment.OnStep = func(environment *core.Environment, turtles []*core.Turtle, i int) {
|
|
||||||
environment.EvaporateAndDiffuse(0.99, "slime")
|
|
||||||
environment.EvaporateAndDiffuse(0.99, "food")
|
|
||||||
|
|
||||||
for x := 0; x < 300; x++ {
|
|
||||||
for y := 0; y < 300; y++ {
|
|
||||||
if maze[y/20][x/20] == 2 && environment.HasValue(x, y) {
|
|
||||||
//environment.Mark("food",x,y,256)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fmt.Printf("%d: Turtles: %v\n", environment.Step, len(turtles))
|
|
||||||
|
|
||||||
}
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
)
|
|
||||||
|
|
||||||
var numFrogs = flag.Int("numFrogs", 5000, "the number of frogs")
|
|
||||||
var move = flag.Bool("move", true, "")
|
|
||||||
var turtlePreference = flag.Float64("turtlePreference", 0.3, "")
|
|
||||||
var frogPreference = flag.Float64("frogPreference", 0.3, "")
|
|
||||||
|
|
||||||
type Frog struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Frog) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
// Do nothing
|
|
||||||
t.SetAttribute("type", "frog")
|
|
||||||
t.SetColor(color.RGBA{0, 255, 255, 0})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Frog) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.FollowGradient(env, 1, 1, "frog-scent")
|
|
||||||
t.Wiggle()
|
|
||||||
amountTurtle := t.AmountAll(env, 1, "turtle-scent")
|
|
||||||
amountFrog := t.AmountAll(env, 1, "frog-scent")
|
|
||||||
if amountFrog > 1 && amountFrog > (amountTurtle+amountFrog)*float32(*frogPreference) {
|
|
||||||
// Do Nothing
|
|
||||||
} else {
|
|
||||||
if *move {
|
|
||||||
t.Step(env)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Drop(env, 1, "frog-scent")
|
|
||||||
}
|
|
||||||
|
|
||||||
type Turtle struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Turtle) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
// Do nothing
|
|
||||||
t.SetAttribute("type", "turtle")
|
|
||||||
t.SetColor(color.RGBA{255, 000, 0, 0})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *Turtle) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.FollowGradient(env, 1, 1, "turtle-scent")
|
|
||||||
t.Wiggle()
|
|
||||||
amountTurtle := t.AmountAll(env, 1, "turtle-scent")
|
|
||||||
amountFrog := t.AmountAll(env, 1, "frog-scent")
|
|
||||||
if amountTurtle > 1 && amountTurtle > (amountTurtle+amountFrog)*float32(*turtlePreference) {
|
|
||||||
// Do Nothing
|
|
||||||
} else {
|
|
||||||
if *move {
|
|
||||||
t.Step(env)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Drop(env, 1, "turtle-scent")
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
num := -1
|
|
||||||
experiment.InitNTurtles(func() core.Actor {
|
|
||||||
num++
|
|
||||||
if num%2 == 0 {
|
|
||||||
sm := new(Frog)
|
|
||||||
return sm
|
|
||||||
}
|
|
||||||
return new(Turtle)
|
|
||||||
}, *numFrogs+experiment.GetNumTurtles())
|
|
||||||
|
|
||||||
experiment.InitPheromone("turtle-scent", color.RGBA{0xFF, 0x00, 0x00, 0x00})
|
|
||||||
experiment.InitPheromone("frog-scent", color.RGBA{0x00, 0xFF, 0xFF, 0x00})
|
|
||||||
|
|
||||||
experiment.OnStep = func(env *core.Environment, turtles []*core.Turtle, i int) {
|
|
||||||
env.Evaporate(.99, "turtle-scent")
|
|
||||||
env.Evaporate(.99, "frog-scent")
|
|
||||||
}
|
|
||||||
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image/color"
|
|
||||||
"math/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
var sniffDistance = flag.Int("sniffDistance", 3, "the distance a turtle can detect pheromone levels from")
|
|
||||||
var numWoodChips = flag.Int("numWoodChips", 5000, "the number of woodchips in the model")
|
|
||||||
|
|
||||||
type WoodChips struct {
|
|
||||||
SniffDistance int
|
|
||||||
Carrying bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *WoodChips) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.SetColor(color.RGBA{0x00, 0xFF, 0xFF, 0x88})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *WoodChips) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
if a.Carrying {
|
|
||||||
if env.HasValue(t.Pos()) {
|
|
||||||
for {
|
|
||||||
t.Wiggle()
|
|
||||||
t.Step(env)
|
|
||||||
if !env.HasValue(t.Pos()) {
|
|
||||||
env.PutValue(t.Pos())
|
|
||||||
a.Carrying = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if env.HasValue(t.Pos()) {
|
|
||||||
env.TakeValue(t.Pos())
|
|
||||||
a.Carrying = true
|
|
||||||
t.TurnAround()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Wiggle()
|
|
||||||
t.Step(env)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mainrun() {
|
|
||||||
experiment := new(experiments.Experiment)
|
|
||||||
experiment.InitializeExperiment()
|
|
||||||
experiment.InitEnvironment(func(environment *core.Environment) {
|
|
||||||
for x := 0; x < *numWoodChips; x++ {
|
|
||||||
environment.PutValue(rand.Intn(environment.Width()), rand.Intn(environment.Height()))
|
|
||||||
}
|
|
||||||
|
|
||||||
for x := 200; x < 210; x++ {
|
|
||||||
for y := 200; y < 210; y++ {
|
|
||||||
environment.PutValue(x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
experiment.InitTurtles(func() core.Actor {
|
|
||||||
sm := new(WoodChips)
|
|
||||||
sm.SniffDistance = *sniffDistance
|
|
||||||
return sm
|
|
||||||
})
|
|
||||||
experiment.InitPheromone("trail", color.RGBA{0x80, 0xFF, 0x00, 0x00})
|
|
||||||
experiment.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
pixelgl.Run(mainrun)
|
|
||||||
}
|
|
20
go.mod
20
go.mod
|
@ -1,21 +1,3 @@
|
||||||
module git.openprivacy.ca/sarah/microworlds
|
module git.openprivacy.ca/sarah/microworlds
|
||||||
|
|
||||||
go 1.13
|
require github.com/veandco/go-sdl2 v0.3.0
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
|
||||||
github.com/asim/quadtree v0.0.0-20190907063054-ae2e556e6bb4
|
|
||||||
github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380 // indirect
|
|
||||||
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 // indirect
|
|
||||||
github.com/faiface/pixel v0.8.0
|
|
||||||
github.com/foolusion/quadtree v0.0.0-20140826014210-88d124c993be
|
|
||||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 // indirect
|
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 // indirect
|
|
||||||
github.com/go-gl/mathgl v0.0.0-20190713194549-592312d8590a // indirect
|
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
|
||||||
github.com/nickng/bibtex v1.0.1 // indirect
|
|
||||||
github.com/pkg/errors v0.8.1 // indirect
|
|
||||||
github.com/veandco/go-sdl2 v0.3.3
|
|
||||||
github.com/wcharczuk/go-chart v2.0.1+incompatible
|
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect
|
|
||||||
)
|
|
||||||
|
|
34
go.sum
34
go.sum
|
@ -1,36 +1,2 @@
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/asim/quadtree v0.0.0-20190907063054-ae2e556e6bb4 h1:ilm6YOZRb8ZA/ulKbNcL+AC/fbpkM3dRZ9kWXhBwx8U=
|
|
||||||
github.com/asim/quadtree v0.0.0-20190907063054-ae2e556e6bb4/go.mod h1:K2M5YTG4dpIXvuERd53snM5THchZczdy+k9gH02Shww=
|
|
||||||
github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380 h1:FvZ0mIGh6b3kOITxUnxS3tLZMh7yEoHo75v3/AgUqg0=
|
|
||||||
github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380/go.mod h1:zqnPFFIuYFFxl7uH2gYByJwIVKG7fRqlqQCbzAnHs9g=
|
|
||||||
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 h1:baVdMKlASEHrj19iqjARrPbaRisD7EuZEVJj6ZMLl1Q=
|
|
||||||
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3/go.mod h1:VEPNJUlxl5KdWjDvz6Q1l+rJlxF2i6xqDeGuGAxa87M=
|
|
||||||
github.com/faiface/pixel v0.8.0 h1:phOHW6ixfMAKRamjnvhI6FFI2VRyPEq7+LmmkDGXB/4=
|
|
||||||
github.com/faiface/pixel v0.8.0/go.mod h1:CEUU/s9E82Kqp01Boj1O67KnBskqiLghANqvUJGgDAM=
|
|
||||||
github.com/foolusion/quadtree v0.0.0-20140826014210-88d124c993be h1:fLLJtjJ2bdBHXLPtRsDVdnVEr9zBmw9be/WF751O0Gg=
|
|
||||||
github.com/foolusion/quadtree v0.0.0-20140826014210-88d124c993be/go.mod h1:Gk+3NkBZRly4/GnVRU95Wwv+JmmyoVGmdcEDwA5Wm1M=
|
|
||||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw=
|
|
||||||
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
|
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=
|
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
|
||||||
github.com/go-gl/mathgl v0.0.0-20190713194549-592312d8590a h1:yoAEv7yeWqfL/l9A/J5QOndXIJCldv+uuQB1DSNQbS0=
|
|
||||||
github.com/go-gl/mathgl v0.0.0-20190713194549-592312d8590a/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ=
|
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
|
||||||
github.com/nickng/bibtex v1.0.1 h1:Uop3DVOdQdrTamXfxr65f9KyHrd4RhttXwHi1BY6Wk0=
|
|
||||||
github.com/nickng/bibtex v1.0.1/go.mod h1:0qHZj8RRrLaGXyPoF9odM3M1EX1HnWiwACyR3wgGf8U=
|
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/veandco/go-sdl2 v0.3.0 h1:IWYkHMp8V3v37NsKjszln8FFnX2+ab0538J371t+rss=
|
github.com/veandco/go-sdl2 v0.3.0 h1:IWYkHMp8V3v37NsKjszln8FFnX2+ab0538J371t+rss=
|
||||||
github.com/veandco/go-sdl2 v0.3.0/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg=
|
github.com/veandco/go-sdl2 v0.3.0/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg=
|
||||||
github.com/veandco/go-sdl2 v0.3.1 h1:WMQ72+BeCj2o/zOO/wsB4MMpqHr1Y67m6QNFxp053ug=
|
|
||||||
github.com/veandco/go-sdl2 v0.3.1/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg=
|
|
||||||
github.com/veandco/go-sdl2 v0.3.3 h1:4/TirgB2MQ7oww3pM3Yfgf1YbChMlAQAmiCPe5koK0I=
|
|
||||||
github.com/veandco/go-sdl2 v0.3.3/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg=
|
|
||||||
github.com/wcharczuk/go-chart v2.0.1+incompatible h1:0pz39ZAycJFF7ju/1mepnk26RLVLBCWz1STcD3doU0A=
|
|
||||||
github.com/wcharczuk/go-chart v2.0.1+incompatible/go.mod h1:PF5tmL4EIx/7Wf+hEkpCqYi5He4u90sw+0+6FhrryuE=
|
|
||||||
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
|
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
package graphics
|
package graphics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
"git.openprivacy.ca/sarah/microworlds/core"
|
||||||
"github.com/faiface/pixel"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
"github.com/faiface/pixel/imdraw"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
"math"
|
"math"
|
||||||
|
"os"
|
||||||
//"strconv"
|
//"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Graphics struct {
|
type Graphics struct {
|
||||||
window *pixelgl.Window
|
window *sdl.Window
|
||||||
|
renderer *sdl.Renderer
|
||||||
width, height, pxsize int32
|
width, height, pxsize int32
|
||||||
imd *imdraw.IMDraw
|
|
||||||
t int
|
t int
|
||||||
colorMap map[string][4]uint8
|
colorMap map[string][4]uint8
|
||||||
}
|
}
|
||||||
|
@ -24,31 +22,28 @@ func NewGraphics(width, height, pxsize int32) *Graphics {
|
||||||
graphics.width = width
|
graphics.width = width
|
||||||
graphics.height = height
|
graphics.height = height
|
||||||
graphics.pxsize = pxsize
|
graphics.pxsize = pxsize
|
||||||
cfg := pixelgl.WindowConfig{
|
window, err := sdl.CreateWindow("Microworlds", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
|
||||||
Title: "Microworlds",
|
width * pxsize, height * pxsize, sdl.WINDOW_SHOWN)
|
||||||
Bounds: pixel.R(0, 0, float64(width*pxsize), float64(height*pxsize)),
|
|
||||||
VSync: true,
|
|
||||||
Resizable: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
win, err := pixelgl.NewWindow(cfg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
graphics.imd = imdraw.New(nil)
|
graphics.window = window
|
||||||
graphics.window = win
|
|
||||||
|
surface, _ := window.GetSurface()
|
||||||
|
renderer, err := sdl.CreateSoftwareRenderer(surface)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to create renderer: %s\n", err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
graphics.colorMap = make(map[string][4]uint8)
|
graphics.colorMap = make(map[string][4]uint8)
|
||||||
|
|
||||||
|
graphics.renderer = renderer
|
||||||
return graphics
|
return graphics
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) DrawTileColor(imd *imdraw.IMDraw, x, y int32, rgba color.RGBA) {
|
func (g *Graphics) DrawTileColor(x, y int32) {
|
||||||
|
g.renderer.FillRect(&sdl.Rect{X: x * g.pxsize, Y: y * g.pxsize, W: g.pxsize, H: g.pxsize})
|
||||||
imd.Color = rgba
|
|
||||||
imd.Push(pixel.V(float64(x*g.pxsize), float64(y*g.pxsize)))
|
|
||||||
imd.Push(pixel.V(float64((x*g.pxsize)+g.pxsize), float64(y*g.pxsize)))
|
|
||||||
imd.Push(pixel.V(float64(x*g.pxsize), float64((y*g.pxsize)+g.pxsize)))
|
|
||||||
imd.Push(pixel.V(float64((x*g.pxsize)+g.pxsize), float64((y*g.pxsize)+g.pxsize)))
|
|
||||||
imd.Rectangle(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) ColorPheromone(name string, color [4]uint8) {
|
func (g *Graphics) ColorPheromone(name string, color [4]uint8) {
|
||||||
|
@ -56,55 +51,43 @@ func (g *Graphics) ColorPheromone(name string, color [4]uint8) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graphics) Render(env *core.Environment, turtles []*core.Turtle) {
|
func (g *Graphics) Render(env *core.Environment, turtles []*core.Turtle) {
|
||||||
g.imd.Clear()
|
g.renderer.SetDrawColor(0x00, 0x00, 0x00, 0x00)
|
||||||
g.window.Clear(color.RGBA{0,0,0,0})
|
g.renderer.FillRect(&sdl.Rect{X: 0, Y: 0, W: g.width * g.pxsize, H: g.width * g.pxsize})
|
||||||
pheromoneImage := image.NewRGBA(image.Rect(0, 0, int(g.width), int(g.height)))
|
|
||||||
for x := 0; x < int(g.width); x++ {
|
for x := 0; x < int(g.width); x++ {
|
||||||
for y := 0; y < int(g.height); y++ {
|
for y := 0; y < int(g.height); y++ {
|
||||||
if env.HasValue(x, y) {
|
|
||||||
pheromoneImage.SetRGBA(x,y, color.RGBA{255, 0, 128, 0xFF})
|
|
||||||
} else {
|
|
||||||
scaledamountRedTotal := 0
|
|
||||||
scaledamountGreenTotal := 0
|
|
||||||
scaledamountBlueTotal := 0
|
|
||||||
for name, color := range g.colorMap {
|
for name, color := range g.colorMap {
|
||||||
amount := math.Min(float64(env.Sniff(name, x, y)), 255)
|
amount := math.Min(float64(env.Sniff(name, x, y)), 255)
|
||||||
|
|
||||||
if amount > 2 {
|
|
||||||
amount = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
if amount > 0 {
|
if amount > 0 {
|
||||||
scaledamountRed := uint8(float64(color[0]) * (amount / 2))
|
// TODO explictly define this scale
|
||||||
scaledamountGreen := uint8(float64(color[1]) * (amount / 2))
|
scaledamount := uint8(float64(color[0]) * (amount/2))
|
||||||
scaledamountBlue := uint8(float64(color[2]) * (amount / 2))
|
g.renderer.SetDrawColor(scaledamount,0,scaledamount, uint8(0xF0))
|
||||||
scaledamountRedTotal += int(scaledamountRed)
|
g.DrawTileColor(int32(x), int32(y))
|
||||||
scaledamountGreenTotal += int(scaledamountGreen)
|
|
||||||
scaledamountBlueTotal += int(scaledamountBlue)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pheromoneImage.SetRGBA(x, y, color.RGBA{uint8(scaledamountRedTotal / len(g.colorMap)), uint8(scaledamountGreenTotal / len(g.colorMap)), uint8(scaledamountBlueTotal / len(g.colorMap)), uint8(0xF0)})
|
|
||||||
|
if env.HasValue(x, y) {
|
||||||
|
g.renderer.SetDrawColor(255, 255, 255, uint8(255))
|
||||||
|
g.DrawTileColor(int32(x), int32(y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pd := pixel.PictureDataFromImage(pheromoneImage)
|
g.renderer.SetDrawColor(0xF3, 0x81, 0, 0x00)
|
||||||
sprite := pixel.NewSprite(pd, pd.Bounds())
|
|
||||||
mat := pixel.IM
|
|
||||||
|
|
||||||
mat = mat.Moved(g.window.Bounds().Center())
|
|
||||||
mat = mat.ScaledXY(pixel.V(float64(g.width*g.pxsize)/2, float64(g.height*g.pxsize)/2), pixel.V(float64(g.pxsize), float64(-g.pxsize)))
|
|
||||||
sprite.Draw(g.window, mat)
|
|
||||||
|
|
||||||
for _, t := range turtles {
|
for _, t := range turtles {
|
||||||
if t.GetAttribute("status") == "dead" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
x, y := t.Pos()
|
x, y := t.Pos()
|
||||||
g.DrawTileColor(g.imd, int32(x), int32(y), t.GetColor())
|
g.DrawTileColor(int32(x), int32(y))
|
||||||
|
t.Run(env)
|
||||||
}
|
}
|
||||||
g.imd.Draw(g.window)
|
|
||||||
g.window.Update()
|
// TODO: Move this into an environment specification
|
||||||
|
for name := range g.colorMap {
|
||||||
|
env.Evaporate(0.95, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
g.renderer.Present()
|
||||||
|
g.window.UpdateSurface()
|
||||||
// surface, _ := g.window.GetSurface()
|
// surface, _ := g.window.GetSurface()
|
||||||
// surface.SaveBMP("./images/" + strconv.Itoa(g.t) + ".bmp")
|
// surface.SaveBMP("./images/" + strconv.Itoa(g.t) + ".bmp")
|
||||||
g.t++
|
g.t++
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
package graphics
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"github.com/faiface/pixel"
|
|
||||||
"github.com/faiface/pixel/pixelgl"
|
|
||||||
"github.com/wcharczuk/go-chart"
|
|
||||||
"image"
|
|
||||||
"log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Plot struct {
|
|
||||||
GeneratePlot func(*core.Environment, []*core.Turtle) *chart.Chart
|
|
||||||
async chan chart.Chart
|
|
||||||
width, height int32
|
|
||||||
window *pixelgl.Window
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPlot(title string, width, height, pxsize int32) *Plot {
|
|
||||||
graphics := new(Plot)
|
|
||||||
graphics.width = width
|
|
||||||
graphics.height = height
|
|
||||||
cfg := pixelgl.WindowConfig{
|
|
||||||
Title: title,
|
|
||||||
Bounds: pixel.R(0, 0, float64(width), float64(height)),
|
|
||||||
VSync: true,
|
|
||||||
Resizable: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
win, err := pixelgl.NewWindow(cfg)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
graphics.window = win
|
|
||||||
graphics.async = make(chan chart.Chart)
|
|
||||||
return graphics
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Plot) RenderAsync() {
|
|
||||||
w := p.window.Bounds().W()
|
|
||||||
h := p.window.Bounds().H()
|
|
||||||
for {
|
|
||||||
graph := <-p.async
|
|
||||||
nw := p.window.Bounds().W()
|
|
||||||
nh := p.window.Bounds().H()
|
|
||||||
if nw != w || nh != h {
|
|
||||||
w = nw
|
|
||||||
h = nh
|
|
||||||
}
|
|
||||||
graph.Width = int(w)
|
|
||||||
graph.Height = int(h)
|
|
||||||
buffer := bytes.NewBuffer([]byte{})
|
|
||||||
err := graph.Render(chart.PNG, buffer)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
graphimg, _, _ := image.Decode(buffer)
|
|
||||||
pd := pixel.PictureDataFromImage(graphimg)
|
|
||||||
sprite := pixel.NewSprite(pd, pd.Bounds())
|
|
||||||
sprite.Draw(p.window, pixel.IM.Moved(p.window.Bounds().Center()))
|
|
||||||
|
|
||||||
/**for x := 0; x < int(w); x++ {
|
|
||||||
for y := 0; y < int(h); y++ {
|
|
||||||
col := graphimg.At(x, y)
|
|
||||||
r, g, b, a := col.RGBA()
|
|
||||||
if r != 0xff && g != 0xff && b != 0xff {
|
|
||||||
p.renderer.SetDrawColor(uint8(r), uint8(g), uint8(b), uint8(a))
|
|
||||||
p.renderer.DrawPoint(int32(x), int32(y))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
p.window.Update()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Plot) Render(env *core.Environment, turtles []*core.Turtle) {
|
|
||||||
graph := p.GeneratePlot(env, turtles)
|
|
||||||
if env.Step > 2 {
|
|
||||||
p.async <- *graph
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"git.openprivacy.ca/sarah/microworlds/actors"
|
||||||
|
"git.openprivacy.ca/sarah/microworlds/core"
|
||||||
|
"git.openprivacy.ca/sarah/microworlds/graphics"
|
||||||
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"runtime/pprof"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
|
||||||
|
|
||||||
|
var model = flag.String("model", "slime", "slimemold|swarm|woodchips")
|
||||||
|
|
||||||
|
var width = flag.Int("width", 300, "width of environment")
|
||||||
|
var height = flag.Int("height", 300, "height of environment")
|
||||||
|
var pxsize = flag.Int("pxsize", 1, "pixels per tile edge")
|
||||||
|
var numTurtles = flag.Int("numTurtles", 5000, "number of turtles")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// We don't need real randomness
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
if *cpuprofile != "" {
|
||||||
|
f, err := os.Create(*cpuprofile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
pprof.StartCPUProfile(f)
|
||||||
|
defer pprof.StopCPUProfile()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer sdl.Quit()
|
||||||
|
|
||||||
|
env := core.NewEnvironment(*width, *height)
|
||||||
|
turtles := make([]*core.Turtle, *numTurtles)
|
||||||
|
g := graphics.NewGraphics(int32(*width), int32(*height), int32(*pxsize))
|
||||||
|
|
||||||
|
switch *model {
|
||||||
|
|
||||||
|
case "swarm":
|
||||||
|
// Create 2 food blocks
|
||||||
|
for x := 100; x < 110; x++ {
|
||||||
|
for y := 100; y < 110; y++ {
|
||||||
|
env.PutValue(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for x := 200; x < 210; x++ {
|
||||||
|
for y := 200; y < 210; y++ {
|
||||||
|
env.PutValue(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 0; i < *numTurtles; i++ {
|
||||||
|
turtles[i] = core.NewTurtle(env, &actors.Ant{SniffDistance: 3, Carrying: false})
|
||||||
|
}
|
||||||
|
env.InitPheromone("food")
|
||||||
|
g.ColorPheromone("food", [4]uint8{0x81, 0x81, 0x12, 0x00})
|
||||||
|
case "woodchips":
|
||||||
|
for x := 0; x < *numTurtles; x++ {
|
||||||
|
env.PutValue(rand.Intn(*width), rand.Intn(*height))
|
||||||
|
}
|
||||||
|
|
||||||
|
for x := 200; x < 210; x++ {
|
||||||
|
for y := 200; y < 210; y++ {
|
||||||
|
env.PutValue(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := 0; i < *numTurtles; i++ {
|
||||||
|
turtles[i] = core.NewTurtle(env, &actors.WoodChips{SniffDistance: 20, Carrying: false})
|
||||||
|
}
|
||||||
|
case "slimemold":
|
||||||
|
for i := 0; i < *numTurtles; i++ {
|
||||||
|
turtles[i] = core.NewTurtle(env, &actors.SlimeMold{SniffDistance: 5})
|
||||||
|
}
|
||||||
|
env.InitPheromone("trail")
|
||||||
|
g.ColorPheromone("trail", [4]uint8{0x81, 0, 0x81, 0x00})
|
||||||
|
|
||||||
|
default:
|
||||||
|
for i := 0; i < *numTurtles; i++ {
|
||||||
|
turtles[i] = core.NewTurtle(env, &actors.SlimeMold{SniffDistance: 20})
|
||||||
|
}
|
||||||
|
env.InitPheromone("trail")
|
||||||
|
g.ColorPheromone("trail", [4]uint8{0x81, 0, 0x81, 0x00})
|
||||||
|
}
|
||||||
|
|
||||||
|
running := true
|
||||||
|
wait := sync.WaitGroup{}
|
||||||
|
|
||||||
|
wait.Add(1)
|
||||||
|
go func() {
|
||||||
|
for running {
|
||||||
|
g.Render(env, turtles)
|
||||||
|
}
|
||||||
|
wait.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
wait.Add(1)
|
||||||
|
for running {
|
||||||
|
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
||||||
|
switch event.(type) {
|
||||||
|
case *sdl.QuitEvent:
|
||||||
|
running = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wait.Done()
|
||||||
|
wait.Wait()
|
||||||
|
}
|
|
@ -1,85 +0,0 @@
|
||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"image/color"
|
|
||||||
)
|
|
||||||
|
|
||||||
type NeoSlimeMold struct {
|
|
||||||
Num int
|
|
||||||
StartX, StartY int
|
|
||||||
N int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *NeoSlimeMold) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.SetColor(color.RGBA{100, 255, 10, 0})
|
|
||||||
if sm.StartX != 0 && sm.StartY != 0 {
|
|
||||||
t.SetXY(sm.StartX, sm.StartY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *NeoSlimeMold) CheckNeighbours(env *core.Environment, ox, oy int) int {
|
|
||||||
neighbours := 0
|
|
||||||
if env.Check(ox-1, oy-1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox, oy-1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox+1, oy-1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox-1, oy) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox+1, oy) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
|
|
||||||
if env.Check(ox-1, oy+1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox, oy+1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox+1, oy+1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
return neighbours
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *NeoSlimeMold) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
|
|
||||||
// Move around the world, if there are too many slimes around us turn around, otherwise follow slimes and food.
|
|
||||||
t.Wiggle()
|
|
||||||
if sm.N == 0 {
|
|
||||||
t.FollowGradient(env, 1, .1, "food")
|
|
||||||
}
|
|
||||||
t.AvoidAverageGradient(env, 1, 1, "slime")
|
|
||||||
|
|
||||||
// If we have no neighbours we pretend we found some food so the others can find us.
|
|
||||||
if t.Step(env) {
|
|
||||||
ox, oy := t.Pos()
|
|
||||||
if sm.CheckNeighbours(env, ox, oy) > 3 {
|
|
||||||
t.Drop(env, .1, "slime")
|
|
||||||
} else {
|
|
||||||
t.Drop(env, .1, "food")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We are on top of other slime, add some more randomness
|
|
||||||
t.Wiggle()
|
|
||||||
t.Wiggle()
|
|
||||||
t.Wiggle()
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've found food, let's drop some chemical to tell others
|
|
||||||
if env.HasValue(t.Pos()) && sm.N == 0 {
|
|
||||||
//env.TakeValue(t.Pos())
|
|
||||||
sm.N = 100
|
|
||||||
t.Drop(env, 20, "food")
|
|
||||||
}
|
|
||||||
|
|
||||||
if sm.N > 0 {
|
|
||||||
sm.N--
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
package models
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.openprivacy.ca/sarah/microworlds/core"
|
|
||||||
"image/color"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SlimeMold struct {
|
|
||||||
Num int
|
|
||||||
StartX, StartY int
|
|
||||||
N int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) Setup(env *core.Environment, t *core.Turtle) {
|
|
||||||
t.SetColor(color.RGBA{100, 255, 10, 0})
|
|
||||||
if sm.StartX != 0 && sm.StartY != 0 {
|
|
||||||
t.SetXY(sm.StartX, sm.StartY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) CheckNeighbours(env *core.Environment, ox, oy int) int {
|
|
||||||
neighbours := 0
|
|
||||||
if env.Check(ox-1, oy-1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox, oy-1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox+1, oy-1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox-1, oy) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox+1, oy) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
|
|
||||||
if env.Check(ox-1, oy+1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox, oy+1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
if env.Check(ox+1, oy+1) {
|
|
||||||
neighbours++
|
|
||||||
}
|
|
||||||
return neighbours
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *SlimeMold) Run(env *core.Environment, t *core.Turtle) {
|
|
||||||
|
|
||||||
// Move around the world, if there are too many slimes around us turn around, otherwise follow slimes and food.
|
|
||||||
t.Wiggle()
|
|
||||||
if t.Amount(env, 1, "slime") > 10 {
|
|
||||||
t.TurnAround()
|
|
||||||
} else {
|
|
||||||
t.FollowGradient(env, 1, 1, "slime")
|
|
||||||
}
|
|
||||||
t.FollowGradient(env, 1, .1, "food")
|
|
||||||
|
|
||||||
// If we have no neighbours we pretend we found some food so the others can find us.
|
|
||||||
if t.Step(env) {
|
|
||||||
ox, oy := t.Pos()
|
|
||||||
if sm.CheckNeighbours(env, ox, oy) > 3 && !env.HasValue(t.Pos()) {
|
|
||||||
t.Drop(env, .1, "slime")
|
|
||||||
} else {
|
|
||||||
t.Drop(env, 1, "food")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We are on top of other slime, add some more randomness
|
|
||||||
t.Wiggle()
|
|
||||||
t.Wiggle()
|
|
||||||
t.Wiggle()
|
|
||||||
}
|
|
||||||
|
|
||||||
// We've found food, let's drop some chemical to tell others
|
|
||||||
if env.HasValue(t.Pos()) {
|
|
||||||
env.TakeValue(t.Pos())
|
|
||||||
t.Drop(env, 10, "food")
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue