/*----------------------------------------------------------------------+
|      Title:	Battle.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.                                              |
+----------------------------------------------------------------------*/

public class Battle {
  private Strategy S[];
  private int numberOfMatches, lengthOfMatch;
  private int payoff[][] = new int[2][2];

  public Battle (Strategy[] SIn) {
    S = SIn;
  }

  private Player P[]; // array of players
  private Player Q[];  // array of quitters
  private int nQ; // number of quitters

  public void doSimulation (int nP, int numberOfMatchesIn,
        int lengthOfMatchIn, int payoffIn[][], TimeGraph statGraph) {
    numberOfMatches = numberOfMatchesIn;
    lengthOfMatch = lengthOfMatchIn;
    for (int i=0; i<=1; ++i)
      for (int j=0; j<=1; ++j)
        payoff[i][j] = payoffIn[i][j];
    for (int s=0; s<S.length; ++s)
      S[s].reset();
    // initialize Player array P and
    // put them all in the quitters array
    P = new Player[nP];
    nQ = 0;
    Q = new Player[nP];
    for (int p=0; p<nP; ++p) {
      P[p] = new Player(p,S[p*S.length/nP]);
      Q[nQ++] = P[p];
    }
    // now do the simulation
    for (int m=0; m<numberOfMatches; ++m) {
      updateData(statGraph);
      playMatch();
      reassignPlayers();
    }
  }

  private void updateData (TimeGraph statGraph) {
    int data[] = new int[S.length];
    for (int s=0; s<S.length; ++s)
      data[s] = S[s].pop;
    statGraph.newData(data);
    //statGraph.repaint();
  }

  private void playMatch() {
    // first clear the scores
    for (int p=0; p<P.length; ++p)
      P[p].score = 0;
    // now do all the plays
    for (int r=0; r<lengthOfMatch; ++r) {
      matchQuitters();
      // let each player have a turn
      for (int i=0; i<P.length; ++i)
        if (P[i].partner != -1 && i < P[i].partner)
          play(P[i],P[P[i].partner]);
    }
  }

  private void matchQuitters() {
    //Simply shuffle them
    for (int i=0; i<nQ-1; ++i) {
      int j = i + (int)((nQ-i)*Math.random());
      Player Temp = Q[i];
      Q[i] = Q[j];
      Q[j] = Temp;
    }
    // now adjacent pairs will pair off, starting at the end
    while (nQ>=2) {
      --nQ;
      Q[nQ].partner = Q[nQ-1].id;
      Q[nQ-1].partner = Q[nQ].id;
      Q[nQ].movenumber = 0;
      Q[nQ-1].movenumber = 0;
      --nQ;
    }
  }

  private void play(Player A, Player B) {
    if (A.movenumber == 0) {
      A.thisMove = A.S.firstMove();
      B.thisMove = B.S.firstMove();
    } else if (A.movenumber == 1) {
      A.thisMove = A.S.secondMove(A.previousMove,B.previousMove,A.score);
      B.thisMove = B.S.secondMove(B.previousMove,A.previousMove,B.score);
    } else  {
      A.thisMove = A.S.thirdMove(A.lastMove,B.lastMove,
      A.previousMove,B.previousMove,A.score);
      B.thisMove = B.S.thirdMove(B.lastMove,A.lastMove,
      B.previousMove,A.previousMove,B.score);
    }
    A.score += payoff[A.thisMove][B.thisMove];
    B.score += payoff[B.thisMove][A.thisMove];
    if (A.S.leave(A.thisMove,B.thisMove,A.score) ||
                B.S.leave(B.thisMove,A.thisMove,B.score)) {
      A.partner = -1;
      B.partner = -1;
      Q[nQ++] = A;
      Q[nQ++] = B;
    } else {
      A.previousMove = A.lastMove;
      B.previousMove = B.lastMove;
      A.lastMove = A.thisMove;
      B.lastMove = B.thisMove;
      ++A.movenumber;
      ++B.movenumber;
    }
    return;
  }

  private void reassignPlayers() {
      // compute total scores for the strategies
      int total[] = new int[S.length];
      for (int p=0; p<P.length; ++p) {
        int s=P[p].S.strategyNumber;
        total[s] += P[p].score;
      }
      // compute the grand total
      int grandTotal = 0;
      for (int s=0; s<S.length; ++s) {
        grandTotal += total[s];
      }
      // determine how many players there should be for
      // each strategy and assign the strategies
      int p = 0;
      for (int s=0; s<S.length; ++s) {
        S[s].pop = total[s]*P.length/grandTotal;
        for (int j=0; j<S[s].pop; ++j)
          P[p++].S = S[s];
      }
      // Because of truncation, maybe not all players
      // have been assigned a strategy
      // Choose the remaining strategies randomly
      // weighted by the totals
      while (p<P.length) {
        int f = (int)(grandTotal*Math.random());
        int s = S.length;
        for (int i=grandTotal; i>f; i-=total[--s]); //no body for loop
        if (s==S.length) // error
          System.out.println ("***  p="+p+"  f = "+f+"  s = "+s);
        S[s].pop++;
        P[p++].S = S[s];
      }
  }
} // Battle.java

