Hunters
Implementation Details


Site maintained by: Andrew Schlei
Last updated: 22 June 2003

Table of Contents:

Agent-Based Computational Economics (ACE) Website
ACE/CAS Interactive Computer Demos Site
Hunters Screen Shot


 
Hunter Rules [top]
The Hunter agents have rules that determine their behavior during the simulation. These rules are the same for all agents, but the outcome of following these rules depends on the agents' data. Following is a description of the rules that govern how the agents act during the simulation.

Movement:
The movement rule determines how agents move around in their two-dimensional world. The rule is as follows:
  • Look in each of the four principal directions as far as vision and world boundaries allow, and record a total score for each path by adding together the scores for each grid square along that path. The following table is used to determine the score for an individual grid square:

    Cell Contains Agent is Attacking Agent is Sharing Agent is Hoarding
    Other Agent 4 4 0
    Food 5 5 5
    Nothing 0 0 0

  • If one direction had a higher score than all the others, then attempt to move in that direction, otherwise choose a random direction to move in, which includes staying in the same square.
  • If it is possible to move in the chosen direction (the first space in that direction is empty), then move in that direction. Otherwise continue choosing random directions until a safe direction is found (staying still is always safe, so a safe direction will always be found).
Food Gathering:
The food gathering rule determines how agents collect food. The rule is as follows:
  • Look one square in each of the four principal directions.
  • If there is food in a square, gather it.
Interaction:
The interaction rule determines how agents find others to interact with and what actions they choose. The interaction rule also determines the outcome of the interaction, including strength adjustments. The rule is as follows:
  • Look one square in each of the four principal directions.
  • If another hunter is found, interact with it.
  • Choose the action with the highest associated strength. The other agent will also choose an action based on it's own strengths.
  • If either hunter chooses to attack, a battle will be fought. The agent with the higher power wins the battle. If they have equal power, a winner is determined randomly. The winner of the battle steals half of the loser's food. Any agent that attacks loses food equal to the material cost of attacking.
  • If both agents choose to share, they each take half of their food and pool it together. Each agent then takes half of the food pool. If the amount of food does not divide evenly in half, one of the agents is chosen randomly to receive the extra food.
  • Adjust action strengths according to the following table:
    Hunter 1 Hunter 2 Adjust A1 Adjust S1 Adjust H1 Adjust A2 Adjust S2 Adjust H2
    Attacked Attacked + difference 0 0 + difference 0 0
    Attacked Shared + difference 0 0 +/- 1 0 0
    Attacked Hoarded + difference 0 0 +/- 1 0 + difference
    Shared Shared 0 + difference 0 0 + difference 0
    Shared Hoarded 0 0 0 0 0 0
    Hoarded Hoarded 0 0 0 0 0 0
    Hunter 1 and Hunter 2 are two Hunter agents that are interacting. Which hunter is number 1 and which is number 2 is not important. The adjust columns refer to the strengths to be adjusted. Adjust A1 is the adjustment to Hunter 1's attack strength, Adjust S2 is the adjustment to Hunter 2's share strength, and so on. An entry of "0" means that no adjustment takes place. An entry of "+ difference" means to adjust the hunter's strength by the difference between the hunter's current food supply and its food supply before the interaction (note that this can be negative), and then add the utility offset for the action the hunter performed. An entry of "+/- 1" means to increment the strength by one if the agent won the battle, or decrement it by one if the agent lost the battle.
  • Adjust interaction arrays to reflect interactions that occurred.
  • Remove any ties for the highest action strength by randomly incrementing one of the strengths tied for highest.

Evolution:
The evolution rule determines how dead hunters are replaced with new hunters. The rule is as follows:

  • Gather a list of all of the agents that survived the current generation.
  • Scan through the entire list of agents, looking for dead ones.
  • For every dead agent found, replace it by choosing two "parents" at random from the list of living agents (it is possible for a single agent to act as both parents). Change the dead agent's data so that its power and action strengths are now the average of those of its parents. For example, consider that the first chosen parent has a power of 20, an attack strength of 10, a share strength of 2, and a hoard strength of 0, while the other parent has a power of 10, an attack strength of 0, a share strength of 4, and a hoard strength of 0. The dead agent's data would be changed as follows: power would be set to 15, attack strength would be set to 5, share strength would be set to 3, and hoard strength would be set to 0.



