Example #1
0
func printLoop(ch <-chan []grid2d.Update, g grid2d.Grid, cns *census.DirCensus, cond *sync.Cond, numUpdates *int64, clearScreen bool) {
	// Try to keep rendering smooth.
	runtime.LockOSThread()

	for _ = range ch {
		if clearScreen {
			// TODO(dnesting): use termcap/terminfo to do this more portably.
			fmt.Print("")
		}
		term.PrintWorld(os.Stdout, g)
		fmt.Println()
		if clearScreen {
			fmt.Print("")
		}

		// Write some summary stats after the rendering.
		fmt.Printf("%d updates\n", atomic.LoadInt64(numUpdates))
		fmt.Printf("%d/%d orgs (%d/%d species, %d recorded)\n", cns.Count(), cns.CountAllTime(), cns.Distinct(), cns.DistinctAllTime(), cns.NumRecorded())
		if loc := g.Get(0, 0); loc != nil {
			fmt.Printf("random: %v\n", loc.Value())
		}

		// If we're running with --sync, signal to any goroutines waiting on a rendering that
		// it's OK for them to continue again.
		if cond != nil {
			cond.Broadcast()
		}
	}
}
Example #2
0
func startUpdateTracker(g grid2d.Grid, numUpdates *int64) {
	ch := make(chan []grid2d.Update, 0)
	go func() {
		for updates := range ch {
			atomic.AddInt64(numUpdates, int64(len(updates)))
		}
	}()
	g.Subscribe(ch)
}
Example #3
0
// StartAll finds all organisms driven by Cpu instances, and spawns a goroutine
// to begin executing each Cpu instance found.
func StartAll(g grid2d.Grid) {
	var locs []grid2d.Point
	g.Locations(&locs)
	for _, p := range locs {
		if o, ok := p.V.(*org.Organism); ok {
			if c, ok := o.Driver.(*Cpu); ok {
				go c.Run(o)
			}
		}
	}
}
Example #4
0
// Count counts the number of occupants in g that satisfy fn.
func Count(g grid2d.Grid, fn CounterFunc) int {
	var locs []grid2d.Point
	g.Locations(&locs)

	var count int
	for _, p := range locs {
		if fn(p.V) {
			count += 1
		}
	}
	return count
}
Example #5
0
func startOrg(g grid2d.Grid) {
	c := cpu1.Random()
	o := org.Random()
	o.Driver = c
	o.AddEnergy(initialEnergy)
	for {
		// PutRandomly might fail if there's no room, so just keep trying.
		if _, loc := g.PutRandomly(o, org.PutWhenFood); loc != nil {
			go c.Run(o)
			break
		}
	}
}
Example #6
0
func startAndMaintainOrgs(g grid2d.Grid) {
	// Obtain an initial count before we start anything executing.
	mCount := maintain.Count(g, isOrg)

	ch := make(chan []grid2d.Update, 0)
	g.Subscribe(ch)

	// Start all organisms currently existing in the Grid.  We do this *after*
	// subscribing ch so that we don't end up with a wrong count if any organisms
	// divide or die.
	cpu1.StartAll(g)

	go maintain.Maintain(ch, isOrg, func() { startOrg(g) }, minOrgs, mCount)
}
Example #7
0
// PrintWorld renders g to w.
func PrintWorld(w io.Writer, g grid2d.Grid) {
	points := locPool.Get().([]grid2d.Point)
	width, height, _ := g.Locations(&points)
	sort.Sort(byCoordinate(points))

	iy, ix := 0, -1
	addHeader(w, width)

	for _, p := range points {
		fillBefore(w, p.X, p.Y, width, &ix, &iy)
		writeRune(w, RuneForOccupant(p.V))
		ix += 1
	}
	locPool.Put(points)
	fillBefore(w, width, height-1, width, &ix, &iy)
	writeRune(w, rightRune)
	writeRune(w, '\n')
	addFooter(w, width)
}
Example #8
0
func startPrintLoop(g grid2d.Grid, cns *census.DirCensus, cond *sync.Cond, numUpdates *int64, clearScreen bool) {
	// We want to use chanbuf.Tick to ensure renders occur at specific intervals regardless
	// of the rate at which updates arrive.  To prevent the notification channel from backing up
	// and causing deadlock, we buffer using a chanbuf.Trigger (since we don't care about the
	// update messages themselves).  We could have used a time.Tick instead, but we'd need to
	// do something special to ensure this loop exits when the notifications stop.

	// grid notifier -> updateCh -> trigger -> tick -> print world
	//   grid notifier first dispatches an update the moment it occurs
	//   trigger consumes the event and flags that an update occurred
	//   tick fires every freq, halting when trigger reports it's closed
	//   printLoop renders the grid every time tick fires

	updateCh := make(chan []grid2d.Update, 0)
	trigger := chanbuf.Trigger()
	freq := time.Duration(1000000.0/printRate) * time.Microsecond
	go chanbuf.Feed(trigger, grid2d.NotifyToInterface(updateCh))
	tickCh := chanbuf.Tick(trigger, freq, true)
	g.Subscribe(updateCh)

	go printLoop(grid2d.NotifyFromInterface(tickCh), g, cns, cond, numUpdates, clearScreen)
}
Example #9
0
func startCensus(g grid2d.Grid) *census.DirCensus {
	// Create a new Census that writes to /tmp/census when a population grows to 40.
	cns, err := census.NewDirCensus("/tmp/census", func(p census.Population) bool { return p.Count > 40 })
	if err != nil {
		fmt.Printf("Error creating census: %v\n", err)
		os.Exit(1)
	}

	// Use human times.
	timeNow := func(interface{}) interface{} { return time.Now() }

	ch := make(chan []grid2d.Update, 0)
	g.Subscribe(ch)

	// Populate the Census with what's already in the world (perhaps restored from an autosave).
	// Assumes nothing in the world is changing yet.
	grid2d.ScanForCensus(cns, g, timeNow, orgHash)

	// Start monitoring for changes
	go grid2d.WatchForCensus(cns, ch, timeNow, orgHash)

	return cns
}