// FILE: Pondlife.java
// A simple simulation program to model the fish and weeds in a pond

import edu.colorado.simulations.*; // Provides Organism, Plant, Herbivore classes
import java.util.Vector;

/******************************************************************************
* The <CODE>PondLife</CODE> Java application runs a simple simulation that
* models the fish and weeds in a pond.
*
* <P>The simulation is currently set up to use these values:
* <UL>
* <LI> Number of weeds in the pond: 2000
* <LI> Initial size of each weed: 15 ounces 
* <LI> Growth rate of weeds: 2.5 ounces/week  
* <LI> Initial number of fish in the pond: 300
* <LI> Fish size: 50 ounces 
* <LI> A fish must eat 0.5 times its size during one week, or it will die.
* <LI> Average number of weeds nibbled by a fish over a week: 30 
* <LI> At the end of each week, some fish have babies. The total number of new
*        fish born is the current number of fish times the 0.05 
*        (rounded down to an integer).
* <LI> Number of weeks to simulate: 38
* </UL>                   
*
* <p><dt><b>Java Source Code for this class:</b><dd>
*   <A HREF="../applications/PondLife.java">
*   http://www.cs.colorado.edu/~main/applications/PondLife.java
*   </A>
*
* @author Michael Main 
*   <A HREF="mailto:main@colorado.edu"> (main@colorado.edu) </A>
*
* @version
*   Jul 29, 2005
*
* @see edu.colorado.simulations.Organism
* @see edu.colorado.simulations.Plant
* @see edu.colorado.simulations.Herbivore
******************************************************************************/
public class PondLife
{
   // Number of weeds in the pond
   public static final int MANY_WEEDS = 2000;
   
   // Initial size of each weed, in ounces 
   public static final double WEED_SIZE = 15;
  
   // Growth rate of weeds, in ounces/week  
   public static final double WEED_RATE = 2.5; 
  
   // Initial number of fish in the pond 
   public static final int INIT_FISH = 300;
   
   // Fish size, in ounces 
   public static final double FISH_SIZE = 50; 
   
   // A fish must eat FRACTION times its size during one week, or it will die.
   public static final double FRACTION = 0.5;
   
   // Average number of weeds nibbled by a fish over a week 
   public static final int AVERAGE_NIBBLES = 30; 
   
   // At the end of each week, some fish have babies. The total number of new
   // fish born is the current number of fish times the BIRTH_RATE 
   // (rounded down to an integer).
   public static final double BIRTH_RATE = 0.05;
   
   // Number of weeks to simulate
   public static final int MANY_WEEKS  = 38; 
   
   
   /**
   * Run the simulation, using the values indicated in the documentation.
   * The <CODE>String</CODE> arguments (<CODE>args</CODE>) are not used
   * in this implementation.
   **/                                                    
   public static void main(String[ ] args)   
   {
       Vector<Herbivore> fish = new Vector<Herbivore>(INIT_FISH);   // A Vector of our fish
       Vector<Plant> weeds = new Vector<Plant>(MANY_WEEDS); // A Vector of our weeds
       int i;                                 // Loop control variable

       // Initialize the bags of fish and weeds
       for (i = 0; i < INIT_FISH; i++)
          fish.addElement(new Herbivore(FISH_SIZE, 0, FISH_SIZE * FRACTION));
       for (i = 0; i < MANY_WEEDS; i++)
          weeds.addElement(new Plant(WEED_SIZE, WEED_RATE));

       System.out.println("Week \tNumber \tPlant Mass");
       System.out.println("     \tof     \t(in ounces)");
       System.out.println("     \tFish");

       // Simulate the weeks
       for (i = 1; i <= MANY_WEEKS; i++)
       {
          pondWeek(fish, weeds);
          System.out.print(i + "\t");
          System.out.print(fish.size( ) + "\t");
          System.out.print((int) totalMass(weeds) + "\n");
       }
   }
   
   
   /**
   * Simulate one week of life in the pond, using the values indicated in the
   * documentation.
   **/
   public static void pondWeek(Vector<Herbivore> fish, Vector<Plant> weeds)
   {
      int i;
      int manyIterations;
      int index;
      Herbivore nextFish;
      Plant nextWeed;

      // Have randomly selected fish nibble on randomly selected plants
      manyIterations = AVERAGE_NIBBLES * fish.size( );
      for (i = 0; i < manyIterations; i++)
      {
         index = (int) (Math.random( ) * fish.size( ));
         nextFish = fish.elementAt(index);
         index = (int) (Math.random( ) * weeds.size( ));
         nextWeed = weeds.elementAt(index);
         nextFish.nibble(nextWeed);
      }

      // Simulate the weeks for the fish
      i = 0;
      while (i < fish.size( ))
      {
         nextFish = fish.elementAt(i);
         nextFish.simulateWeek( );
         if (nextFish.isAlive( ))
            i++;
         else
            fish.removeElementAt(i);
      }

      // Simulate the weeks for the weeds
      for (i = 0; i <weeds.size( ); i++)
      {
         nextWeed = weeds.elementAt(i);
         nextWeed.simulateWeek( );
      }

      // Create some new fish, according to the BIRTH_RATE constant
      manyIterations = (int) (BIRTH_RATE * fish.size( ));
      for (i = 0; i < manyIterations; i++)
          fish.addElement(new Herbivore(FISH_SIZE, 0, FISH_SIZE * FRACTION));
   }
   
   
   /**
   * Calculate the total mass of a collection of <CODE>Organism</CODE>s.
   * @param <CODE>organisms</CODE>
   *   a <CODE>Vector</CODE> of <CODE>Organism</CODE> objects
   * <dt><b>Precondition:</b><dd>
   *   Every object in <CODE>organisms</CODE> is an <CODE>Organism</CODE>.
   * @return
   *   the total mass of all the objects in <CODE>Organism</CODE> (in ounces).
   **/
   public static <T extends Organism> double totalMass(Vector<T> organisms)
   {
      double answer = 0;
      
      for (Organism next : organisms)
      {
         if (next != null)
            answer += next.getSize( );
      }
      return answer;
   }

}