The Hunter Class [top]
The Hunter class defines the agents used in this simulation. This class contains variables, methods, and non-member functions. The class serves as a container for agent data, and contains the implementation for agent functions.

Private Variables:

  • int xPos The hunter's x position, or horizontal position, increasing from left to right.
  • int yPos The hunter's y position, or vertical position, increasing from top to bottom.
  • int power The hunter's power. This is used to describe how strong an agent is, in terms of its ability to win a fight. Whenever two hunters do battle, their power is compared to determine the winner. Hunters with a higher power are considered stronger.
  • int hID The hunter's ID number. This corresponds directly to its position in the array used to store the agents. Every agent must have their own, unique ID number.
  • int foodCount The amount of food the hunter has. There is no limit to the amount of food that any hunter can carry with him.
  • int costAttack The cost, in food, of attacking. Whenever an agent attacks another agent, it must consume this additional amount of food
  • int vision The range of the hunter's vision. When a hunter is deciding which way to move, it looks as far as its vision allows in each of the four principal directions (north, east, south, and west). The hunter can only see in these four directions, and not diagonally.
  • int metabolism The amount of food the hunter must consume each round in order to survive.
  • bool alive The hunter's status as living or dead. True if the hunter is alive, false if it is dead. Hunters die when they have no food left to consume at the end of a round. It is possible for a hunter to drop below zero food and still survive, as long as it gets more food before the round ends. Once a hunter dies, it stays dead for the remainder of the current generation. An agent that is dead at the end of a generation will be replaced by the offspring of more successful hunters.
  • bool* interactedWith This array keeps track of which other agents an agent has already interacted with in a given round. Any pair of agents is only allowed one interaction per round. Each hunter has his own interaction array, but all of the arrays correspond to one another. Thus, if two hunters have not yet interacted with each other in a given round, both hunters will agree that they have not interacted. After they interact for that round, both agents will agree that they have interacted.
  • Action utility offsets: After two agents interact, their action strengths are adjusted. The amount of adjustment is determined by the actions each agent performed, and how much food each agent lost or gained. However, the loss or gain of food is offset by action utility variables. These action utility offsets can be used to encourage or discourage certain agent behaviors.
    • int utilityAttack Attack utility offset
    • int utilityShare Share utility offset
    • int utilityHoard Hoard utility offset
  • Action Strengths: When an agent interacts with another agent, it has the choice of attacking, sharing, or hoarding. The action it chooses depends on which action has the highest associated strength. In general, when an action is beneficial to an agent, the associated strength for that action increases. When an action is detrimental to an agent, the associated strength for that action decreases. Each agent has his own data for attack, share, and hoard strengths, and no two strengths can be tied for the highest.
    • int strengthAttack Attack strength
    • int strengthShare Share strength
    • int strengthHoard Hoard strength

