forked from sarah/microworlds
Plotting, Slime Mazes, Evolution(First Cuts)
This commit is contained in:
parent
a7be149155
commit
3ba02dfb02
|
@ -1,17 +1,47 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"github.com/foolusion/quadtree"
|
||||
)
|
||||
|
||||
type Environment struct {
|
||||
width, height int
|
||||
state map[string][][]float32
|
||||
value [][]bool
|
||||
col [][]*Turtle
|
||||
Step int
|
||||
quadtree *quadtree.QuadTree
|
||||
}
|
||||
|
||||
func (e *Environment) Width() int {
|
||||
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 {
|
||||
return e.height
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ func (t *Turtle) Heading() int {
|
|||
|
||||
func NewTurtle(env *Environment, actor Actor) *Turtle {
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
for i := 0; i < 10; i++ {
|
||||
turtle := new(Turtle)
|
||||
turtle.width = env.width
|
||||
turtle.height = env.height
|
||||
|
@ -42,7 +42,7 @@ func NewTurtle(env *Environment, actor Actor) *Turtle {
|
|||
turtle.ypos = rand.Intn(env.height)
|
||||
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)
|
||||
env.Occupy(turtle, turtle.xpos, turtle.ypos)
|
||||
|
@ -109,7 +109,6 @@ func (t *Turtle) SetHeading(heading int) {
|
|||
t.heading = heading
|
||||
}
|
||||
|
||||
|
||||
func (t *Turtle) TurnAround() {
|
||||
t.heading = (t.heading + 4) % 8
|
||||
}
|
||||
|
@ -256,6 +255,42 @@ 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) {
|
||||
|
||||
|
|
|
@ -0,0 +1,361 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.openprivacy.ca/sarah/microworlds/core"
|
||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
||||
"image/color"
|
||||
"math/rand"
|
||||
"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 main() {
|
||||
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))
|
||||
|
||||
if environment.Step % 10 == 0 {
|
||||
|
||||
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])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
experiment.Run()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"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"
|
||||
|
@ -27,6 +28,8 @@ type Experiment struct {
|
|||
initializedTurtles int
|
||||
pheromones []string
|
||||
OnStep func(*core.Environment, []*core.Turtle, int)
|
||||
plots []*graphics.Plot
|
||||
running bool
|
||||
}
|
||||
|
||||
func (e *Experiment) InitializeExperiment() {
|
||||
|
@ -40,7 +43,6 @@ func (e *Experiment) InitializeExperiment() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
pprof.StartCPUProfile(f)
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil {
|
||||
|
@ -89,43 +91,65 @@ 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
|
||||
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{}
|
||||
|
||||
running := true
|
||||
e.running = true
|
||||
wait.Add(1)
|
||||
e.env.ResetQuadtree()
|
||||
go func() {
|
||||
step := 0
|
||||
for running {
|
||||
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)
|
||||
deleted := 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
|
||||
deleted++
|
||||
}
|
||||
}
|
||||
|
||||
e.turtles = newTurtles
|
||||
e.env.ResetQuadtree()
|
||||
for _, t := range e.turtles {
|
||||
e.env.InsertIntoQuadTree(t)
|
||||
}
|
||||
|
||||
step++
|
||||
}
|
||||
wait.Done()
|
||||
}()
|
||||
|
||||
wait.Add(1)
|
||||
for running {
|
||||
for e.running {
|
||||
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
||||
switch event.(type) {
|
||||
case *sdl.QuitEvent:
|
||||
running = false
|
||||
e.running = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
var sniffDistance = flag.Int("sniffDistance", 3, "the distance a turtle can detect pheromone levels from")
|
||||
|
||||
type Bird struct {
|
||||
|
||||
}
|
||||
|
||||
func (sm *Bird) Setup(env *core.Environment, t *core.Turtle) {
|
||||
|
@ -60,4 +59,3 @@ func main() {
|
|||
}
|
||||
experiment.Run()
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@ import (
|
|||
"git.openprivacy.ca/sarah/microworlds/core"
|
||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
||||
"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
|
||||
|
@ -22,10 +22,10 @@ func (sm *SlimeMold) Setup(env *core.Environment, t *core.Turtle) {
|
|||
}
|
||||
|
||||
func (sm *SlimeMold) Run(env *core.Environment, t *core.Turtle) {
|
||||
frac := (float64(sm.Age)/float64(env.Step+1))
|
||||
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, col})
|
||||
t.SetColor(color.RGBA{col, 0, col / 2, 0xf2})
|
||||
} else {
|
||||
t.SetColor(color.RGBA{col, 0, col, col})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"git.openprivacy.ca/sarah/microworlds/core"
|
||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
||||
"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 main() {
|
||||
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()
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"git.openprivacy.ca/sarah/microworlds/core"
|
||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"image/color"
|
||||
"math"
|
||||
"math/rand"
|
||||
|
@ -109,28 +110,25 @@ func main() {
|
|||
sm := new(Prey)
|
||||
return sm
|
||||
}, *numPrey)
|
||||
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) {
|
||||
alive := 0
|
||||
predalive := 0
|
||||
|
||||
env.EvaporateAndDiffuse(0.95, "scent")
|
||||
// Grow Grass
|
||||
x := rand.Intn(env.Width())
|
||||
y := rand.Intn(env.Height())
|
||||
env.PutValue(x, y)
|
||||
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" {
|
||||
alive++
|
||||
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)
|
||||
alive++
|
||||
preyalive++
|
||||
}
|
||||
}
|
||||
if turtle.GetAttribute("type") == "predator" && turtle.GetAttribute("status") != "dead" {
|
||||
|
@ -148,8 +146,57 @@ func main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
x = append(x, float64(environment.Step))
|
||||
prey = append(prey, float64(preyalive))
|
||||
pred = append(pred, float64(predalive))
|
||||
|
||||
preypop := chart.ContinuousSeries{
|
||||
Name: "Prey Population Size",
|
||||
XValues: x,
|
||||
YValues: prey,
|
||||
}
|
||||
|
||||
predpop := chart.ContinuousSeries{
|
||||
Name: "Predator Population Size",
|
||||
XValues: x,
|
||||
YValues: pred,
|
||||
}
|
||||
|
||||
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}, 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)
|
||||
//fmt.Printf("%v,%v,%v\n", step, alive, predalive)
|
||||
//}
|
||||
}
|
||||
experiment.Run()
|
|
@ -10,13 +10,14 @@ import (
|
|||
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) {
|
||||
|
|
|
@ -3,81 +3,10 @@ package main
|
|||
import (
|
||||
"git.openprivacy.ca/sarah/microworlds/core"
|
||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
||||
"git.openprivacy.ca/sarah/microworlds/models"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
type SlimeMold struct {
|
||||
Num int
|
||||
}
|
||||
|
||||
func (sm *SlimeMold) Setup(env *core.Environment, t *core.Turtle) {
|
||||
t.SetColor(color.RGBA{100, 255, 10, 0})
|
||||
t.SetXY(150+(sm.Num%100), 150+(sm.Num/100))
|
||||
}
|
||||
|
||||
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) > 0 || env.HasValue(t.Pos()) {
|
||||
t.Drop(env, .1, "slime")
|
||||
} else {
|
||||
t.Drop(env, 10, "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, 256, "food")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
experiment := new(experiments.Experiment)
|
||||
experiment.InitializeExperiment()
|
||||
|
@ -108,14 +37,14 @@ func main() {
|
|||
})
|
||||
|
||||
experiment.InitNTurtles(func() core.Actor {
|
||||
sm := new(SlimeMold)
|
||||
sm := new(models.SlimeMold)
|
||||
sm.Num = num
|
||||
num++
|
||||
return sm
|
||||
}, 3000)
|
||||
}, 10000)
|
||||
|
||||
experiment.InitPheromone("slime", color.RGBA{0x80, 0xFF, 0x00, 0x00})
|
||||
experiment.InitPheromone("food", 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")
|
||||
|
|
|
@ -4,97 +4,290 @@ import (
|
|||
"flag"
|
||||
"git.openprivacy.ca/sarah/microworlds/core"
|
||||
"git.openprivacy.ca/sarah/microworlds/experiments"
|
||||
"git.openprivacy.ca/sarah/microworlds/models"
|
||||
"image/color"
|
||||
"math"
|
||||
)
|
||||
|
||||
var sniffDistance = flag.Int("sniffDistance", 30, "the distance an ant can detect pheromone levels from")
|
||||
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{0xff, 0, 0, 0xff})
|
||||
t.SetColor(color.RGBA{0x4b, 0x35, 0x57, 0xff})
|
||||
}
|
||||
func (a *Wall) Run(env *core.Environment, t *core.Turtle) {
|
||||
|
||||
}
|
||||
|
||||
type Ant struct {
|
||||
SniffDistance int
|
||||
Carrying bool
|
||||
DropSize float64
|
||||
type SlimeMold struct {
|
||||
Num int
|
||||
Heading 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, W, W, W, W, W, 0, W, 0, W, 0, W, 0, W},
|
||||
{W, 0, W, 0, 0, 0, 0, 0, W, 0, W, 0, W, 0, W},
|
||||
{W, 0, W, 0, W, W, W, W, W, 0, W, 0, W, 0, W},
|
||||
{W, 0, W, 0, W, 0, 0, 0, 0, 0, W, 0, W, 0, W},
|
||||
{W, 0, W, 0, W, 0, W, W, W, 0, W, 0, W, 0, W},
|
||||
{W, 0, 0, 0, W, 0, 0, 0, W, 0, W, W, W, 0, W},
|
||||
{W, 0, W, 0, W, W, 0, W, W, 0, W, 0, W, 0, W},
|
||||
{W, 0, W, 0, W, 0, 0, W, 0, 0, W, 0, W, 0, W},
|
||||
{W, 0, W, 0, W, W, 0, W, 0, W, W, 0, 0, 0, W},
|
||||
{W, 2, W, 0, W, 0, 0, W, 0, 0, 0, 0, W, 0, W},
|
||||
{W, 2, W, 0, W, 0, W, W, W, W, W, 0, W, 0, W},
|
||||
{W, 2, W, 0, W, 0, 0, W, 0, 0, 0, 0, W, 2, 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},
|
||||
}
|
||||
|
||||
func (a *Ant) Setup(env *core.Environment, t *core.Turtle) {
|
||||
//t.SetColor(color.RGBA{0x67,0xf5,0x10,0xff})
|
||||
|
||||
//t.SetXY(40+(a.Num %70),50+(a.Num/50))
|
||||
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},
|
||||
}
|
||||
|
||||
func (a *Ant) Run(env *core.Environment, t *core.Turtle) {
|
||||
a.Heading = t.Heading()
|
||||
if env.HasValue(t.Pos()) || a.Carrying {
|
||||
t.Drop(env, 255, "slime")
|
||||
a.Carrying = true
|
||||
} else {
|
||||
n := t.Check(env)
|
||||
if n != nil {
|
||||
ant,ok := n.GetActor().(*Ant)
|
||||
if ok {
|
||||
if ant.Carrying {
|
||||
a.DropSize += 10
|
||||
t.SetHeading(a.Heading)
|
||||
} else if ant.DropSize > 20{
|
||||
t.SetHeading(a.Heading)
|
||||
a.DropSize += 5
|
||||
} else if ant.DropSize > 1 {
|
||||
t.Wiggle()
|
||||
a.DropSize += 5
|
||||
}
|
||||
}
|
||||
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},
|
||||
}
|
||||
|
||||
if a.DropSize < 10 {
|
||||
t.SetColor(color.RGBA{0, 0xf5, 0x10, 0x1f})
|
||||
t.FollowGradient(env, a.SniffDistance, 20, "slime")
|
||||
t.Wiggle()
|
||||
t.Step(env)
|
||||
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},
|
||||
}
|
||||
|
||||
if a.DropSize > 1 {
|
||||
a.DropSize--
|
||||
t.SetColor(color.RGBA{0xff,0xf5,0, 0x1f})
|
||||
t.Drop(env, float32(a.DropSize), "slime")
|
||||
}
|
||||
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 main() {
|
||||
|
||||
maze = maze0
|
||||
|
||||
experiment := new(experiments.Experiment)
|
||||
experiment.InitializeExperiment()
|
||||
t := new(core.Turtle)
|
||||
|
@ -109,25 +302,62 @@ func main() {
|
|||
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.InitTurtles(func() core.Actor {
|
||||
sm := new(Ant)
|
||||
sm.SniffDistance = *sniffDistance
|
||||
sm.DropSize = 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.InitPheromone("slime", color.RGBA{0xff, 0xfF, 0x00, 0xff})
|
||||
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.5, "slime")
|
||||
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()
|
||||
}
|
||||
|
|
11
go.mod
11
go.mod
|
@ -2,4 +2,13 @@ module git.openprivacy.ca/sarah/microworlds
|
|||
|
||||
go 1.13
|
||||
|
||||
require github.com/veandco/go-sdl2 v0.3.3
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
github.com/asim/quadtree v0.0.0-20190907063054-ae2e556e6bb4
|
||||
github.com/foolusion/quadtree v0.0.0-20140826014210-88d124c993be
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/nickng/bibtex v1.0.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
|
||||
)
|
||||
|
|
15
go.sum
15
go.sum
|
@ -1,6 +1,21 @@
|
|||
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/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/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/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.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-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=
|
||||
|
|
|
@ -37,7 +37,6 @@ func NewGraphics(width, height, pxsize int32) *Graphics {
|
|||
}
|
||||
|
||||
graphics.colorMap = make(map[string][4]uint8)
|
||||
|
||||
graphics.renderer = renderer
|
||||
return graphics
|
||||
}
|
||||
|
@ -51,7 +50,7 @@ func (g *Graphics) ColorPheromone(name string, color [4]uint8) {
|
|||
}
|
||||
|
||||
func (g *Graphics) Render(env *core.Environment, turtles []*core.Turtle) {
|
||||
g.renderer.SetDrawColor(0x00, 0x00, 0x00, 0x00)
|
||||
g.renderer.SetDrawColor(0x00, 0x00, 0x0, 0xff)
|
||||
g.renderer.FillRect(&sdl.Rect{X: 0, Y: 0, W: g.width * g.pxsize, H: g.width * g.pxsize})
|
||||
|
||||
for x := 0; x < int(g.width); x++ {
|
||||
|
@ -84,7 +83,7 @@ func (g *Graphics) Render(env *core.Environment, turtles []*core.Turtle) {
|
|||
g.DrawTileColor(int32(x), int32(y))
|
||||
}
|
||||
|
||||
g.renderer.SetDrawColor(255, 0, 0, uint8(255))
|
||||
g.renderer.SetDrawColor(0x4b, 0x35, 0x57, uint8(255))
|
||||
if env.Get(x, y) != nil {
|
||||
g.DrawTileColor(int32(x), int32(y))
|
||||
}
|
||||
|
@ -99,7 +98,6 @@ func (g *Graphics) Render(env *core.Environment, turtles []*core.Turtle) {
|
|||
col := t.GetColor()
|
||||
g.renderer.SetDrawColor(col.R, col.G, col.B, col.A)
|
||||
g.DrawTileColor(int32(x), int32(y))
|
||||
t.Run(env)
|
||||
}
|
||||
|
||||
g.renderer.Present()
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package graphics
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"git.openprivacy.ca/sarah/microworlds/core"
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"image"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Plot struct {
|
||||
Graphics
|
||||
GeneratePlot func(*core.Environment, []*core.Turtle) *chart.Chart
|
||||
}
|
||||
|
||||
func NewPlot(title string, width, height, pxsize int32) *Plot {
|
||||
graphics := new(Plot)
|
||||
graphics.width = width
|
||||
graphics.height = height
|
||||
window, err := sdl.CreateWindow(title, sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
|
||||
width, height, sdl.WINDOW_SHOWN|sdl.WINDOW_RESIZABLE)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
graphics.window = window
|
||||
|
||||
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.renderer = renderer
|
||||
return graphics
|
||||
}
|
||||
|
||||
func (p *Plot) Render(env *core.Environment, turtles []*core.Turtle) {
|
||||
graph := p.GeneratePlot(env, turtles)
|
||||
|
||||
// graph.Elements = []chart.Renderable{chart.Legend(graph)}
|
||||
w, h := p.window.GetSize()
|
||||
surface, _ := p.window.GetSurface()
|
||||
renderer, _ := sdl.CreateSoftwareRenderer(surface)
|
||||
p.renderer = renderer
|
||||
graph.Width = int(w)
|
||||
graph.Height = int(h)
|
||||
if env.Step > 2 {
|
||||
buffer := bytes.NewBuffer([]byte{})
|
||||
err := graph.Render(chart.PNG, buffer)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
graph, _, _ := image.Decode(buffer)
|
||||
|
||||
for x := 0; x < int(w); x++ {
|
||||
for y := 0; y < int(h); y++ {
|
||||
col := graph.At(x, y)
|
||||
r, g, b, a := col.RGBA()
|
||||
p.renderer.SetDrawColor(uint8(r), uint8(g), uint8(b), uint8(a))
|
||||
p.renderer.DrawPoint(int32(x), int32(y))
|
||||
}
|
||||
}
|
||||
}
|
||||
p.window.UpdateSurface()
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
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--
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
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