From 06da955b217911a06c13afc1f9e569b1141ac2e2 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Sat, 30 Nov 2019 13:50:21 -0800 Subject: [PATCH] Much nicer flocking simulation --- experiments/flocking/flocking.go | 107 +++++++++++++++++++++++++++ experiments/flocking/main.go | 66 ----------------- experiments/predatorprey/predprey.go | 13 ++-- graphics/graphics.go | 4 +- 4 files changed, 115 insertions(+), 75 deletions(-) create mode 100644 experiments/flocking/flocking.go delete mode 100644 experiments/flocking/main.go diff --git a/experiments/flocking/flocking.go b/experiments/flocking/flocking.go new file mode 100644 index 0000000..b2160bf --- /dev/null +++ b/experiments/flocking/flocking.go @@ -0,0 +1,107 @@ +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) +} diff --git a/experiments/flocking/main.go b/experiments/flocking/main.go deleted file mode 100644 index 1045414..0000000 --- a/experiments/flocking/main.go +++ /dev/null @@ -1,66 +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") - -type Bird struct { -} - -func (sm *Bird) Setup(env *core.Environment, t *core.Turtle) { - t.SetColor(color.RGBA{100, 255, 10, 0}) - //t.SetHeading(5) -} - -func (sm *Bird) Run(env *core.Environment, t *core.Turtle) { - //t.Wiggle() - if t.AmountAll(env, 1, "bird") > 1 { - //t.Wiggle() - t.AvoidAverageGradient(env, 1, 2.5, "bird") - //t.Wiggle() - t.Step(env) - t.Drop(env, 2, "bird") - } else if t.AmountAll(env, 1, "bird") > 2 { - t.AvoidAverageGradient(env, 1, 1, "bird") - t.Wiggle() - t.Step(env) - t.Drop(env, 1, "bird") - } else { - // t.TurnAround() - // t.Wiggle() - // t.Wiggle() - // t.Wiggle() - t.FollowAverageGradient(env, 5, 1, "bird") - t.FollowAverageGradient(env, 4, 2, "bird") - t.FollowAverageGradient(env, 3, 3, "bird") - //t.FollowAverageGradient(env, 2, 4, "bird") - - t.Step(env) - t.Drop(env, 1, "bird") - } -} - -func mainrun() { - experiment := new(experiments.Experiment) - experiment.InitializeExperiment() - experiment.InitTurtles(func() core.Actor { - sm := new(Bird) - - return sm - }) - experiment.InitPheromone("bird", color.RGBA{0x80, 0xaa, 0x00, 0x00}) - experiment.OnStep = func(environment *core.Environment, turtles []*core.Turtle, i int) { - environment.EvaporateAndDiffuse(0.99, "bird") - } - experiment.Run() -} - -func main() { - pixelgl.Run(mainrun) -} diff --git a/experiments/predatorprey/predprey.go b/experiments/predatorprey/predprey.go index 9612e7d..62433f7 100644 --- a/experiments/predatorprey/predprey.go +++ b/experiments/predatorprey/predprey.go @@ -149,24 +149,23 @@ func mainrun() { } x = append(x, float64(environment.Step)) - prey = append(prey, float64(preyalive)) - pred = append(pred, float64(predalive)) + 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 Size", + Name: "Prey Population Density", XValues: x, YValues: prey, } predpop := chart.ContinuousSeries{ - Name: "Predator Population Size", + Name: "Predator Population Density", XValues: x, YValues: pred, + } graph := chart.Chart{ - Width: 300, - Height: 300, Background: chart.Style{ Padding: chart.Box{ @@ -176,7 +175,7 @@ func mainrun() { 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 { + 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{ diff --git a/graphics/graphics.go b/graphics/graphics.go index 3952a5c..2622092 100644 --- a/graphics/graphics.go +++ b/graphics/graphics.go @@ -57,12 +57,12 @@ func (g *Graphics) ColorPheromone(name string, color [4]uint8) { func (g *Graphics) Render(env *core.Environment, turtles []*core.Turtle) { g.imd.Clear() - //g.window.Clear(color.RGBA{0,0,0,0}) + g.window.Clear(color.RGBA{0,0,0,0}) pheromoneImage := image.NewRGBA(image.Rect(0, 0, int(g.width), int(g.height))) for x := 0; x < int(g.width); x++ { for y := 0; y < int(g.height); y++ { if env.HasValue(x, y) { - g.DrawTileColor(g.imd, int32(x), int32(y), color.RGBA{255, 255, 255, uint8(255)}) + pheromoneImage.SetRGBA(x,y, color.RGBA{255, 0, 128, 0xFF}) } else { scaledamountRedTotal := 0 scaledamountGreenTotal := 0