GREENFIELDS
II
Anita Buragohain & Adam
Lowenstein
ABSTRACT
In this project, we simulated a field in which each
location corresponded to a habitat area which could be populated by hawks
(predator), squirrels (prey), or both. Each species has an associated birth
rate, death rate, and reproductive rate to determine the longevity of its life
in the simulation. At each time step, hawks and squirrels are moved to new
areas on the field, mindful of the distance they can relocate within. Also,
hawks hunt squirrels and, depending on their hunt (success) rate and each
squirrel’s dodge (escape) rate, a hunt leads either to a boost in the hawk’s
health and the regrettable demise of the squirrel involved or the depletion of
the hawk’s health and daring escape of the squirrel. In this project, squirrels
are unconcerned about food, just as hawks are unconcerned about becoming prey.
The agents that die are removed from the field while new ones that are born are
added to it. Varying the parameters such as birth/death rates, hunt success
rates, as well as the starting populations let us simulate a number of
scenarios helpful in understanding the role of specific factors in shaping
predator-prey relationships over time.
PROBLEM
DESCRIPTION
This project shows how, over a given time interval,
different variables associated with predator and prey scenarios impact the
relationship between the two and, more specifically, the populations of the two
species. In this case, there is a field—a 2-dimensional array of specified
dimensions—which is inhabited by hawk and squirrel agents. Each location on the
field holds a reference to a linked list that can hold all the agents
(regardless of type) at a particular location, allowing for the existence of
more than one agent at any given space. Consequently, each location can be
thought of as an area of certain size in the larger geography of the field—a
list within a list.
There are two ways in which a hawk can die. The
first is of old age, which is wholly dependent on the death rate of the hawk
species. The second is of starvation, which can be brought about by a series of
unsuccessful hunts where the hawk in question fails to kill squirrels for food.
A successful hunt yields a corresponding boost in the hawk’s health.
Similarly, there are two ways in which a squirrel
can die. The first one is analogous to that of the hawks (i.e., of old age),
operating on the same underlying principles.
The second occurs when the squirrel is killed for food (or for spite) by
a hawk. To counter a hawk’s ill intentions, squirrels have a dodge capability
that lets them escape in a hunt by a hawk in certain situations (depending on a
parameter, “dodge rate,” that is specific to squirrels). As one of our extensions, we set the dodge rate of the
squirrels as (1 – the hunt success rate of the hawks) in the interest of
consistency (the hawk hunt rate and dodge success rate should add up to 100%).
It is assumed that unlike hawks, squirrels have no health maintenance
associated with their survival. Food is ample, and they forage from trees.
Both hawks and squirrels can produce offspring.
Offspring are generated at birth rates specified for both hawks and squirrels.
Creatures that die or are killed are removed from the field at each time step,
while those that are born are added to the simulation in random locations.
At each time step, all squirrels move to new
locations in the field. Their new locations are within the maximum specified
moving distance of the old locations and are not checked for the presence of
hawks. Thus, if a hawk is found at the squirrel’s new location, a hunt ensues
and either the hawk kills the squirrel and hawk’s health is incremented, or the
squirrel escapes and the health of the hawk is depleted. If no hawk is found,
the squirrel stays at the new location and carries on with its day to day
activities.
Hawks are also moved to a random location within
their boundaries, and upon moving, each hawk inspects its current location for
a squirrel. If one is found, a hunt ensues. However, if no squirrel is found at
its present location, the hawk is moved to a random new location within its
moving distance. There is no check performed to ascertain whether the new
location does, in fact, have a squirrel. If it does have one, then a hunt once
again ensues. If there are no squirrels in that location, then the hawk’s
health is depleted. For another extension, we modified
our code to run simulations where the optimality of a move is checked for the
creature in question before it is executed. For instance, before assigning a
squirrel to a new location, a check is performed to see if there are hawks in
that vicinity. If that is the case, the search continues until a “safe” space
is found for it. In another simulation,
we checked that a squirrel is actually in the area before a hawk is moved to it.
In the final step in each
iteration, all squirrels that have died due to old age or being hunted
are removed from the field. All hawks dead as a result of either starvation
(depletion of health to zero) or old age are also removed. Any new squirrels or
hawks born to the surviving agents are added into the field.
The changes in the number of agents in the field
and their locations can be tracked after each time step by printing the terrain
representation to the terminal window.
THEORY AND
ALGORITHMS
An Entity class was used as the parent class of
classes Hawk and Squirrel, which were in turn used to create the agents that
populated the field. The superclass Entity was implemented as given in the
assignment in the course webpage. The Hawk class implemented the Predator and
Critter interfaces, both also provided, in addition to extending the class
Entity. Similarly, the Squirrel class implemented the Prey and Critter
interfaces.
The class EntityList
creates a linked list structure that can hold objects of type Entity. At the
creation of an object of type EntityList, the user is
asked to specify the maximum number of agents that can be stored in the list.
Because of our extensions to this project, where simulations can be run such
that the squirrels have an advantage (or more intelligence) in checking the
safety of a move before executing it (and likewise for hawks in another
simulation involving hawks moving only to locations where squirrels are
present), we decided to remove the maximum size constraint specified in EntityList. In a situation where one creature has such an
advantage over the other, this constraint would have caused a population to
exceed the originally-anticipated population, a problem which an object of type
EntityList with the original constraint would not
support. In anticipation of this problem, and because Entities were stored
using liked list implementation (rather than array-based implementation), we
abandoned the restriction. Removing the maximum size constraint also made the
project more realistic: in a situation where the population of hawks vastly
outnumbers that of the squirrels, for example, it is not surprising that most
of the hawks will be crowded around the few squirrels that are left.
The theory behind the
The Simulator class brought all the other classes
together. It had four primary methods: a constructor, initialize(),
iterate(), and write(). The constructor simply takes in the parameters of the
simulation (terrain size, the number of hawks, and the number of squirrels). It
then calls the initialize() method with these
variables. The write() method outputs a string
representation of the field. The figure below shows a 6 x 4 grid with 20 hawks
and 14 squirrels:

