/*----------------------------------------------------------------------+
|      Title:	LiveBattle.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/                           |
|           djoyce@clarku.edu                                           |
|                                                                       |
|      Date:    May, 2002.                                              |
+----------------------------------------------------------------------*/

import java.awt.*;

public class LiveBattle  implements Runnable {
  private int lengthOfMatch;
  private int payoff[][] = new int[2][2];
  private int deaths;
  private TextArea reportArea;
  private TimeGraph timeGraph;
  private Player P[]; // array of players
  private Strategy oldmaxS,maxS;
  private Match match;

  public LiveBattle (Player PIn[],
        int lengthOfMatchIn, int payoffIn[][], int deathsIn,
        TimeGraph timeGraphIn, TextArea reportAreaIn) {
    // first save the paramters
    P = PIn;
    lengthOfMatch = lengthOfMatchIn;
    for (int i=0; i<=1; ++i)
      for (int j=0; j<=1; ++j)
        payoff[i][j] = payoffIn[i][j];
    deaths = deathsIn;
    timeGraph = timeGraphIn;
    reportArea = reportAreaIn;
    // next initialize the variables
    oldmaxS = null;
    match = new Match();
    }

  private Thread thread = null;
  private boolean doStop = false;

  public void go() {
    if (thread == null) {
      thread = new Thread(this);
      thread.start();
    }
  }//go

  public void stop() {
    doStop = true;
  }//stop

  public void run() {
    match = new Match();
    createPlayers();
    do {
      updateData();
      if (oldmaxS.pop == P.length)
        break;
      match.simulate(P,lengthOfMatch, payoff);
      reassignPlayers(deaths);
      try {thread.sleep(100);} // wait this many milliseconds
      catch (InterruptedException e) {};
    } while (!doStop);
    thread = null;
    doStop = false;
  }//run

  /*
  public void run() {
    createPlayers();
    int deaths = P.length*deathRate/100;
    LiveBattle battle = new
      LiveBattle(P,gamesPerMatch,payoff,deaths,timeGraph,reportArea);
    // Perform the simulation until requested to stop
    timeGraph.init(Color.gray,rainbow(P.length),100);
    int simulationNumber = 0;
    do {
      simulationNumber++;
      System.out.println("Starting simulation"+simulationNumber);
      battle.doSimulation(10);
      timeGraph.repaint();
      try {thread.sleep(200);} // wait this many milliseconds
      catch (Exception e) {};
    } while (!doStop);
    thread = null;
    doStop = false;
  }//run
  */

  private void createPlayers() {
    P = new Player[players];
    for (int p=0; p<players; ++p) {
      Genome gen = new Genome();
      gen.randomize();
      P[p] = new Player(p,new LiveStrategy(p,"Live",gen));
    }
  }//createPlayers
  
  private void updateData () {
    int data[] = new int[P.length];
    Strategy maxS = P[0].S;
    int max=0;
    for (int p=0; p<P.length; ++p) {
      int stratNum = P[p].S.strategyNumber;
      data[stratNum]++;
      if (data[stratNum] > max) {
        max = data[stratNum];
        maxS = P[p].S;
      }
    } // for
    timeGraph.newData(data);
    if (oldmaxS == null || maxS.strategyNumber != oldmaxS.strategyNumber) {
      reportArea.append(maxS+"\n");
      oldmaxS = maxS;
    }
  } // updateData

  private void reassignPlayers(int deaths) {
    // First, remove some players due to death, randomly
    for (int d=0; d<deaths; ++d) {
      int dp;
      do
        dp = (int)(Math.random()*P.length);
      while (P[dp] == null) ;
      P[dp].S.pop--;
      P[dp] = null;
    }
    // Next, compute the cumulative scores across the players
    int cumulativeScore[] = new int[P.length];
    int cum=0;
    for (int p=0; p<P.length;++p) {
      if (P[p] != null)
        cum += P[p].score;
      cumulativeScore[p] = cum;
    }
    // Now, for each removed player, select another.
    for (int p=0; p<P.length;++p)
      if (P[p] == null)
        P[p] = new Player (p,selectStrategy(cumulativeScore));
  } // reassignPlayers()
  
  private Strategy selectStrategy(int cumulativeScore[]) {
    // Simply, select an existing player's strategy weighted by score
    int score =(int)(Math.random()*cumulativeScore[P.length-1]);
    int p;
    for (p=0; p<P.length; ++p)
      if (cumulativeScore[p]>=score)
        break;
    if (p == P.length) {// error
      System.out.println(" Error in LiveBattle.selectStrategy.");
      System.exit(0);
    }
    return P[p].S;
  } // replacementPlayer

} // Battle.java

