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 OnStep func(*core.Environment, []*core.Turtle, 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, 0) e.graphics = graphics.NewGraphics(int32(*width), int32(*height), int32(*pxsize)) } func (e *Experiment) GetNumTurtles() int { return (*numTurtles) } func (e *Experiment) InitPheromone(name string, col color.Color) { e.env.InitPheromone(name) r, g, b, a := col.RGBA() e.graphics.ColorPheromone(name, [4]uint8{uint8(r), uint8(g), uint8(b), uint8(a)}) } func (e *Experiment) InitEnvironment(f func(environment *core.Environment)) { f(e.env) } func (e *Experiment) InitNTurtles(f func() core.Actor, num int) { numSuccess := 0 for i := e.initializedTurtles; i < e.initializedTurtles+num; i++ { t := core.NewTurtle(e.env, f()) if t != nil { e.turtles = append(e.turtles, t) numSuccess++ } } e.initializedTurtles += numSuccess } func (e *Experiment) InitTurtles(f func() core.Actor) { e.InitNTurtles(f, (*numTurtles)) } func (e *Experiment) Run() { wait := sync.WaitGroup{} running := true wait.Add(1) go func() { step := 0 for running { e.graphics.Render(e.env, e.turtles) e.OnStep(e.env, e.turtles, step) newTurtles := make([]*core.Turtle, 0) deleted := 0 for _, t := range e.turtles { if t.GetAttribute("status") != "dead" { newTurtles = append(newTurtles, t) } else { e.env.Leave(t.Pos()) // Dead turtles occupy no space deleted++ } } e.turtles = newTurtles step++ } wait.Done() }() 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() }