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 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.
|