/*----------------------------------------------------------------------+
|    Title:  Herd.java                                                  |
|                                                                       |
|    Author: David E. Joyce                                             |
|            Department of Mathematics and Computer Science             |
|            Clark University                                           |
|            Worcester, MA 01610-1477                                   |
|            U.S.A.                                                     |
|            http://aleph0.clarku.edu/~djoyce/home.html                 |
|            djoyce@clarku.edu                                          |
|                                                                       |
|    Date:   February, 2001.                                            |
+----------------------------------------------------------------------*/

import java.awt.Color;

public class Herd {

  int paired;     // the number of paired altruist animals
  int unpaired;   // the number of unpaired altruist animals
  int selfish;    // the number of selfish animals

  Herd () { }     // default constructor

  Herd (int initPaired, int initUnpaired, int initSelfish) {
    set (initPaired, initUnpaired, initSelfish);
  }

  public void set (int initPaired, int initUnpaired, int initSelfish) {
    paired = initPaired;
    unpaired = initUnpaired;
    selfish = initSelfish;
  }
  
  public String toString() {
    return "["+paired+","+unpaired+","+selfish+"]";
  }

  // see if on this day any unpaired altruists become paired
  public void pairing() {
    int i = unpaired;   // i and j indicate those yet to pair
    int j = selfish;
    while (i>1)  
      if (Math.random() < (i-1.0)/(i-1+j)) {
        paired +=2;
        unpaired -=2;
        i -=2;
      } else {
        --i; --j;
      }
  }
  
  public void death (int n) {  // n animals of the herd die
    int total = paired + unpaired + selfish;
    for (int i=0; i<n; ++i) {
      double r = Math.random();
      if (r < (paired+0.0)/total) {  // a paired altruist dies
        paired -=2;
        ++unpaired;
      } else if (r < (paired+unpaired+0.0)/total)   // an unpaired altruist dies
        --unpaired;
      else    // a selfish dies
        --selfish;
      --total;
    }  
  }
 
  public void birth (double cost, double benefit, int n) {
    // n new animals are born in the herd
    double total_vitality = (10-cost+benefit)*(paired+unpaired) + 10*selfish;
    double altruist_vitality = (10-cost+benefit)*paired + (10-cost)*unpaired;
    double probability_altruist = altruist_vitality/total_vitality;
    for (int i=0; i<n; ++i) {
      if (Math.random() < probability_altruist)
        ++unpaired;
      else
        ++selfish;
    }
  }
  
  public void migrate_in (Herd Band) { // a band of animals joins the herd
    paired   += Band.paired;
    unpaired += Band.unpaired;
    selfish  += Band.selfish;
    Band.paired = Band.unpaired = Band.selfish = 0;
  }

  // a band of n animals leave the herd
  public void migrate_out (int n, Herd Band)  {
      for (int i=0; i<n; ++i) {
      double r = Math.random();
      if (r < (paired+0.0)/(paired+unpaired+selfish)) {
        // a paired altruist leaves
        paired -=2;
        ++Band.unpaired;
        ++unpaired;
      } else if (r < (paired+unpaired+0.0)/(paired+unpaired+selfish)) {
        // an unpaired altruist dies
        --unpaired;
        ++Band.unpaired;
      } else  {  // a selfish dies
        --selfish;
        ++Band.selfish;
      }
    }  
  }

  public Color chooseColor() {
    return Herd.chooseColor(paired, unpaired, selfish);
  }

  public static Color chooseColor(int paired, int unpaired, int selfish) {
      double fract = (paired + unpaired + 0.0)
                   / (paired + unpaired + selfish);
      double hue = 0.0;
      double bright = 1.0;
      double sat = 1.0;
      if (0.0 == fract) {
        hue    = 0.0;
        sat    = 1.0;
        bright = 0.0;
      } else if (fract < 0.1) {
        hue    = 0.0;
        sat    = 1.0;
        bright = 5.0 * (0.1 + fract);
      } else if (fract < 0.75) {
        hue    = fract - 0.1;
        sat    = 1.0;
        bright = 1.0;
      } else if (fract != 1.0) {
        hue    = fract - 0.1;
        sat    = 3.9*(1.0 - fract);
        bright = 1.0;
      } else { // fract == 1.0
        hue    = 0.0;
        sat    = 0.0;
        bright = 1.0;
      }
      int cidx = Color.HSBtoRGB ((float)(hue),		// hue
			         (float)(sat),          // sat
			         (float)(bright));	// bright
      return new Color(cidx);
  }

}

