# Create Agents

`Agents` is a set of autonomous entities moving around and interacting with the environment during the simulation. Unlike `Places`, it is not a grid, but a big array of instances where some of them are "alive" while the others are "dead" (i.e.: still present in memory but will not participate in simulation). It is optional for a simulation and should always be associated with a `Places` instance. Each individual entity, called an `Agent` instance, should always reside on a `Place` instance. 


## Define Custom `Agent` Class

Similar to `Places`, before instantiating an instance of `Agents`, we need to first define the behavior of each `Agent` instance in the simulation by defining a class inheriting from `mass::Agent`, which requires implementing the following methods: 

* The constructor. It always takes in a `mass::Index` representing the flattened local index of this instance in the block, which should be passed to the base class constructor. Usually the body of the constructor should be empty since all the attributes are not created at this time. It should be decorated with `__universal__`.

* The `callMethod`. This method is called when the `callAll` method is invoked to the `Places` instance. It is responsible for dispatching method invocation requests to the actual member method based on the given `mass::FunctionId` and the arguments as `void*`. Typical implementation of this method is using a big `switch` statement on the `FunctionId`. It should be decorated with `__device__`.

For better identifying the custom methods and dispatch invocation requests in `callMethod`, it is recommended to use an enum as their identifier (the `FunctionId`).

```cpp
#include <mass/Agent.h>

class MyAgent final : public mass::Agent {
public:
    __universal__ explicit MyAgent(const mass::Index localIndex) : mass::Agent(localIndex) {}

    enum Function {
        FUNC1, FUNC2
    };

    __device__ void callMethod(const mass::FunctionId functionId, void*const args) {
        switch (functionId) {
        case FUNC1: func1(); break;
        case FUNC2: func2(*static_cast<const int*>(args)); break;
        default: break;
        }
    }

    __device__ void func1() {}
    __device__ void func2(const int arg) {}
};
```


## Instantiate `Agents` Instance

With the custom `Agent` class defined, we can create an instance of `Agents` using the defined `MyAgent` class. This is done using the `mass::makeAgents` function, which takes in the integer handle of the created `Agents` instance and a configuration instance of type `mass::AgentsConfig`.  The integer handle can be any value as long as it is unique among all `Agents` instances in the same simulation. As for the `AgentsConfig` structure, it contains the following options.

Note that since an `Agents` should always be associated with a `Places` instance, we should always create the `Places` instance first before creating an `Agents`.

### `AgentsConfig::associatedPlacesHandle`

The integer handle of the `Places` instance that this `Agents` instance will be associated with. This is a required option since an `Agents` should always be associated with a `Places` instance. Typical ways to configure this option is first using the `getHandle` method on the `Places` instance the created `Agents` will be associated to, and then pass it to `AgentsConfig::associatedPlacesHandle`.

### `AgentsConfig::initialAgentsConfig`

The configuration for the initial set of alive `Agents` instances. This can be either a single integer or a `span` of `mass::Index`. 

* If a single integer $N$ is provided, it means that there will initially be $N$ alive `Agent` instances activated, which will be assigned to the `Place` instances in a round-robin fashion. In other words, the first `Agent` instance is assigned to the `Place` instance with flatten index 0, the second `Agent` instance is assigned to the `Place` instance with flatten index 1, and so on, wrapping around when the last `Place` instance is reached. 

* If a `span` of `mass::Index` $S$ is provided, it means that there will initially be $|S|$ alive `Agent` instances activated where the $i$-th `Agent` instance will be assigned to the `Place` instance with flatten index $S[i]$. In other words, the first agent instance assigned to the `Place` instance with index $S[0]$, the second agent instance assigned to the `Place` instance with index $S[1]$, and so on. 

### `AgentsConfig::globalAgentSlotCount`

An integer value specifying the total number of slots for `Agent` instances. In other words, the maximum number of alive `Agent` instances that can be activated during the simulation. It should be larger than the number of initial alive agents configured in `AgentsConfig::initialAgentsConfig` 