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 Greenfield class was fairly straightforward, as outlined in the instructions. Greenfield created a 2-dimensional array of specified parameters where each location (referenced by row and column) in turn referenced an EntityList holding all of the agents at that location.

 

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, greenfield, of type Greenfield is created with row and column parameters taken from the user and passed from the constructor. Two objects of type EntityListhlist and slist—are created to store the agents of classes Hawk and Squirrel, respectively. The initial numbers of hawks and squirrels are also required from the user and provided through the constructor.

 

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 greenfield) is set to the row and column obtained in step 1.

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 Greenfield, the following algorithm is applied:

 

·         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 Greenfield and remove the from the list of squirrels in the simulator (slist). R.I.P. squirrel.

o        If it has not died of old age, move the squirrel to a random location in Greenfield that is within the radius of the maximum distance it is allowed to move (as an extension, our program allows the programmer to decide if the squirrel should keep searching for a new random location if the first one it finds contains a hawk. Logically, a squirrel would not move to a location that already contained a hawk. Because there may not always be a hawk-free location within the defined area, a counter can break the loop after a specified number of iterations). Remove the squirrel from the EntityList referenced by its old location, and insert it into the one referenced by the new location. The location of the squirrel is also updated.

 

iterHawk():

 

For each hawk present in Greenfield, the following algorithm is applied:

 

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

·         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 Greenfield and the list of the hawk population, and print a message declaring that a hawk has died. R.I.P.

 

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.