
/*
the following items are given in order of removal in order of removal

infantry
artillery
tank
fighter (11)
bomber (12)
aa (always last)

*/


public class AxisBattle {

	public AxisBattle(String[] attacker, String[] defender) {

		boolean antiAir;
		int ac, dc, i, j, maxloss;
		int attackers = attacker.length;
		int defenders = defender.length;
		output = "Battle not commenced";

		antiAir = false;
		if("aa".equals(defender[defenders-1])) {
			defenders--;
			antiAir = true;
		}

		double[][] states = new double[attackers+1][defenders+1];

		double prob[]  = new double[7];
		prob[0] = 0; prob[1] = 1.0/6.0; prob[2] = 2.0/6.0; prob[3] = 0.5;
		prob[4] = 4.0/6.0; prob[5] = 5.0/6.0; prob[6] = 1.0;

		/*
		 * probability for number of losses
		 */
		i = attackers + 1;
		double[] aoutcome = new double[i];
		while(i>0) {
			i--; aoutcome[i] = 0.0;
		}
		i = defenders + 1;
		double[] doutcome = new double[i];
		while(i>0) {
			i--; doutcome[i] = 0.0;
		}
		

		// set up power arrays

		int[] aforce = new int[attackers];
		int[] apower = new int[attackers];
		int[] dpower = new int[defenders];
		double[] adamage = new double[attackers+1];
		double[] ddamage = new double[defenders+1];
		int aloss;
		int afighters = 0;
		int abombers  = 0;
		
		for(ac=0;ac<attackers;ac++) {
			if(attacker[ac].equals("infantry")) aforce[ac] = 1;
			else if(attacker[ac].equals("artillery")) aforce[ac] = 2;
			else if(attacker[ac].equals("tank")) aforce[ac] = 3;
			else if(attacker[ac].equals("fighter")) {aforce[ac] = 11; afighters++;}
			else if(attacker[ac].equals("bomber")) {aforce[ac] = 12; abombers++;}
			else {
				output = "Unknown attack unit: " + attacker[ac];
				return;
			}
		}
		for(dc=0;dc<defenders;dc++) {
			if(defender[dc].equals("infantry")) dpower[dc] = 2;
			else if(defender[dc].equals("artillery")) dpower[dc] = 2;
			else if(defender[dc].equals("tank")) dpower[dc] = 2;
			else if(defender[dc].equals("fighter")) dpower[dc] = 4;
			else if(defender[dc].equals("bomber")) dpower[dc] = 1;
			else {
				output = "Unknown defend unit: " + defender[dc];
				return;
			}
		}

		//if no AA then no fighter/bomber-losses
		if(!antiAir) afighters = abombers = 0;


		/*
		 * So now it is battle time...
		 * The battle is to be fought with all different possible output of the
		 * AA-gun and the probabilities then added together
		 */

		double aa_prob;
		double zero_damage_mod;
		int aaf, aab;
		int tmpb, tmpf;
		for(aaf=0;aaf<=afighters;aaf++) for(aab=0;aab<=abombers;aab++) {
			/* first, what is the probability that aaf fighters
			 * and aab bombers were shot down
			 */
			aa_prob = binomial(aaf,afighters,prob[1]) *
				  binomial(aab,abombers ,prob[1]);

			aloss = aaf + aab;
			tmpb = tmpf = 0; 
			ac = aloss;
			for(i=0;i<attackers;i++) {
				if(aforce[i] < 10) {
					apower[ac] = aforce[i];
					ac++;
				} else if (aforce[i] == 11) {
					if(tmpf == aaf) { //already taken fighter losses
						apower[ac] = 3;
						ac++;
					} else {
						tmpf++;
					}
				} else {
					if(tmpb == aab) {
						apower[ac] = 4;
						ac++;
					} else {
						tmpb++;	
					}
				} 
			}


			/*
			 * At this point:
			 *  - apower and dpower contains all attack values
			 *  - attackers and defenders contain no units (before aa, excl aa)
			 *  - aloss is the number of units lost to AA
			 */

			// set all probabilities to 0.0
			for(ac=0;ac<=attackers;ac++) for(dc=0;dc<=defenders;dc++) states[ac][dc] = 0.0;

			// set probability for initial state to 1.0
			states[aloss][0] = 1.0;

			/*
			 * The strategy now is to handle states that no other remaining states
			 * can result in (and take care of the possibility of returning to the
			 * same state again). Each state results in other states with given
			 * probabilities thus increasing these states "state-value".
			 */

			for(ac=aloss;ac<attackers;ac++) for(dc=0;dc<defenders;dc++) {
				adamage[0] = prob[6 - apower[ac]];
				adamage[1] = prob[apower[ac]];

				for(i=ac+1;i<attackers;i++) {
					j = i - ac;
					adamage[j+1] = prob[apower[i]] * adamage[j];
					while(j>0) {
						adamage[j] *= prob[6 - apower[i]];
						adamage[j] += prob[apower[i]] * adamage[j-1];
						j--;
					}
					adamage[0] *= prob[6 - apower[i]];
				}

				ddamage[0] = prob[6 - dpower[dc]];
				ddamage[1] = prob[dpower[dc]];

				for(i=dc+1;i<defenders;i++) {
					j = i - dc;
					ddamage[j+1] = prob[dpower[i]] * ddamage[j];
					while(j>0) {
						ddamage[j] *= prob[6 - dpower[i]];
						ddamage[j] += prob[dpower[i]] * ddamage[j-1];
						j--;
					}
					ddamage[0] *= prob[6 - dpower[i]];
				}

				/* reduce over-damage */
				i = attackers - ac;
				j = defenders - dc;
				while(i>j) {
					adamage[i-1] += adamage[i];
					i--;
				}
				while(i<j) {
					ddamage[j-1] += ddamage[j];
					j--;
				}
				maxloss = i;
					
				/*
				 * now we know with what probability attacker and defender
				 * will do a given amount of damage
				 */

				zero_damage_mod = 1.0 / (1.0 - adamage[0] * ddamage[0]);
					
				for(i=maxloss;i>=0;i--) for(j=maxloss;j>=0;j--) {
					states[ac+i][dc+j] += states[ac][dc] *
							      adamage[j] *
							      ddamage[i] *
							      zero_damage_mod;

				}
			}

			for(i=0;i<=attackers;i++) {
				aoutcome[i] += states[i][defenders] * aa_prob;
			}
			for(i=0;i<=defenders;i++) {
				doutcome[i] += states[attackers][i] * aa_prob;
			}
		}
		double checksum = 0.0;
		
		output = "Attacker wins with n units left\n";
		for(i = 1;i<=attackers;i++) {
			output += i + "   " + aoutcome[attackers - i] + "\n";
			checksum += aoutcome[attackers - i];
		}
		output += "Total: " + checksum + "\n";
		output += "\nDefender wins with n units left\n";
		for(i = 0;i<=defenders;i++) {
			output += i + "   " + doutcome[defenders - i] + "\n";
		}
	}

	/* returns probability that a successful out of b with probability p */
	public static double binomial(int a, int b, double p) {
		double t = Math.pow(p, (double)a) * Math.pow( (1.0-p) , (double)(b-a) );
		double s = 1.0;
		int i;
		for(i=a+1;i<=b;i++) t *= (double) i;
		for(i=(b-a);i>1;i--) s *= (double) i;
		return (t /= s);
	}


	public String battleResults() {
		return output;
	}

	public static void main(String[] args) {
		int i;
		i = args.length - 1;
		while(i>=0) {
			if(args[i].equals("vs")) break;
			i--;
		}
		if(i <= 0 || i >= (args.length -1) ) {
			System.out.println("Give a list of units separated by vs");
			return;
		}
		String[] a = new String[i];
		String[] b = new String[args.length - i -1];
		for(i=0;i<a.length;i++) a[i] = args[i];
		for(i=0;i<b.length;i++) b[i] = args[i + a.length + 1];
		AxisBattle z = new AxisBattle(a,b);
		System.out.println(z.battleResults());

	}

	String output;

}
