diff --git a/actors/ant.go b/actors/ant.go deleted file mode 100644 index 5e4dda7..0000000 --- a/actors/ant.go +++ /dev/null @@ -1,35 +0,0 @@ -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) - } -} diff --git a/actors/flocking.go b/actors/flocking.go deleted file mode 100644 index 8f4a9bf..0000000 --- a/actors/flocking.go +++ /dev/null @@ -1,35 +0,0 @@ -package actors - -import ( -"git.openprivacy.ca/sarah/microworlds/core" -) - - -type Flocking struct { - SniffDistance int -} - -func (sm *Flocking) Setup(env *core.Environment, t *core.Turtle) { - // Do nothing -} - -func (sm *Flocking) Run(env *core.Environment, t *core.Turtle) { - if t.Near(env, 1,1, "avoid") { - t.TurnAround() - t.Step(env) - } else if t.Near(env, 2,1, "avoid") { - t.TurnAround() - t.Step(env) - } else { - t.FollowGradient(env, 4, 1, "trail") - t.FollowGradient(env, 3, 1,"trail") - t.FollowGradient(env, 2,1, "trail") - t.FollowGradient(env, 1, 3, "trail") - t.Wiggle() - t.Step(env) - } - t.Drop(env, 1, "trail") - t.Drop(env, 2, "avoid") -} - - diff --git a/actors/isolate.go b/actors/isolate.go deleted file mode 100644 index 8845626..0000000 --- a/actors/isolate.go +++ /dev/null @@ -1,67 +0,0 @@ -package actors - -import ( -"git.openprivacy.ca/sarah/microworlds/core" -"math/rand" -"strconv" -) - -type Isolate struct { - color int - Probability float32 - 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) - } -} - - diff --git a/actors/maze.go b/actors/maze.go deleted file mode 100644 index d0cb769..0000000 --- a/actors/maze.go +++ /dev/null @@ -1,23 +0,0 @@ -package actors - -import ( - "git.openprivacy.ca/sarah/microworlds/core" -) - - -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") -} - diff --git a/actors/slimemold.go b/actors/slimemold.go deleted file mode 100644 index 7903ba3..0000000 --- a/actors/slimemold.go +++ /dev/null @@ -1,20 +0,0 @@ -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") -} diff --git a/actors/slush.go b/actors/slush.go deleted file mode 100644 index c1e0f39..0000000 --- a/actors/slush.go +++ /dev/null @@ -1,41 +0,0 @@ -package actors - -import ( - "git.openprivacy.ca/sarah/microworlds/core" - "math/rand" - "strconv" -) - -type Slush struct { - color int - Probability float32 -} - -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) -} - - diff --git a/actors/snowball.go b/actors/snowball.go deleted file mode 100644 index d624a71..0000000 --- a/actors/snowball.go +++ /dev/null @@ -1,65 +0,0 @@ -package actors - -import ( - "git.openprivacy.ca/sarah/microworlds/core" - "math/rand" - "strconv" -) - -type Snowball struct { - color int - Probability float32 - sureness float32 - Byztantine bool -} - -func (sm *Snowball) 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 *Snowball) Run(env *core.Environment, t *core.Turtle) { - if sm.Byztantine { - t.Wiggle() - t.Drop(env, 1, "2") - } 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) - } -} - - diff --git a/actors/woodchips.go b/actors/woodchips.go deleted file mode 100644 index 63689ae..0000000 --- a/actors/woodchips.go +++ /dev/null @@ -1,38 +0,0 @@ -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) -} diff --git a/core/turtle.go b/core/turtle.go index efc6000..2df397c 100644 --- a/core/turtle.go +++ b/core/turtle.go @@ -5,10 +5,10 @@ import ( ) type Turtle struct { - xpos, ypos int - heading int - actor Actor - width,height int + xpos, ypos int + heading int + actor Actor + width, height int } type NilActor struct { @@ -58,7 +58,7 @@ func (t *Turtle) SetXY(x, y int) { if y < 0 { y = (t.height - 1) - } else if y >=t.height { + } else if y >= t.height { y = y % (t.height) } @@ -111,7 +111,7 @@ func (t *Turtle) Amount(env *Environment, distance int, pheromone string) float3 as0 := env.SniffNormalized(x0, y0, pheromone) as := env.SniffNormalized(x, y, pheromone) as1 := env.SniffNormalized(x1, y1, pheromone) - return as0+as+as1 + return as0 + as + as1 } func (t *Turtle) Near(env *Environment, distance int, threshold float32, pheromone string) bool { @@ -152,7 +152,7 @@ func (t *Turtle) Near(env *Environment, distance int, threshold float32, pheromo as1 = 0 } - if as0 == 0 && as == 0 && as1 == 0 { + if as0 == 0 && as == 0 && as1 == 0 { return false } else { return true diff --git a/experiments/experiment.go b/experiments/experiment.go new file mode 100644 index 0000000..7505aff --- /dev/null +++ b/experiments/experiment.go @@ -0,0 +1,102 @@ +package experiments + +import ( + "flag" + "git.openprivacy.ca/sarah/microworlds/core" + "git.openprivacy.ca/sarah/microworlds/graphics" + "github.com/veandco/go-sdl2/sdl" + "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 +} + +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) + defer pprof.StopCPUProfile() + } + + if err := sdl.Init(sdl.INIT_EVERYTHING); err != nil { + panic(err) + } + + e.env = core.NewEnvironment(*width, *height) + e.turtles = make([]*core.Turtle, *numTurtles) + 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.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) { + for i := e.initializedTurtles; i < e.initializedTurtles+num; i++ { + e.turtles[i] = core.NewTurtle(e.env, f()) + } + e.initializedTurtles += num +} + +func (e *Experiment) InitTurtles(f func() core.Actor) { + e.InitNTurtles(f, (*numTurtles)) +} + +func (e *Experiment) Run() { + wait := sync.WaitGroup{} + + running := true + wait.Add(1) + go func() { + for running { + e.graphics.Render(e.env, e.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() +} diff --git a/experiments/isolate/main.go b/experiments/isolate/main.go new file mode 100644 index 0000000..8e39af4 --- /dev/null +++ b/experiments/isolate/main.go @@ -0,0 +1,91 @@ +package main + +import ( + "flag" + "git.openprivacy.ca/sarah/microworlds/core" + "git.openprivacy.ca/sarah/microworlds/experiments" + "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 main() { + 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() +} diff --git a/experiments/maze/main.go b/experiments/maze/main.go new file mode 100644 index 0000000..2a2098a --- /dev/null +++ b/experiments/maze/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "flag" + "git.openprivacy.ca/sarah/microworlds/core" + "git.openprivacy.ca/sarah/microworlds/experiments" + "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 main() { + 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() +} diff --git a/experiments/slimemold/main.go b/experiments/slimemold/main.go new file mode 100644 index 0000000..e16ac26 --- /dev/null +++ b/experiments/slimemold/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "flag" + "git.openprivacy.ca/sarah/microworlds/core" + "git.openprivacy.ca/sarah/microworlds/experiments" + "image/color" +) + +var sniffDistance = flag.Int("sniffDistance", 3, "the distance a turtle can detect pheromone levels from") + +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") +} + +func main() { + 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() +} diff --git a/experiments/slush/main.go b/experiments/slush/main.go new file mode 100644 index 0000000..f72eacc --- /dev/null +++ b/experiments/slush/main.go @@ -0,0 +1,58 @@ +package main + +import ( + "flag" + "git.openprivacy.ca/sarah/microworlds/core" + "git.openprivacy.ca/sarah/microworlds/experiments" + "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 main() { + 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() +} diff --git a/experiments/snowball/main.go b/experiments/snowball/main.go new file mode 100644 index 0000000..b909713 --- /dev/null +++ b/experiments/snowball/main.go @@ -0,0 +1,89 @@ +package main + +import ( + "flag" + "git.openprivacy.ca/sarah/microworlds/core" + "git.openprivacy.ca/sarah/microworlds/experiments" + "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 Snowball struct { + color int + Probability float64 + sureness float32 + Byztantine bool +} + +func (sm *Snowball) 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 *Snowball) Run(env *core.Environment, t *core.Turtle) { + if sm.Byztantine { + t.Wiggle() + t.Drop(env, 1, "2") + } 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 main() { + experiment := new(experiments.Experiment) + experiment.InitializeExperiment() + honestTurtles := experiment.GetNumTurtles() - (*byzantineTurtles) + experiment.InitNTurtles(func() core.Actor { + sm := new(Snowball) + sm.Probability = *prob + return sm + }, honestTurtles) + 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.Run() +} diff --git a/experiments/swarm/main.go b/experiments/swarm/main.go new file mode 100644 index 0000000..b12f0fe --- /dev/null +++ b/experiments/swarm/main.go @@ -0,0 +1,66 @@ +package main + +import ( + "flag" + "git.openprivacy.ca/sarah/microworlds/core" + "git.openprivacy.ca/sarah/microworlds/experiments" + "image/color" +) + +var sniffDistance = flag.Int("sniffDistance", 3, "the distance an ant can detect pheromone levels from") +var dropSize = flag.Float64("dropSize", 1.0, "the amount of pheromone an ants drops") + +type Ant struct { + SniffDistance int + Carrying bool + DropSize float64 +} + +func (a *Ant) Setup(env *core.Environment, t *core.Turtle) { +} + +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, float32(a.DropSize), "food") + t.Wiggle() + t.Step(env) + } +} + +func main() { + experiment := new(experiments.Experiment) + experiment.InitializeExperiment() + experiment.InitEnvironment(func(environment *core.Environment) { + // Create 2 food piles + for x := 100; x < 110; x++ { + for y := 100; y < 110; y++ { + environment.PutValue(x, y) + } + } + for x := 200; x < 210; x++ { + for y := 200; y < 210; y++ { + environment.PutValue(x, y) + } + } + }) + experiment.InitTurtles(func() core.Actor { + sm := new(Ant) + sm.SniffDistance = *sniffDistance + sm.DropSize = *dropSize + return sm + }) + experiment.InitPheromone("food", color.RGBA{0x81, 0x81, 0x12, 0x00}) + experiment.Run() +} diff --git a/experiments/woodchips/main.go b/experiments/woodchips/main.go new file mode 100644 index 0000000..e92c72b --- /dev/null +++ b/experiments/woodchips/main.go @@ -0,0 +1,67 @@ +package main + +import ( + "flag" + "git.openprivacy.ca/sarah/microworlds/core" + "git.openprivacy.ca/sarah/microworlds/experiments" + "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) { +} + +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 main() { + 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() +} diff --git a/graphics/graphics.go b/graphics/graphics.go index be4329d..e190f6f 100644 --- a/graphics/graphics.go +++ b/graphics/graphics.go @@ -7,16 +7,15 @@ import ( "math" "os" "strconv" - //"strconv" ) type Graphics struct { - window *sdl.Window - renderer *sdl.Renderer + window *sdl.Window + renderer *sdl.Renderer width, height, pxsize int32 - t int - colorMap map[string][4]uint8 + t int + colorMap map[string][4]uint8 } func NewGraphics(width, height, pxsize int32) *Graphics { @@ -25,7 +24,7 @@ func NewGraphics(width, height, pxsize int32) *Graphics { graphics.height = height graphics.pxsize = pxsize window, err := sdl.CreateWindow("Microworlds", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, - width * pxsize, height * pxsize, sdl.WINDOW_SHOWN) + width*pxsize, height*pxsize, sdl.WINDOW_SHOWN) if err != nil { panic(err) } @@ -65,20 +64,20 @@ func (g *Graphics) Render(env *core.Environment, turtles []*core.Turtle) { amount := math.Min(float64(env.Sniff(name, x, y)), 255) if amount > 2 { - amount = 2 + amount = 2 } if amount > 0 { - scaledamountRed := uint8(float64(color[0]) * (amount/2)) - scaledamountGreen := uint8(float64(color[1]) * (amount/2)) - scaledamountBlue := uint8(float64(color[2]) * (amount/2)) + scaledamountRed := uint8(float64(color[0]) * (amount / 2)) + scaledamountGreen := uint8(float64(color[1]) * (amount / 2)) + scaledamountBlue := uint8(float64(color[2]) * (amount / 2)) scaledamountRedTotal += int(scaledamountRed) scaledamountGreenTotal += int(scaledamountGreen) scaledamountBlueTotal += int(scaledamountBlue) } } - g.renderer.SetDrawColor(uint8(scaledamountRedTotal/len(g.colorMap)),uint8(scaledamountGreenTotal/len(g.colorMap)),uint8(scaledamountBlueTotal/len(g.colorMap)), uint8(0xF0)) + g.renderer.SetDrawColor(uint8(scaledamountRedTotal/len(g.colorMap)), uint8(scaledamountGreenTotal/len(g.colorMap)), uint8(scaledamountBlueTotal/len(g.colorMap)), uint8(0xF0)) g.DrawTileColor(int32(x), int32(y)) if env.HasValue(x, y) { diff --git a/main.go b/main.go deleted file mode 100644 index c41c335..0000000 --- a/main.go +++ /dev/null @@ -1,176 +0,0 @@ -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") -var byzantineTurtles = flag.Int("byzantineTurtles", 50,"in consensus simlulations, the number of turtles who will always vote 2") -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.") - -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}) - case "maze": - for i := 0; i < *numTurtles; i++ { - turtles[i] = core.NewTurtle(env, &actors.MazeGeneration{SniffDistance: 5}) - } - env.InitPheromone("trail") - g.ColorPheromone("trail", [4]uint8{0x81, 0, 0x81, 0x00}) - case "slush": - for i := 0; i < *numTurtles; i++ { - turtles[i] = core.NewTurtle(env, &actors.Slush{Probability:float32(*prob)}) - } - env.InitPheromone("1") - env.InitPheromone("2") - g.ColorPheromone("1", [4]uint8{0x80, 0xFF, 0x00, 0x00}) - g.ColorPheromone("2", [4]uint8{0xFF, 0, 0xFF, 0x00}) - case "snowball": - for i := 0; i < *numTurtles; i++ { - turtles[i] = core.NewTurtle(env, &actors.Snowball{Probability:float32(*prob)}) - } - env.InitPheromone("1") - env.InitPheromone("2") - g.ColorPheromone("1", [4]uint8{0x00, 0xFF, 0x80, 0x00}) - g.ColorPheromone("2", [4]uint8{0xFF, 0x80, 0x00, 0x00}) - case "snowball-byzantine": - honestTurtles := (*numTurtles)-(*byzantineTurtles) - for i := 0; i < honestTurtles; i++ { - turtles[i] = core.NewTurtle(env, &actors.Snowball{Probability:float32(*prob)}) - } - for i := honestTurtles; i < honestTurtles+(*byzantineTurtles); i++ { - turtles[i] = core.NewTurtle(env, &actors.Snowball{Probability:float32(*prob), Byztantine:true}) - } - env.InitPheromone("1") - env.InitPheromone("2") - g.ColorPheromone("1", [4]uint8{0x00, 0xFF, 0x80, 0x00}) - g.ColorPheromone("2", [4]uint8{0xFF, 0x00, 0xa5, 0x00}) - case "isolate": - honestTurtles := (*numTurtles)-(*byzantineTurtles) - for i := 0; i < honestTurtles; i++ { - turtles[i] = core.NewTurtle(env, &actors.Isolate{Probability:float32(*prob)}) - } - for i := honestTurtles; i < honestTurtles+(*byzantineTurtles); i++ { - turtles[i] = core.NewTurtle(env, &actors.Isolate{Probability:float32(*prob), Byztantine:true}) - } - env.InitPheromone("1") - env.InitPheromone("2") - g.ColorPheromone("1", [4]uint8{0x00, 0xFF, 0x80, 0x00}) - g.ColorPheromone("2", [4]uint8{0xFF, 0x00, 0xa5, 0x00}) - case "flocking": - for i := 0; i < *numTurtles; i++ { - turtles[i] = core.NewTurtle(env, &actors.Flocking{SniffDistance: 1}) - } - env.InitPheromone("trail") - env.InitPheromone("avoid") - g.ColorPheromone("trail", [4]uint8{0x81, 0, 0x81, 0x00}) - g.ColorPheromone("avoid", [4]uint8{0xd1, 0, 0xff, 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() -}