/* 
	Battle.java

	Title:			Battle
	Author:			
	Description:	
*/

//package Battle;

import java.awt.*;
//import java.awt.event.*;
import java.applet.*;

public class Battle extends Applet 
{
	// member declarations
	int nS = 5;  // number of strategies
	int initPlayersPerStrategy = 10;
	int nP = nS*initPlayersPerStrategy; // number of players, must be even
	Strategy S[] = new Strategy[nS];
	Player P[] = new Player[nP];
	int lengthOfMatch = 100;
	int numberOfMatches = 100;

	Player Q[] = new Player[nP];  // array of quitters
	int nQ = 0; // number of quitters

	boolean isStandalone = false;

	boolean showPlay = false;

	public Battle() 
	{
	}

	// Retrieve the value of an applet parameter
	public String getParameter(String key, String def) 
	{
		return isStandalone ? System.getProperty(key, def) :
			(getParameter(key) != null ? getParameter(key) : def);
	}

	// Get info on the applet parameters
	public String[][] getParameterInfo() 
	{
		return null;
	}

	// Get applet information
	public String getAppletInfo() 
	{
		return "Applet Information";
	}

	// Initialize the applet
	public void init() 
	{
		try {
			initComponents();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void initComponents() throws Exception
	{
		// the following code sets the frame's initial state
		//setLocation(new java.awt.Point(0, 0));
		setLayout(null);
		//setSize(new java.awt.Dimension(400, 300));
		
		// set up the Strategy array S
		S[0] = new Strategy(); //Nice Strategy
		S[1] = new Nasty();
		S[2] = new TitForTat();
		S[3] = new Moth();
		S[4] = new HitAndRun();
		//S[5] = new RandomNoMemory();
		//(RandomNoMemory) S[5].randomize();
		for (int s=0; s<nS; ++s)
		  S[s].strategyNumber = s;
		// initialize Player array P and
		// put them all in the quitters array
		for (int p=0; p<nP; ++p) {
		    P[p] = new Player();
		    P[p].id = p;
		    P[p].S = S[p/initPlayersPerStrategy];
		    Q[nQ++] = P[p];
		}
		// simulate the game
		System.out.println ("Simulate the game");
		for (int m=0; m<numberOfMatches; ++m) {
		    System.out.println("\nMatch "+m+" begins");
		    playMatch();
		    System.out.println("Scores");
		    reassignPlayers();
		}
		System.out.println("\nSimulation complete.");
	}
	
	void playMatch() {
		// first clear the scores
		for (int p=0; p<nP; ++p)
		  P[p].score = 0;
		// now do all the plays
		for (int r=0; r<lengthOfMatch; ++r) {
		  if (showPlay) System.out.println("\nRound "+r);
		  matchQuitters();
		  // let each player have a turn
		  for (int i=0; i<nP; ++i)
		    if (P[i].partner != -1 && i < P[i].partner) {
		      if (showPlay) 
			System.out.print("  p="+i +" s="+P[i].S.strategyNumber+" vs. p="+P[i].partner+" s="+P[P[i].partner].S.strategyNumber+" m="+P[i].movenumber+"   ");
		      play(P[i],P[P[i].partner]);
		    }
		}
	}
	
	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;
		}
    }		
	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);
		}
	    if (showPlay)
		System.out.print(A.thisMove+" vs. "+B.thisMove);
	    if (A.thisMove == 2 || B.thisMove == 2) {
	        A.partner = -1;
	        B.partner = -1;
	        Q[nQ++] = A;
	        Q[nQ++] = B;
		if (showPlay)
		    System.out.println("  Player quit.");
	        return;
	    }
	    if (showPlay)
		System.out.print("\n    Old scores:"+A.score+" vs "+B.score);
	    if (A.thisMove == 0 && B.thisMove == 0) {
	        A.score += 3;
	        B.score += 3;
	    } else if (A.thisMove == 0 && B.thisMove == 1) {
	        A.score += 0;
	        B.score += 5;
	    } else if (A.thisMove == 1 && B.thisMove == 0) {
	        A.score += 5;
	        B.score += 0;
	    } else { // (A.thisMove == 1 && B.thisMove == 1)
	        A.score += 1;
	        B.score += 1;
	    }
	    if (showPlay)
		System.out.println("\n    New Scores: "+A.score+" vs. "+B.score);
	    A.previousMove = A.lastMove;
	    B.previousMove = B.lastMove;
	    A.lastMove = A.thisMove;
	    B.lastMove = B.thisMove;
	    ++A.movenumber;
	    ++B.movenumber;
	    return;
	}
	
	void reassignPlayers() {
	    // compute total scores for the strategies
	    int total[] = new int[nS];
	    for (int p=0; p<nP; ++p) {
	      int s=P[p].S.strategyNumber;
	      total[s] += P[p].score;
	      //System.out.println("P["+p+"].score="+P[p].score+"  total["+s+"]="+total[s]);
	    }
	    // compute the grand total
	    int grandTotal = 0;
	    for (int s=0; s<nS; ++s) {
	      grandTotal += total[s];
	    }
	    System.out.println ("Total score: "+grandTotal);
	    // determine how many players there should be for each strategy
	    // and assign the strategies
	    int p = 0;
	    for (int s=0; s<nS; ++s) {
	      int assign = total[s]*nP/grandTotal;
	      System.out.println ("Strategy "+s+": "+total[s]+ "   "+assign+" players");
	      for (int j=0; j<assign; ++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<nP) {
	      int f = (int)(grandTotal*Math.random());
	      int s = nS;
	      for (int i=grandTotal; i>f; i-=total[--s]); //no body for loop
	      if (s==nS)
	        System.out.println ("***  p="+p+"  f = "+f+"  s = "+s);
	      P[p++].S = S[s];
	    }
	}

	// Standard method to start the applet
	public void start() {}

	// Standard method to stop the applet
	public void stop() {}

	// Standard method to destroy the applet
	public void destroy() {}
}