Methods:

  • void setPos(int x, int y)
    This method sets the x and y positions
    pre: x and y are coordinates in the 2-D world, with x increasing from left to right and y increasing from top to bottom
    post: xPos and yPos have changed to reflect the agent's new position
  • void setPower(int pow)
    inline
    This method sets the agents's power
    pre: pow is the number to set the agent's power to
    post: power has been set to pow
  • void setFoodCount(int fc)
    inline
    This method sets how much food an agent has
    pre: fc is the amount of food the agent is to possess
    post: foodCount has been set to fc
  • void setID(int idNum)
    inline
    This method sets the agent's id number
    pre: idNum is the agent's new id number
    post: hID has been set to idNum
  • void setAlive(bool a)
    inline
    This method sets the agent's alive status
    pre: a is the agent's new status (true = alive, false = dead)
    post: alive has been set to a
  • void setStrengthAttack(int str)
    inline
    This method is used to set the agent's strength associated with attacking
    pre: str is the new strength to be assigned to attacking
    post: strengthAttack has been set to str
  • void setStrengthShare(int str)
    inline
    This method is used to set the agent's strength associated with sharing
    pre: str is the new strength to be assigned to sharing
    post: strengthShare has been set to str
  • void setStrengthHoard(int str)
    inline
    This method is used to set the agent's strength associated with hoarding
    pre: str is the new strength to be assigned to hoarding
    post: strengthHoard has been set to str
  • void setCostAttack(int cost)
    inline
    This method sets the agent's material cost for attacking
    pre: cost is the amount of food used up when attacking
    post: costAttack has been set to cost
  • void setUtilityAttack(int util)
    inline
    This method set the agent's utility offset for attacking
    pre: util is the additional amount to adjust strength by when attacking
    post: utilityAttack has been set to util
  • void setUtilityShare(int util)
    inline
    This method set the agent's utility offset for sharing
    pre: util is the additional amount to adjust strength by when sharing
    post: utilityShare has been set to util
  • void setUtilityHoard(int util)
    inline
    This method set the agent's utility offset for hoarding
    pre: util is the additional amount to adjust strength by when hoarding
    post: utilityHoard has been set to util
  • void setVision(int vis)
    inline
    This method is used to set the agent's vision range
    pre: vis is the desired vision range
    post: vision has been set to vis
  • void setMetabolism(int met)
    inline
    This method is used to set the agent's metabolism
    pre: met is the desired metabolism
    post: metabolism has been set to met
  • void createInteract(int numHunters)
    This method is used to create the interactedWith array
    pre: numHunters is the number of hunter agents in the simulation
    post: the agent's interactedWith array has been allocated
  • void initInteract(int numHunters)
    This method initializes the hunters interactedWith array
    pre: numHunters is the number of hunter agents in the simulation
    post: the agent's interactedWith array has been initialized to false
  • void setInteracted(int i)
    inline
    This method is used to adjust the agent's interactedWith array to show that the agent has interacted with another hunter agent
    pre: i is the id number of the agent that was interacted with
    post: interactedWith[i] has been set to true, showing that the agent has interacted with agent i
  • void move(int* worldMatrix, int WSX, int WSY, int EMPTY, int FOOD)
    This method determines how the agents move
    pre: worldMatrix is a pointer to a 1 dimensional array that represents the 2 dimensional world the hunter agents live in.
    WSX is the world size in the x dimension (in cells).
    WSY is the world size in the y dimension (in cells).
    EMPTY is the number denoting an empty cell in worldMatrix.
    FOOD is the number denoting food in worldMatrix
    post: worldMatrix has been modified to reflect the new positions of the hunter agents. The agent's xPos and yPos coordinates have also been altered to reflect the agent's new position.
  • int getScore(int* worldMatrix, int WSX, int EMPTY, int FOOD, int cellX, int cellY)
    This method is used to find the score for a given cell, which agents use to determine how to move
    pre: worldMatrix is a pointer to a 1 dimensional array that represents the 2 dimensional world the hunter agents live in.
    WSX is the world size in the x dimension (in cells).
    EMPTY is the number denoting an empty cell in worldMatrix.
    FOOD is the number denoting food in worldMatrix.
    cellX is the x coordinate of the cell to be examined.
    cellY is the y coordinate of the cell to be examined
    post: returns score for given cell
  • void gather(int* worldMatrix, int WSX, int WSY, int EMPTY, int FOOD,int FOOD_VALUE)
    this method is used by the agents to gather food
    pre: worldMatrix is a pointer to a 1 dimensional array that represents the 2 dimensional world the hunter agents live in
    WSX is the world size in the x dimension (in cells)
    WSY is the world size in the y dimension (in cells)
    EMPTY is the number denoting an empty cell in worldMatrix
    FOOD is the nubmer denoting a cell containing food in worldMatrix
    FOOD_VALUE is the amount of food gained from collecting from a food cell
    post: The agent's foodCount has been adjusted to reflect any food gathered. worldMatrix has been modified to remove any food cells that were gathered (by setting them to EMPTY).
  • void removeTies()
    This method is used to remove any ties for the highest strength. If any strengths are tied for highest, it randomly selects one to increment by one.
    pre: none
    post: the agent's action strengths have been adjusted to remove any ties
  • int getPower()
    inline
    pre: none
    post: returns the agent's power
  • int getFoodCount()
    inline
    pre: none
    post: returns the agent's foodCount
  • int getStrengthAttack()
    inline
    pre: none
    post: returns the agent's strengthAttack
  • int getStrengthShare()
    inline
    pre: none
    post: returns the agent's strengthShare
  • int getStrengthHoard()
    inline
    pre: none
    post: returns the agent's strengthHoard
  • int getY()
    inline
    pre: none
    post: returns the agent's yPos
  • int getX()
    inline
    pre: none
    post: returns the agent's xPos
  • int getCostAttack()
    inline
    pre: none
    post: returns the agent's costAttack
  • int getUtilityAttack()
    inline
    pre: none
    post: returns the agent's utilityAttack
  • int getUtilityShare()
    inline
    pre: none
    post: returns the agent's utilityShare
  • int getUtilityHoard()
    inline
    pre: none
    post: returns the agent's utilityHoard
  • int getVision()
    inline
    pre: none
    post: returns the agent's vision range
  • int getMetabolism()
    inline
    pre: none
    post: returns the agent's metabolism
  • bool isAlive()
    inline
    pre: none
    post: returns the agent's alive status
  • bool interacted(int i)
    inline
    pre: i is a hunter id number
    post: returns true if the agent has interacted with agent i
  • bool isAttacking()
    This method is used to determine if the agent is currently in "attack mode"
    pre: none
    post: returns true if the the agent's strengthAttack is its highest strength
  • bool isSharing()
    This method is used to determine if the agent is currently in "share mode"
    pre: none
    post: returns true if the the agent's strengthShare is its highest strength
  • bool isHoarding()
    This method is used to determine if the agent is currently in "hoard mode"
    pre: none
    post: returns true if the the agent's strengthHoard is its highest strength

