# extending-agents

    library(villager)
    library(leaflet)

# Extending Agents

To create agents (agents) that have more properties than the ones provided by villager, subclass the `agent` class into a new R6 class. Once sub-classed, additional properties can be added to the agent which can be used in the subsequent model. The new agent class can be tied to individual villages. This gives flexibility to model populations differently when running under the same simulation.

To add new members to the agent class,

1. Copy the agent class source code
2. Create the new member variable
3. Add it as a parameter to the `initialize` function
4. Make an entry for it in the `as_table` function

## Agent with a GPS coordinate

To give a complete example of the sublclassing process, consider an extended agent. In this case the agent has an additional property, `gps_coordinates`, that’s a named list of latitude and longitude coordinates: [lat=1234, long=1234]. Each coordinate gets updated by the model each day by a random number.

To start the base class off, the original class was copied to save time with the member variable definitions.

### Custom agent class

    gps_agent <- R6::R6Class("agent",
      inherit = villager::agent,
      public = list(
        age = NULL,
        alive = NULL,
        children = NULL,
        father_id = NULL,
        first_name = NULL,
        gender = NULL,
        health = NULL,
        identifier = NULL,
        last_name = NULL,
        mother_id = NULL,
        partner = NULL,
        profession = NULL,
        latitude = NULL,
        longitude = NULL,

        initialize = function(identifier = NA,
                              first_name = NA,
                              last_name = NA,
                              age = 0,
                              mother_id = NA,
                              father_id = NA,
                              partner = NA,
                              children = vector(mode = "character"),
                              gender = NA,
                              profession = NA,
                              alive = TRUE,
                              health = 100,
                              latitude = 0,
                              longitude = 0) {
        super$initialize(identifier,
                         first_name,
                         last_name,
                         age,
                         mother_id,
                         father_id,
                         partner,
                         children,
                         gender,
                         profession,
                         alive,
                         health)
          self$latitude <- latitude
          self$longitude <- longitude
        },

        as_table = function() {
          agent_table <- data.frame(
            age = self$age,
            alive = self$alive,
            father_id = self$father_id,
            first_name = self$first_name,
            gender = self$gender,
            health = self$health,
            identifier = self$identifier,
            last_name = self$last_name,
            mother_id = self$mother_id,
            partner = self$partner,
            profession = self$profession,
            latitude = self$latitude,
            longitude = self$longitude
          )
          return(agent_table)
        }
      )
    )

### Initial Condition

We’ll create the initial population of one Agent in the `initial_condition` function, which gets run before the model starts. The initial starting location is in Los Angeles, Ca. Note that the new `gps_agent` class is used to instantiate the agent rather than the library provided `agent` class.

    initial_condition <- function(current_state, model_data, agent_mgr, resource_mgr) {
      # Create the initial villagers
      test_agent <- gps_agent$new(first_name="Lewis", last_name="Taylor", age=9125, latitude=33.8785486, longitude=-118.0434921)
      agent_mgr$add_agent(test_agent)
    }

### Model

Each day, the model picks a number between 0.0000001 and 0.0000003 and increments `gps_coordinate` on the agent.

    test_model <- function(current_state, previous_state, model_data, agent_mgr, resource_mgr) {
      # Loop over all the agents (just one at the moment)
      for (agent in agent_mgr$get_living_agents()) {
        # Generate new coordinates
        latitude <- agent$latitude + runif(1, 0.01, 0.03)
        longitude <- agent$longitude + runif(1, 0.01, 0.03)
        agent$latitude <- latitude
        agent$longitude <- longitude
      }
    }

### Running

Finally, we’ll create and run a simulation with a duration of 10 days.

    los_angeles <- village$new("Test_Village", initial_condition, test_model, gps_agent)
    simulator <- simulation$new(10, list(los_angeles))
    simulator$run_model()

### Results

    # Load in data
    agent_data <- readr::read_csv("results/Test_Village/agents.csv")
    #> Rows: 10 Columns: 14
    #> ── Column specification ────────────────────────────────────────────────────────
    #> Delimiter: ","
    #> chr (3): first_name, identifier, last_name
    #> dbl (5): age, health, latitude, longitude, step
    #> lgl (6): alive, father_id, gender, mother_id, partner, profession
    #>
    #> ℹ Use `spec()` to retrieve the full column specification for this data.
    #> ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

    # Grab just the location data
    agent_location <- data.frame(latitude = agent_data$latitude, longitude = agent_data$longitude)

    # create a map
    leaflet::leaflet() %>%
      leaflet::addTiles() %>%  # Add default OpenStreetMap map tiles
      leaflet::addMarkers (data = agent_location) # Add agent locations