Flocc

Agent-based modeling in JavaScript in the browser or on the server. [v0.5.19]

Environment

Overview

The base flocc.Environment class (from here on, just Environment) stores agents and runs the simulation over time.

An empty environment can be instantiated by calling: const environment = new Environment();

Options

When instantiating an Environment, you can pass a number of configuration options.

torus

The torus option specifies whether 2-dimensional spatial environments should wrap or not. If torus is set to true, then an agent whose x value is set to the environment’s width + 1 will wrap around and reappear at 1. This pattern is very common, see for example the Flocking model.

torus defaults to true; you have to set it to false to override this behavior.

width/height

Passing numbers for width and height will set the dimensions of the environment. This is most useful for toroidal environments where agents should reappear at the opposite side when they go out of bounds.

Properties

.time

When an environment is instantiated, the time property is set to 0. Then, with each ticktime is incremented by 1.

environment.time; // = 0
environment.tick();
environment.time; // now 1
environment.tick();
environment.tick();
environment.time; // now 3

Methods

Environments are actually an extension of Agents, so they inherit all the methods that Agents have, such as .set.get.getData.increment, and .decrement. Setting data on the Environment can be a handy way of setting global-ish variables that all Agents can access.

.addAgent(agent)

Add an agent to the environment. Since most of the time you will want to add many agents to an environment, doing it within a for loop is most useful:

for (let i = 0; i < 100; i++) {
  environment.addAgent(new Agent());
}

.removeAgent(agent)

Remove a previously referenced agent from the environment.

const agent = new Agent();
environment.addAgent(agent);
// the environment now has 101 agents
environment.removeAgent(agent);
// the environment now has 100 agents

.getAgents()

Returns a JavaScript array of all the agents in the environment, in the order they were added.

.tick(n = 1 | opts)

When .tick is called, each agent’s rule function(s) is/are invoked. If an agent has multiple rule functions, they are all run before moving on to the next agent. After all agents’ rule functions have been invoked, any enqueued functions are run.

environment.tick(); // ticks once

An environment may tick more than once (i.e. loop through all agents and execute rules multiple times) by passing a number greater than 1.

environment.tick(10); // ticks 10 times

.tick may also be called with a configuration object that can have keys count (number, the same as if passing a number as the parameter), and randomizeOrder (a boolean). If randomizeOrder is set to true, then the environment will loop over agents in a (pseudo-) random order, instead of the order they were added to the environment. Any enqueued rules will also be executed in a random order. If the environment uses a Terrain, then all of the terrain’s cells will also be looped over in a random order.

environment.tick({
  count: 20,
  randomizeOrder: true
}); // ticks 20 times in a randomized order

.use(helper)

Pass an instance of an environment helper to provide more structure and functionality for the environment and the agents. The two current Environment helpers are the Network and KDTree.

.stat(key)

Returns an array of data associated with agent.get(key) across all agents in the environment. This is a shorthand for calling environment.getAgents().map(a => a.get(key)). It defaults to caching the result and using it for future calls within the same environment tick. However, this behavior can be turned off (for example, if agents are updating synchronously and the data should reflect this) by passing false as a second parameter: environment.stat('synchronousKey', false)

.memo(fn)

Calling environment.memo(function() { return 'someExpensiveValue' }) will return 'someExpensiveValue' and then cache and use that result for future calls within the same environment tick. The function that is passed as the only parameter is called only the first time .memo is used within an environment tick, and then its return value is used for future calls, until the next environment tick.