Non-Member Functions:

  • void hunterInteraction(int* world,int WSY,int WSX,Hunter* hunters, int i, ofstream &log)
    This function is used by hunter i to search for nearby hunters it can interact with. When it finds a hunter it has not yet interacted with, hunterInteractionResolver is called.
    pre: worldMatrix is a pointer to a 1 dimensional array that represents the 2 dimensional world the hunter agents live in
    WSX is the world size in the x dimension (in cells)
    WSY is the world size in the y dimension (in cells)
    hunters is a pointer to the array of hunter agents
    i is the id number of the agent currently acting
    log is an open output file stream
    post: agent i will have interacted with any agents nearby if it hasn't already
  • void hunterInteractionResolver(Hunter* hunters, int i, int target, ofstream &log)
    This function is used to resolve interactions between hunters
    pre: hunters is a pointer to the array of hunter agents
    i is the id number of the agent currently acting
    targetID is the id number of the agent being interacted with
    logOutput is an open file output stream
    post: An action between two agents has been resolved, including adjustments to action strengths, foodCounts, and the interactedWith arrays.
  • void hunterEvolution(Hunter* hunters, int NUM_HUNTERS, int numAlive)
    This function handles the evolution of the agents. First, the id numbers of all surviving agents are gathered. Then each dead agent is replaced with a new agent. The new agent is created by first choosing two "parents" from among the living agents and then averaging their power, stengthAttack, stengthShare, and strengthHoard member variables. It is possible for a single agent to be both "parents"
    pre: hunters is a pointer to the array of hunter agents
    NUM_HUNTERS is the total number of hunters in the simulation
    numAlive is the number of agents currently "alive"
    post: all dead hunter agents have been replaced with new agents, although they are still dead.


Feedback [top]
You may contact me at aschlei@hotmail.com. I would greatly appreciate your comments and suggestions.

Copyright 2003 Andrew Schlei. All Rights Reserved.