The algorithms for initialize()
and iterate() are explained below. Iterate is based primarily on iterations of
the hawk and squirrel populations, iterations which implement the iterable interface found within EntityList.
initialize():
A field,
The following loop is repeated for the number of
squirrels to be created:
1. A
random row and column location is picked from within the field dimensions.
2. A
new agent of type Squirrel is created.
3. The
squirrel’s location (in
4. The
squirrel is inserted at the end of slist.
5. The
squirrel is inserted into the appropriate EntityList
found at its location in the terrain.
An identical algorithm is used to create and
populate the EntityList of hawks, called hlist.
iterate():
The iterate() method
consists of calls to three helper functions—iterSquirrel(),
iterHawk(), and addBabies()—at
each time step. The algorithm used in each is outlined below:
iterSquirrel():
For each squirrel present in
·
Check to see if the squirrel has any offspring.
o
If so, increment the counter holding the number of
squirrel offspring (squirrels will be created later).
·
Check whether the squirrel has died of old age.
o
If it has died of old age, then remove the squirrel
from the EntityList at its location in
o
If it has not died of old age, move the squirrel to
a random location in
iterHawk():
For each hawk present in
·
Check to see if the hawk has any offspring.
o
If so, increment the counter holding the number of
hawk offspring (hawks will be created later).
·
Check whether the hawk has died of old age or starvation.
o
If it has not died of old age or starvation (health
equals 0.0):
§
Check to see if there is at least one squirrel at
the current location of the squirrel.
·
If there is one, then call helper function huntHere(),
which take the hawk in question as a parameter. huntHere() selects the
squirrel (or a squirrel if more than one hawk is found) from the hawk’s current
location, and the hawk engages in a hunt with the squirrel.
·
If the hunt is successful (Hunt()
is successful and Dodge() is unsuccessful), then replenish the hawk’s health
and remove the squirrel is removed from
·
If the hunt is unsuccessful, deplete the hawk’s
health.
§
If there is no squirrel at the current location,
them move the hawk to a randomly-selected location within the area defined by
its maxdistance parameter (as
an extension, our program allows the programmer to decide if the hawk should
keep searching for a new random location if the first one it finds does not
contain a squirrel. Because there may not always be a squirrel within the
defined area, a counter breaks the loop after a specified number of iterations).
·
When the hawk is moved to a new location that
contains a squirrel, execute a hunt (described above).
·
When the hawk if moved to a new location that does
not contain a squirrel, decrement its health appropriately using the TurnDepletion()
function.
·
Check is to see if the hawk’s health is equal to
zero or hawk has died of old age (based on its Dies()
method which eliminates certain hawks through a representation of natural selection).
o
If it is greater than zero, do nothing.
o
If it is zero, remove the hawk from both
RESULTS
There are an infinite number of possible outcomes
in a scenario like Greenfields II—there are so many
parameters that can be altered that no result can be applied uniformly (we
can’t conclude that “the hawks will always win,” for example). A small number
of hawks and a large number of squirrels will yield large populations of
squirrels (and a sustainable population of hawks). A small number of squirrels
will ultimately lead to the extinction of the squirrel population and, in turn,
the extinction of the hawk population. These basic natural principles provide a
good test for the efficacy of our program—knowing that the program correctly
predicts these two cases allows the observer to trust the results of the
program in more complex cases. The following two simulations ran under the
specified conditions:
15 hawks, 500
squirrels; 50 iterations; 20 x 40 grid:

500 hawks, 15
squirrels; 50 iterations; 20 x 40 grid:

These figures were generated directly using
Microsoft Excel. We knew that we would be analyzing
large amounts of data, so we created an extension in the main()
method that automatically exported the populations of hawks and squirrels after
every iteration of the simulation to an Excel spreadsheet. Then, we created a
macro in Excel that formats the data and prints the graph with one command. This
allowed us to generate a large number of scenarios very easily, and as a
result, we were able to focus on analyzing the data rather than executing
endless algorithms by hand.
An interesting result was generated in the
following scenario. One can see how the squirrels nearly became extinct but
then “rebounded” and repopulated the terrain:
300 hawks, 40
squirrels; 75 iterations; 20 x 40 grid:

After various tests on a 20 x 40 grid (as suggested
by the assignment), we found that, unless the field was highly overpopulated
with hawks (as in the example with 500 hawks above) or unless the squirrel
population was extremely small, a 20 by 40 grid populated reasonably (neither
species with more than approximately 500 agents) would always yield a drastic
increase in the squirrel population and either a steady decline (and
extinction) of hawks or a low sustainable population of hawks. This outcome, we
concluded, was a result of the large terrain. Because multiple agents can stay
in the same location, we needed either to increase drastically the number of
agents in the population or, more realistically, implement one of our
extensions that only moved hawks to locations with squirrels. To do so, we
added the following code to our “while” loop that determined the new locations
for squirrels:

This addition significantly aided the squirrel
population maintenance. Whereas in the past the hawks were randomly going to
locations in the terrain and dying because of hunger (without a huge population
of squirrels, the chances that the hawks would land on the same (row, column)
location as a squirrel and win a hunt were slim), hawks were now
“intelligently” landing on locations known to have squirrels. With this
extension in place, we produced the following graph.
500 hawks,
1000 squirrels; 75 iterations; 20 x 40 grid:

Clearly, the addition of this extension moderated
the outcome significantly. Although the hawk population still declined and the
squirrel population still rose rapidly, the result was much more gradual.
Our original goal was to obtain populations of
symbiosis—that is, an initial population of X squirrels and X hawks that could
live symbiotically and maintain relatively constant populations over time.
Therefore, a smaller number of hawks or a larger number of squirrels would
destroy the hawk population; and, conversely, a larger number of hawks or a
smaller number of squirrels would destroy the squirrel population. As we
discovered, finding this point of symbiosis is extremely difficult. From a
hawk’s perspective, more hawks means more reproduction but also more
competition. Similarly, more squirrels mean more food for the hawks but also
more offspring. Thus, in some cases, an extremely large population of hawks
actually resulted in the prosperity of the squirrel population.
DISCUSSION
AND SUMMARY
Overall, we believe that our project was extremely
successful. Although we did not achieve our goal of locating populations that
would produce a symbiotic relationship, we created a program that worked
flawlessly and integrated it with an effective way to analyze our data. After
we had finished the coding of the project, we were able to focus on the actual
results yielded by the program.
Interestingly enough, the principles discussed in
this project can be applied to the fundamental economic principle of supply and
demand. When one considers the squirrel to be the “supply” and the hawk to be
the “demand,” the inverse relationship between the two becomes even more
apparent. Our program is not an exact analogy of a supply-demand relationship
(the squirrel could also be considered the demand), but it also is not an exact
representation of a real-life hawk and squirrel relationship. The fundamental
concepts, however, are extremely similar, and as such, we believe that our
program provided an effective and successful means of studying real-world
concepts, situations, and principles.