Index: src/net/yura/domination/engine/ai/AIHardCapital.java
===================================================================
--- src/net/yura/domination/engine/ai/AIHardCapital.java	(revision 1057)
+++ src/net/yura/domination/engine/ai/AIHardCapital.java	(working copy)
@@ -2,639 +2,218 @@
 
 package net.yura.domination.engine.ai;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.Vector;
+import java.util.Map.Entry;
+
 import net.yura.domination.engine.core.Continent;
 import net.yura.domination.engine.core.Country;
 import net.yura.domination.engine.core.Player;
 
+
 /**
  * <p> Class for AIHardPlayer </p>
  * @author SE Group D
  */
 
 public class AIHardCapital extends AIHard {
-
-	public String getPlaceArmies() {
-
-		String output;
-
-		    if ( game.NoEmptyCountries()==false ) {
-
-			Continent[] cont = game.getContinents();
-
-			/* ai attempts to gain control of a continent during initial placement */
-
-			int territorynum = 0;
-			int check = -1;
-			String name=null;
-			int val = -1;
-
-			for (int i=0; i<cont.length; i++) {
-			    Vector ct = new Vector();
-			    Continent co = cont[i];
-			    ct = co.getTerritoriesContained();
-
-			    for (int j=0; j<ct.size(); j++) {
-			        if ( ((Country)ct.elementAt(j)).getOwner() == player ) { territorynum++; }
-			    }
-
-			    if (check <= territorynum) {
-				check = territorynum;
-				val = i;
-			    }
-			    territorynum = 0;
+	
+	protected Vector getBorder(GameState gs) {
+		Vector border = super.getBorder(gs);
+		
+		int minNeeded=Integer.MAX_VALUE;
+		Country priority = null;
+		for (Iterator i = gs.capitals.iterator(); i.hasNext();) {
+			Country c = (Country) i.next();
+			if (c.getOwner() != player) {
+				continue;
 			}
-
-			/* ..pick country from that continent */
-			boolean picked = false;
-			if (check > 0) {
-			    Continent co = cont[val];
-			    Vector ct = co.getTerritoriesContained();
-
-			    for (int j=0; j<ct.size(); j++) {
-				if ( ((Country)ct.elementAt(j)).getOwner() == null )  {
-				    name=((Country)ct.elementAt(j)).getColor()+"";
-				    picked = true;
-				    break;
-				}
-			    }
+			int additional = additionalTroopsNeeded(c);
+			if (additional > 0 && additional < player.getExtraArmies() && additional < minNeeded) {
+				minNeeded = additional;
+				priority = c;
 			}
-
-			if (picked == false) {
-			    Continent co = cont[val];
-			    Vector ct = co.getTerritoriesContained();
-
-			    for (int j=0; j<ct.size(); j++) {
-				if ( ((Country)ct.elementAt(j)).getOwner() == null )  {
-				    name=((Country)ct.elementAt(j)).getColor()+"";
-
-// YURA: no idea what this block does but it crashes with:
-// choosemap CRO.map, startgame capital italianlike
-//				    Vector v = ((Country)ct.elementAt(j)).getNeighbours();
-//				    for (int k=0; k<ct.size(); k++) {
-//					if (((Country)v.elementAt(k)).getOwner() != player) {
-//					    name=((Country)ct.elementAt(j)).getColor()+"";
-//					    break;
-//					}
-//				    }
+			border.add(c);
+		}
+		if (priority != null) {
+			border.add(0, priority);
+		}
+		return border;
+	}
+	
+	@Override
+	protected String plan(boolean attack, Vector attackable,
+			GameState gameState, Map targets) {
+		if (game.getSetup()) {
+			Map owned = new HashMap();
+			for (Iterator i = gameState.capitals.iterator(); i.hasNext();) {
+				Country c = (Country) i.next();
+				Integer count = (Integer)owned.get(c.getOwner());
+				if (count == null) {
+					count = Integer.valueOf(1);
+				} else {
+					count = Integer.valueOf(count.intValue() + 1);
 				}
-			    }
+				owned.put(c.getOwner(), count);
 			}
-
-			String str = expandBase(player.getTerritoriesOwned());
-			if( str != null )
-                            name = str;
-
-                        String s = blockOpponent(player);
-                        if( s != null )
-                            name = s;
-
-		        if (name == null)
-			    output = "autoplace";
-
-		        else
-			    output = "placearmies " + name +" 1";
-		    }
-		    else {
-
-			Vector pt = player.getTerritoriesOwned();
-
-			String name=null;
-			Country capital = player.getCapital();
-			if (capital == null)
-			    capital = findCapital();
-
-			for (int a=0; a< pt.size() ; a++) {
-
-			    if ( ownsNeighbours( (Country)pt.elementAt(a)) == false && ((Country)pt.elementAt(a)).getArmies() <= 11 ) {
-                                name=((Country)pt.elementAt(a)).getColor()+"";
-                                break;
-                            }
-
-		            if ( name != null ) { break; }
-
+			double num = gameState.capitals.size();
+			Integer myowned = (Integer) owned.get(player);
+			//offensive planning
+			if (myowned != null && myowned.intValue()/num >= .5) {
+				String result = planCapitalMove(attack, attackable, gameState, targets, null, true);
+				if (result != null) {
+					return result;
+				}
 			}
-
-			String st = attackCapital();
-			if( st != null ) 
-                            name = st;
-
-                        String s = keepBlocking(player);
-                        if( s != null ) 
-                            name = s;
-
-                        String f = freeContinent(player);
-                        if( f != null ) 
-                            name = f;
-
-			String str = reinforceBase(capital);
-			if (str != null)
-			    name = str;
-
-		    if (name == null)
-		    	name = findAttackableTerritory(player);
-		    
-			if ( name == null ) 
-		    	output = "placearmies " + ((Country)pt.elementAt(0)).getColor() +" "+player.getExtraArmies();
-
-//Removed so that it will add armies one at a time, thus reinforcing the base until it has enough defense
-//at which time it will place in other territories as well.  Re-added so that it would not take forever
-//for the computer to place armies. Re-removed after seeing that the time is neglibile.
-		    else if (game.getSetup() ) 
-			    output = "placearmies " + name +" "+player.getExtraArmies();
-
-		    else
-			    output = "placearmies " + name +" 1";
-		    }
-
-		return output;
-
-	}
-
-
-	public String getAttack() {
-
-		String output=null;
-		boolean attackFromCap = player.getCapital().getArmies() > addEnemies(player.getCapital())*2+5; 
-		    boolean chosen = false;
-		    Continent[] cont = game.getContinents();
-		Vector t = player.getTerritoriesOwned();
-		Vector n;
-		Vector options = new Vector();
-		    for (int a=0; a< t.size(); a++) {
-		        if ( ((Country)t.elementAt(a)).getArmies() > 1 ) {
-			    if ( (Country)t.elementAt(a) != player.getCapital() ||
-			    	attackFromCap ) {
-				n = ((Country)t.elementAt(a)).getNeighbours();
-
-				/* attack ratio set to 50% of attack force */
-
-				int ratio = ((Country)t.elementAt(a)).getArmies();
-				for (int b=0; b< n.size() ; b++) {
-				    if ( ((Country)n.elementAt(b)).getOwner() != player && ((Country)n.elementAt(b)).getArmies() + (ratio / 2) < ratio) {
-					//output= "attack " + ((Country)t.elementAt(a)).getColor() + " " + ((Country)n.elementAt(b)).getColor();
-				    	 Vector attack = new Vector();
-			        	 attack.add(((Country)t.elementAt(a)).getColor()+"");
-			        	 attack.add((Country)n.elementAt(b));
-			        	 options.add(attack);
-				    }
+			//defensive planning
+			for (Iterator i = owned.entrySet().iterator(); i.hasNext();) {
+				Map.Entry e = (Entry) i.next();
+				Integer numOwned = (Integer) e.getValue();
+				Player other = (Player) e.getKey();
+				if (other == player || numOwned/num < .5) {
+					continue;
 				}
-			    }
-		        }
-		    }
-		    Player[] playersGreatestToLeast = OrderPlayers(player);
-	    	outer: for (int j=0; j<playersGreatestToLeast.length; j++) {
-	    		for (int i=0; i<options.size(); i++) {
-		    		if ( ((Country) ((Vector)options.get(i)).get(1)).getOwner().equals(playersGreatestToLeast[j])  ) {
-		    			output = "attack " + ((String) ((Vector)options.get(i)).get(0)) + " " + ((Country) ((Vector)options.get(i)).get(1)).getColor();
-		    			break outer;
-		    		}
-		    	}
-		    }
-
-		    /* attempt to attack continent which is almost all owned, if scenario is there */
-
-		    int count = 0;
-		    Country attackfrom = null;
-                    boolean complex = false;
-
-                    for (int i=0; i<cont.length; i++) {
-
-			if ( mostlyOwned( cont[i] ) == true) {
-
-			    n = cont[i].getTerritoriesContained();
-
-			    for (int j=0; j<n.size(); j++) {
-		    	
-				if ( ((Country)n.elementAt(j)).getArmies() > count
-				    && ((Country)n.elementAt(j)).getOwner() == player
-				    && ((Country)n.elementAt(j)) != player.getCapital()) {
-					count = ((Country)n.elementAt(j)).getArmies();
-					attackfrom = (Country)n.elementAt(j);
+				//see what the danger level is
+				int primaryDefense = 0;
+				for (Iterator j = gameState.capitals.iterator(); j.hasNext();) {
+					Country c = (Country) j.next();
+					if (c.getOwner() != other) {
+						primaryDefense+=c.getArmies();
+					}
 				}
-			    }
-
-			    for (int b=0; b< n.size() ; b++) {
-				if ( ((Country)n.elementAt(b)).getOwner() != player && (((Country)n.elementAt(b)).getArmies()+1) < count && attackfrom.isNeighbours((Country)n.elementAt(b)) == true) {
-				    output= "attack " + attackfrom.getColor() + " " + ((Country)n.elementAt(b)).getColor();
-				    complex = true;
-				    break;
+				PlayerState ps = null;
+				for (int j = 0; j < gameState.orderedPlayers.size(); j++) {
+					ps = (PlayerState) gameState.orderedPlayers.get(j);
+					if (ps.p == other) {
+						break;
+					}
+				}
+				boolean highThreat = ps.attackValue > 2*primaryDefense;
+				if (highThreat && gameState.orderedPlayers.size() > 1) {
+					gameState.commonThreat = ps;
+				}
+				if (!attack && highThreat && player.getExtraArmies() > 2 && myowned != null) {
+					//defend capitals more
+					int max = Integer.MIN_VALUE;
+					Country toDefend = null;
+					for (Iterator j = gameState.capitals.iterator(); j.hasNext();) {
+						Country c = (Country) j.next();
+						if (c.getOwner() == player && c.getArmies() > max) {
+							max = c.getArmies();
+							toDefend = c;
+						}
+					}
+					return getPlaceCommand(toDefend, Math.min(player.getExtraArmies() - 2, Math.max(1, (additionalTroopsNeeded(toDefend) + (int)ps.attackValue - 2*primaryDefense)/2)));
+				}
+				if (highThreat || pressAttack(gameState)) {
+					//can we take one
+					String result = planCapitalMove(attack, attackable, gameState, targets, (Player) e.getKey(), false);
+					if (result != null) {
+						return result;
+					}		
 				}
-			    }
+				break;
 			}
-		    }
-
-		    // else attempt to attack continent with the greatest territories owned, that has yet to be conquered.
-
-		    if (complex == false) {
-			int value = 0;
-			Continent choice = null;
-
-			for (int i=0; i<cont.length; i++) {
-
-			    if ( cont[i].isOwned(player) == false) {
-
-				n = cont[i].getTerritoriesContained();
+		} else if (r.nextInt(game.getPlayers().size()) == 0) {
+			Country c = findCapital();
+			return getPlaceCommand(c, 1);
+		}
+		return super.plan(attack, attackable, gameState, targets);
+	}
 
-				int check = 0;
-				for (int j=0; j<n.size(); j++) {
-				     if ( ((Country)n.elementAt(j)).getOwner() == player && (((Country)n.elementAt(j)) != player.getCapital() || attackFromCap))
-					check++;
+	private String planCapitalMove(boolean attack, Vector attackable,
+			GameState gameState, Map targets, Player target, boolean allOrNone) {
+		int remaining = player.getExtraArmies();
+		List toAttack = new ArrayList();
+		for (Iterator i = gameState.capitals.iterator(); i.hasNext();) {
+			Country c = (Country) i.next();
+			if (c.getOwner() == player || (target != null && target != c.getOwner())) {
+				continue;
+			}
+			AttackTarget at = (AttackTarget) targets.get(c);
+			if (at == null) {
+				if (allOrNone) {
+					return null;
 				}
-
-				if (check > value)
-				    choice = cont[i];
-			    }
+				continue;
 			}
-
-			if (choice !=null) {
-
-                            //System.out.println(choice.getName()); TESTING
-			    n = ((Continent)choice).getTerritoriesContained();
-
-			    for (int j=0; j<n.size(); j++) {
-
-				if ( ((Country)n.elementAt(j)).getArmies() > count
-				    && ((Country)n.elementAt(j)).getOwner() == player
-				    && (((Country)n.elementAt(j)) != player.getCapital() || attackFromCap)) {
-				    count = ((Country)n.elementAt(j)).getArmies();
-				    attackfrom = (Country)n.elementAt(j);
+			if (at.remaining < 1) {
+				remaining += at.remaining;
+				if (remaining < 1 && allOrNone) {
+					return null;
 				}
-			    }
-
-			    for (int b=0; b< n.size() ; b++) {
-				if ( ((Country)n.elementAt(b)).getOwner() != player && (((Country)n.elementAt(b)).getArmies()+1) < count && attackfrom.isNeighbours((Country)n.elementAt(b)) == true ) {
-				    output= "attack " + attackfrom.getColor() + " " + ((Country)n.elementAt(b)).getColor();
-                                    break;
+				if (!attack && !allOrNone) {
+					toAttack.add(at);
 				}
-			    }
+			} else if (attack) {
+				toAttack.add(at);
 			}
-		    }
-
-            Vector continentsToBreak = GetContinentsToBreak(player);
-            String tmp = null;
-            
-            //Attempt to find a path to the continent - distance of 1, then 2, then 3 away.
-            if (continentsToBreak != null) {
-         	   outer: for (int q=1; q<4; q++) { 
-         		   for (int i=0; i<continentsToBreak.size(); i++) {
-             		   for (int j=0; j<t.size(); j++) {
-             			   Vector tNeighbors = ((Country)t.get(j)).getNeighbours();
-             			   for (int k=0; k<tNeighbors.size(); k++) {
-             				   if (((Country)t.get(j)).getArmies()-1 > ((Country)tNeighbors.get(k)).getArmies() &&
-             						   ShortPathToContinent((Continent)continentsToBreak.get(i), (Country)t.get(j), (Country)tNeighbors.get(k), q)  &&
-             						  (((Country)t.get(j)).getColor() != player.getCapital().getColor() || attackFromCap)) {
-             					   tmp = "attack " + ((Country)t.get(j)).getColor() + " " + ((Country)tNeighbors.get(k)).getColor();
-             					   break outer;
-             				   }
-             						   
-             			   }
-             		   }
-             	   }
-         	   }
-            }
-            if (tmp != null)
-         	   output = tmp;
-		    
-		    
-		    
-		    // check to see if there are any players to eliminate
-
-		    Vector players = game.getPlayers();
-                    Vector cankill = new Vector();
-
-                    for (int i=0; i<players.size(); i++) {
-			if (( (Player) players.elementAt(i)).getNoTerritoriesOwned() < 3 && ( (Player) players.elementAt(i)) != player)
-			    cankill.addElement((Player) players.elementAt(i));
-                    }
-
-		    if (cankill.size() > 0) {
-			for (int i=0; i<cankill.size(); i++) {
-			Vector territories = ((Player) cankill.elementAt(i)).getTerritoriesOwned();
-			for (int j=0; j<territories.size(); j++) {
-
-			    Vector neighbours = ((Country)territories.elementAt(j)).getNeighbours();
-                            for (int k=0; k<neighbours.size(); k++) {
-				if (((Country) neighbours.elementAt(k)).getOwner() == player
-				    && (((Country)territories.elementAt(j)).getArmies() + 1 < ((Country) neighbours.elementAt(k)).getArmies())
-				    && ((Country) neighbours.elementAt(k) != player.getCapital() || attackFromCap)
-				    &&  ((Country) neighbours.elementAt(k)).isNeighbours((Country)territories.elementAt(j))) {
-				    output= "attack " + ((Country) neighbours.elementAt(k)).getColor() + " " + ((Country)territories.elementAt(j)).getColor();
-                                    //System.out.println("eliminate: " + output); TESTING
-                                    break;
-				}
-			    }
+		}	
+		if (!toAttack.isEmpty()) {
+			if (allOrNone) {
+				Collections.sort(toAttack); //hardest first
+			} else {
+				Collections.sort(toAttack, Collections.reverseOrder()); 
 			}
-		    }
-		}
-
-
-		if ( output==null ) {
-		    output="endattack";
+			AttackTarget at = (AttackTarget)toAttack.get(0);
+			int route = findBestRoute(attackable, gameState, attack, null, at, (Player)gameState.targetPlayers.get(0), targets);
+			Country start = (Country) attackable.get(route);
+			if (attack) {
+				return getAttack(targets, at, route, start);
+			}
+			return getPlaceCommand(start, -at.remaining + 1);
 		}
-
-		return output;
-
+		return null;
 	}
 
-
-	public String getBattleWon() {
-
-		String output;
-
-		   /* Attempt to safeguard critical areas when moving armies to won country */
-
-		   Country attacker = game.getAttacker();
-		   Continent continent = attacker.getContinent();
-		   //If attacking from the capital, try to leave enough defense.
-		   if (attacker.getColor() == player.getCapital().getColor()) {
-			   if (attacker.getArmies() >= addEnemies(player.getCapital())*2 + 3)
-				   output = "move " + (attacker.getArmies() - (addEnemies(player.getCapital())*2 + 1));
-			   else 
-				   output = "move " + (attacker.getArmies()-1);
-		   }
-		   else if (continent.isOwned(player) == true || mostlyOwned(continent) == true) {
-
-		       /* Set 50% security limit */
-		       if (attacker.getArmies() > 6)
-		   	   output = "move " + (attacker.getArmies()-1);
-
-		       else if (attacker.getArmies() > 3 && attacker.getArmies() <= 6)
-			   output = "move " + (attacker.getArmies()-1);
-
-		       else
-			   output = "move all";
-                   }
-		   else {
-		      output="move all";
-		   }
-
-		return output;
-
+	protected String getBattleWon(GameState gameState) {
+		if (gameState.capitals.contains(game.getAttacker())) {
+			int needed = additionalTroopsNeeded(game.getAttacker());
+			if (needed > 0) {
+				return "move " + game.getMustMove();
+			}
+			return "move " + Math.max(game.getMustMove(), -needed/2 - getMinPlacement());
+		}
+		if (gameState.capitals.contains(game.getDefender())
+				&& (ownsNeighbours(player, game.getAttacker()) || !ownsNeighbours(player, game.getDefender()))) {
+			return "move all";
+		}
+		return super.getBattleWon(gameState);
 	}
-
-
-
+	
 	public String getCapital() {
-
 		return "capital " + findCapital().getColor();
-
-	}
-
-	/**
-	 * Returns the number of armies in most fortified neighbor.  If player owns all of the countries around it,
-	 * return 1, because there is still a potential for a threat
-	 * @param Country c which is the country that you want to know the enemies of the given player that are around
-	 * @return int with the number of Enemies around or 1, whichever is higher.
-	 */
-	public int addEnemies(Country c) {
-
-		int nearbyEnemies = 0;
-		//Country cap = player.getCapital();
-		Country[] countries = game.getCountries();
-		for (int j=0; j<countries.length; j++) {
-			if (countries[j].isNeighbours(c) && countries[j].getOwner() != player)
-				if (countries[j].getArmies() > nearbyEnemies)
-					nearbyEnemies = countries[j].getArmies();
-		}
-		return nearbyEnemies == 0 ? 1 : nearbyEnemies;
 	}
 	
-	/**
-	 * Checks if the player's capital has enough armies and checks if its neighbours has enough armies
-	 * @param capital The capital country
-	 * @return String Returns the name of the capital
-	 */
-	public String reinforceBase(Country capital) {
-	 String str = null;
-	 boolean foundCap = false;
-	 Vector players = game.getPlayers();
-	 //Reinforce base if there are not 3 times the number of surrounding enemies present.
-	 for (int i=0; i<players.size(); i++) {
-	    Player p2 = (Player) players.elementAt(i);
-	    Country cap = p2.getCapital();
-	    if (p2 == player)
-		cap = capital;
-	    if (cap != null && cap.getOwner() == player) {
-	    	if (cap.getArmies() < addEnemies(player.getCapital())*2 && cap.getArmies() < 50) {
-		        str = cap.getColor()+"";
-			    foundCap = true;
-			    break;
-	    	}
-	    }
-	 }
-
-	 if (foundCap == false) {
-	    boolean found = false;
-	    for (int i=0; i<players.size(); i++) {
-		Player p2 = (Player) players.elementAt(i);
-		Country cap = p2.getCapital();
-		if (p2 == player)
-		    cap = capital;
-		if (cap != null && cap.getOwner() == player) {
-		    Vector v = cap.getNeighbours();
-		    for (int j=0; j<v.size(); j++) {
-			Country c = (Country) v.elementAt(j);
-			if (c.getOwner() == player && c.getArmies() < 4) {
-			    str = c.getColor()+"";
-			    found = true;
-			    break;
+	protected Country findCapital() {
+		int score = Integer.MAX_VALUE;
+		Country result = null;
+		Vector v = player.getTerritoriesOwned();
+		for (int i = 0; i < v.size(); i++) {
+			Country c = (Country)v.get(i);
+			int val = scoreCountry(c);
+			val -= c.getArmies()/game.getPlayers().size();
+			if (val < score || (val == score && r.nextBoolean())) {
+				score = val;
+				result = c;
 			}
-		    }
 		}
-		if (found == true)
-		    break;
-    	    }
-         }
-         return str;
+		return result;
 	}
-
-
-	/**
-	 * get the best capital position for the current player
-	 *
-	 */
-	public Country findCapital() {
-
-		// TODO someone needs to document how this is working!
-
-		Vector pt = player.getTerritoriesOwned();
-		Country country = null;
-		int difference1 = Integer.MAX_VALUE;
-		int difference2 = Integer.MAX_VALUE;
-
-		for (int i=0; i<pt.size(); i++) {
-
-			int count = 0;
-			Country c1 = (Country) pt.elementAt(i);
-			Vector v = c1.getNeighbours();
-
-			for (int j=0; j<v.size(); j++) {
-				Country c2 = (Country) v.elementAt(j);
-				if (c2.getOwner() == player) {
-					count++;
-				}
-			}
-
-			int diff1 = v.size() - count;
-			int diff2 = addEnemies(c1) - c1.getArmies();
-
-			if (diff1 <= difference1 && diff2 <= difference2) {
-
-				difference1 = diff1;
-				difference2 = diff2;
-
-				country = c1;
-			}
-			// count = 0; // ??? wtf is this for ???
+	
+	@Override
+	protected double getContinentValue(Continent co) {
+		double value = super.getContinentValue(co);
+		if (!game.getSetup()) {
+			//blunt the affect of continent modification
+			return Math.sqrt(value);
 		}
-
-//		Country country = pt.size() > 0 ? (Country)pt.get(0) : null;
-//		for (int i=0; i<pt.size(); i++) {
-//			Country tmp = (Country)pt.get(i);
-//			if (tmp.getArmies() > country.getArmies())
-//				country = tmp;
-//		}
-		return country;
-
+		return super.getContinentValue(co);
 	}
 
-    /**
-     * Checks through the enemy's capital and finds a neighbouring territory owned by the reinforcing player
-     * @return String Returns the name of the reinforcing territory
-     */
-    public String attackCapital() {
-	String str = null;
-	Vector players = game.getPlayers();
-	Country capital = null;
-	for (int i=0; i<players.size(); i++) {
-	    Player p2 = (Player) players.elementAt(i);
-	    capital = p2.getCapital();
-	    if (capital != null && capital.getOwner() != player)
-	    	break;
-    	}
-    	if (capital != null) {
-	    Vector v = capital.getNeighbours();
-	    for (int i=0; i<v.size(); i++) {
-		Country c = (Country) v.elementAt(i);
-		if (c.getOwner() == player && c.isNeighbours(capital)) {
-		    str = c.getColor()+"";
-		    break;
-	        }
-	    }
-        }
-        return str;
-    }
-
-    /**
-     * Checks through the player's current owned territories and picks a neighbour if it is free
-     * @param pt The player's territories
-     * @return String Returns the name of the country if found, returns null otherwise
-     */
-    public String expandBase(Vector pt) {
-        String str = null;
-	boolean found = false;
-	for (int i=0; i<pt.size(); i++) {
-	    Country c1 = (Country) pt.elementAt(i);
-	    Vector v = c1.getNeighbours();
-	    for (int j=0; j<v.size(); j++) {
-		Country c2 = (Country) v.elementAt(j);
-		if (c2.getOwner() == null) {
-		    str = c2.getColor()+"";
-		    found = true;
-		    break;
-	        }
-            }
-	    if (found == true)
-	        break;
-        }
-        return str;
-    }
-
-    public String getRoll() {
-
-		String output;
-
-		int n=((Country)game.getAttacker()).getArmies() - 1;
-
-
-		/* Only roll for as long as while attacking player has more armies than defending player */
-		int m=((Country)game.getDefender()).getArmies();
-
-		if (((Country)game.getAttacker()).getColor() == player.getCapital().getColor()) {
-			if (player.getCapital().getArmies() > addEnemies(player.getCapital())*2+5)
-				output = "roll "+3;
-			else
-				output = "retreat";
-		} 
-		else if (n > 3 && n > m) {
-		    output= "roll "+3;
-		}
-		else if (n <= 3 && n > m) {
-		    output= "roll "+n;
-		}
-		else {
-		    output= "retreat";
-		}
-
-		return output;
-
-    }
-
-    public String getTacMove() {
-
-		String output=null;
-
-		    /* reinforces armies from less critical to more critical areas */
-
-		    Vector t = player.getTerritoriesOwned();
-		    Vector n;
-		    boolean possible = false;
-                    int difference = 0;
-                    Country sender = null;
-                    Country receiver = null;
-                    Country temp = null;
-                    int highest = 1;
-
-		    for (int a=0; a<t.size(); a++) {
-
-			Country country = ((Country)t.elementAt(a));
-			difference  = country.getArmies();
-			if (difference > highest && country.getColor() != player.getCapital().getColor())  {
-			    highest = difference;
-			    sender = country;
-			}
-		    }
-
-		    if (sender != null)  {
-
-			receiver = check1(sender);
-
-			if (receiver == null) {
-			    n = sender.getNeighbours();
-			    for (int i=0; i<n.size(); i++) {
-				temp = (Country) n.elementAt(i);
-				if (temp.getOwner() == player) {
-				    possible = check2(temp);
-				}
-				if (possible == true)  { receiver = temp; break; }
-			    }
-			}
-		    }
-
-		    if (receiver != null && receiver != sender) {
-			output= "movearmies " + ((Country)sender).getColor() + " " + ((Country)receiver).getColor() + " " + (((Country)sender).getArmies()-1);
-			//System.out.println(((Country)sender).getName()); TESTING
-			//System.out.println(((Country)receiver).getName()); TESTING
-		    }
-
-		    if ( output == null ) {
-			output = "nomove";
-		    }
-
-		return output;
-
-    }
-
-    
 }
Index: src/net/yura/domination/engine/ai/AICrap.java
===================================================================
--- src/net/yura/domination/engine/ai/AICrap.java	(revision 1057)
+++ src/net/yura/domination/engine/ai/AICrap.java	(working copy)
@@ -34,78 +34,48 @@
 
     }
 
-    public String getTrade() {
-
-	  Vector cards = player.getCards();
-
-	  if (cards.size() >= 3 && !( game.getTradeCap()==true && cards.size() < 5 ) ) {
-
-	    Card card1=null, card2=null, card3=null;
-
-	    for (int a=0; a< cards.size() ; a++) {
-		if (card1 != null && card2 != null && card3 != null) { break; }
-		card1 = (Card)cards.elementAt(a);
-
-		for (int b=(a+1); b< cards.size() ; b++) {
-		    if (card1 != null && card2 != null && card3 != null) { break; }
-		    card2 = (Card)cards.elementAt(b);
-
-		    for (int c=(b+1); c< cards.size() ; c++) {
-			if (card1 != null && card2 != null && card3 != null) { break; }
-			card3 = (Card)cards.elementAt(c);
+	public String getTrade() {
 
-			if ( game.checkTrade(card1, card2, card3) ) { break; }
-			else { card3=null; }
+		Vector cards = player.getCards();
 
-		    }
+		if (cards.size() < 3) {
+			return "endtrade";
 		}
-	    }
-
-
-	    if (card3 != null) {
-
-		String output = "trade ";
-
-		  if (card1.getName().equals("wildcard")) { output = output + card1.getName(); }
-		  else { output = output + ((Country)card1.getCountry()).getColor(); }
 
-		output = output+" ";
+		Card[] result = game.getBestTrade(cards, tradeCombinationsToScan());
 
-		  if (card2.getName().equals("wildcard")) { output = output + card2.getName(); }
-		  else { output = output + ((Country)card2.getCountry()).getColor(); }
+		if (result != null) {
+			String output = "trade ";
+			output = getCardName(result[0], output);
+			output = output + " ";
+			output = getCardName(result[1], output);
+			output = output + " ";
+			output = getCardName(result[2], output);
+			return output;
+		}
 
-		output = output+" ";
+		return "endtrade";
+	}
 
-		  if (card3.getName().equals("wildcard")) { output = output + card3.getName(); }
-		  else { output = output + ((Country)card3.getCountry()).getColor(); }
+	public int tradeCombinationsToScan() {
+		return 1;
+	}
 
+	private String getCardName(Card card1, String output) {
+		if (card1.getName().equals("wildcard")) {
+			output = output + card1.getName();
+		} else {
+			output = output + card1.getCountry().getColor();
+		}
 		return output;
-
-	    }
-
-	    return "endtrade";
-	  }
-
-	  return "endtrade";
-
-    }
+	}
 
     public String getPlaceArmies() {
-
 		if ( game.NoEmptyCountries()==false ) {
 		    return "autoplace";
 		}
-		else {
-		    Vector t = player.getTerritoriesOwned();
-		    Vector n;
-		    String name=null;
-		    Random rand = new Random();
-//			if (game.getSetup())
-//				return "placearmies " + ((Country)t.elementAt(rand.nextInt(t.size()))).getColor() +" "+player.getExtraArmies();
-//			else 
-				return "placearmies " + ((Country)t.elementAt(rand.nextInt(t.size()))).getColor() +" 1";
-		}
-
+	    Vector t = player.getTerritoriesOwned();
+		return "placearmies " + randomCountry(player.getTerritoriesOwned()).getColor() +" 1";
     }
 
     public String getAttack() {
@@ -121,44 +91,58 @@
     }
 
     public String getCapital() {
-
-	    Vector t = player.getTerritoriesOwned();
-	    return "capital " + ((Country)t.elementAt( r.nextInt(t.size()) )).getColor();
-
+	    return "capital " + randomCountry(player.getTerritoriesOwned()).getColor();
     }
-
+    
+    public Country randomCountry(Vector countries) {
+    	if (countries.isEmpty()) {
+    		return null;
+    	}
+    	return (Country)countries.elementAt( r.nextInt(countries.size()) );
+    }
 
 	public String getAutoDefendString() {
-
-	    int n=((Country)game.getDefender()).getArmies();
-
-            if (n > game.getMaxDefendDice()) {
-                return "roll "+game.getMaxDefendDice();
-            }
-
-	    return "roll "+n;
+	    int n=game.getDefender().getArmies();
+        return "roll "+Math.min(game.getMaxDefendDice(), n);
 	}
 
     /**
-     * Attempts to find the first territory that can be used to attack from
+     * Finds all countries that can be attacked from excluding the capitol
      * @param p player object
-     * @return Sring name is a move to attack from any space they can (that has less than 500 armies)
-     * else returns null
+     * @return a Vector of countries, never null
      */
-    public String findAttackableTerritory(Player p) {
+    public Vector findAttackableTerritories(Player p, boolean attack) {
     	Vector countries = p.getTerritoriesOwned();
-    	
+    	Vector result = new Vector();
     	for (int i=0; i<countries.size(); i++) {
-    		Vector neighbors = ((Country)countries.elementAt(i)).getNeighbours();
-    		for (int j=0; j<neighbors.size(); j++) {
-    			if (((Country)neighbors.elementAt(j)).getOwner() != p) {
-    				if ((p.getCapital() != null && ((Country)countries.elementAt(i)).getColor() != p.getCapital().getColor()) || p.getCapital() == null)
-    					return ((Country)countries.elementAt(i)).getColor()+"";
-    			}
+    		Country country = (Country)countries.elementAt(i);
+    		if ((!attack || country.getArmies() > 1) && !ownsNeighbours(p, country)) {
+				result.add(country);
     		}
     	}
-    	
-    	return null;
+    	return result;
     }
+    
+    /**
+     * Checks whether a country owns its neighbours
+     * @param p player object, c Country object
+     * @return boolean True if the country owns its neighbours, else returns false
+     */
+    public boolean ownsNeighbours(Player p, Country c) {
+        Vector neighbours = c.getNeighbours();
+
+        for (int i=0; i<neighbours.size(); i++) {
+           if ( ((Country) neighbours.elementAt(i)).getOwner() != p) {
+        	   return false;
+           }
+        }
+
+        return true;
+    }
+    
+    public void setPlayer(RiskGame game) {
+    	this.game = game;
+    	this.player = game.getCurrentPlayer();
+    }
 
 }
Index: src/net/yura/domination/engine/ai/AIHardMission.java
===================================================================
--- src/net/yura/domination/engine/ai/AIHardMission.java	(revision 1057)
+++ src/net/yura/domination/engine/ai/AIHardMission.java	(working copy)
@@ -2,355 +2,93 @@
 
 package net.yura.domination.engine.ai;
 
+import java.util.Arrays;
 import java.util.Vector;
+
 import net.yura.domination.engine.core.Continent;
 import net.yura.domination.engine.core.Country;
-import net.yura.domination.engine.core.Mission;
 import net.yura.domination.engine.core.Player;
 
 
 /**
  * <p> Class for AIHardPlayer </p>
  * @author SE Group D
+ * TODO infer the other missions
  */
 
 public class AIHardMission extends AIHard {
 
-	public String getPlaceArmies() {
-
-		String output=null;
-
-	           if ( game.NoEmptyCountries()==false ) {
-                       String name=null;
-                       Mission m = player.getMission();
-
-                       /* - Mission Types
-                       Mission type A - conquer X continent
-                       Mission type B - Occupy X territories, each with atleast Y armies
-                       Mission type C - Destroy all of player X's troops. If you are
-                                        player X, then your mission is: occupy Y territories
-                       */
-
-                       /* initial placement strategy for mission type A */
-
-                       if (m.getContinent1() != null && m.getContinent2() != null) {
-
-                          Continent c1 = m.getContinent1();
-                          Continent c2 = m.getContinent2();
-
-                          name = missionPlacement0(c1);
-
-                          if (name == null)
-                             name = missionPlacement0(c2);
-                       }
-
-                       if (m.getContinent1() != null && m.getContinent2() == null) {
-                          Continent c1 = m.getContinent1();
-                          name = missionPlacement0(c1);
-                       }
-
-                       /* initial placement strategy for mission type B */
-
-                       /*  ...as usual at present..... */
-
-                       /* initial placement strategy for mission type C */
-
-                       if (m.getPlayer() != null && m.getPlayer() != player && playerKilled(player) ) {
-
-                          Vector enemy = ((Player) m.getPlayer()).getTerritoriesOwned();
-                          for (int i=0; i<enemy.size(); i++) {
-                             Vector neighbours = ((Country) enemy.elementAt(i)).getNeighbours();
-                             for (int j=0; j<neighbours.size(); j++) {
-                                 if ( ((Country) neighbours.elementAt(j)).getOwner() == null)
-                                      name = ((Country)neighbours.elementAt(j)).getColor()+"";
-                             }
-                          }
-                       }
-
-                       if (m.getPlayer() != null && m.getPlayer() == player)
-                          /* ...as usual at present.... */
-
-                       if (name == null)
-                          output = "autoplace";
-                       else
-                          output = "placearmies " + name +" 1";
-	           }
-
-	           else {
-		       String name=null;
-                       Mission m = player.getMission();
-                       Vector t = player.getTerritoriesOwned();
-
-                       /* game placement strategy for mission type A */
-
-                       if (m.getContinent1() != null && m.getContinent2() != null) {
-
-                          Continent c1 = m.getContinent1();
-                          Continent c2 = m.getContinent2();
-
-                          name = missionPlacement1(c1);
-
-                          if (name == null)
-                             name = missionPlacement1(c2);
-
-                          if (name == null)
-                             name = missionPlacement2(c1);
-
-                          if (name == null)
-                             name = missionPlacement2(c2);
-
-                       }
-
-                       if (m.getContinent1() != null && m.getContinent2() == null) {
-
-                          Continent c1 = m.getContinent1();
-                          name = missionPlacement1(c1);
-
-                          if (name == null)
-                             name = missionPlacement2(c1);
-                       }
-
-                        /* game placement strategy for mission type B */
-
-                       /*  ...as usual at present..... */
-
-                       /* game placement strategy for mission type c */
-
-                       if (m.getPlayer() != null && m.getPlayer() != player && playerKilled(player) ) {
-                          Vector enemy = ((Player) m.getPlayer()).getTerritoriesOwned();
-                          for (int i=0; i<enemy.size(); i++) {
-                             Vector neighbours = ((Country) enemy.elementAt(i)).getNeighbours();
-                             for (int j=0; j<neighbours.size(); j++) {
-                                 if ( ((Country) neighbours.elementAt(j)).getOwner() == player && ((Country) neighbours.elementAt(j)).getArmies() < 5) {
-                                      name = ((Country)neighbours.elementAt(j)).getColor()+"";
-                                      break;
-                                 }
-                             }
-                          }
-                       }
-
-                       if (m.getPlayer() != null && m.getPlayer() == player) {;}
-
-
-                       if (name == null) {
-                           Vector n;
-
-                           for (int a=0; a< t.size() ; a++) {
-
-			      n = ((Country)t.elementAt(a)).getNeighbours();
-
-			      for (int b=0; b< n.size() ; b++) {
-			          if ( ((Country)n.elementAt(b)).getOwner() != player ) { name=((Country)t.elementAt(a)).getColor()+""; break; }
-			      }
-
-			      if ( name != null ) { break; }
-
-		          }
-                       }
-                       //System.out.println(m.getDiscription()); TESTING
-
-		       if ( name == null )
-			   output = "placearmies " + ((Country)t.elementAt(0)).getColor() +" "+player.getExtraArmies()  ;
-
-		       else if (game.getSetup() )
-			   output = "placearmies " + name +" "+player.getExtraArmies();
-
-		       else
-		   	   output = "placearmies " + name +" 1";
-	           }
-
-		return output;
-
+	protected Vector getBorder(GameState gs) {
+		Vector result = super.getBorder(gs);
+		if (player.getMission().getNoofarmies() > 1 
+				&& (player.getTerritoriesOwned().size()*2 > player.getMission().getNoofcountries() && pressAttack(gs) || player.getTerritoriesOwned().size() - 3 >= player.getMission().getNoofcountries())) {
+			//this is redundant, but that's ok, what matters is the absolute ordering
+			result.addAll(player.getTerritoriesOwned());
+		}
+		return result;
 	}
-
-
-	public String getAttack() {
-
-		String output=null;
-
-		Vector t = player.getTerritoriesOwned();
-		Vector n;
-
-               for (int a=0; a< t.size() ; a++) {
-	          if ( ((Country)t.elementAt(a)).getArmies() > 1 ) {
-		     n = ((Country)t.elementAt(a)).getNeighbours();
-
-                     /* attack ratio set to 50% of attack force */
-
-                     int ratio = ((Country)t.elementAt(a)).getArmies();
-		     for (int b=0; b< n.size() ; b++) {
-			if ( ((Country)n.elementAt(b)).getOwner() != player && ((Country)n.elementAt(b)).getArmies() + (ratio / 2) < ratio  ) {
-                            output= "attack " + ((Country)t.elementAt(a)).getColor() + " " + ((Country)n.elementAt(b)).getColor();
-	                }
-		     }
-                  }
-               }
-
-               Mission m = player.getMission();
-
-               /* - Mission Types
-               Mission type A - conquer X continent
-               Mission type B - Occupy X territories, each with atleast Y armies
-               Mission type C - Destroy all of player X's troops. If you are
-                                        player X, then your mission is: occupy Y territories
-               */
-
-               /* attacking strategy for mission type A */
-
-               if ( (m.getContinent1() != null && m.getContinent2() != null) ) {
-
-               boolean done = false;
-
-                  for (int i=0; i<t.size(); i++) {
-                     Country s = (Country) t.elementAt(i);
-                     if (s.getContinent() == m.getContinent1() && ((Continent) m.getContinent1()).isOwned(player) == false) {
-                         Vector neighbours = s.getNeighbours();
-                         for (int j=0; j<neighbours.size(); j++) {
-                            Country r = (Country) neighbours.elementAt(j);
-                            if (r.getOwner() != player && r.getArmies() < s.getArmies()-1) {
-                               output= "attack " + s.getColor() + " " + r.getColor();
-                               done = true;
-                            }
-                         }
-                     }
-                  }
-
-                  if (done == false) {
-                     for (int i=0; i<t.size(); i++) {
-                        Country s = (Country) t.elementAt(i);
-                        if (s.getContinent() == m.getContinent2() && ((Continent) m.getContinent2()).isOwned(player) == false) {
-                            Vector neighbours = s.getNeighbours();
-                            for (int j=0; j<neighbours.size(); j++) {
-                               Country r = (Country) neighbours.elementAt(j);
-                               if (r.getOwner() != player && r.getArmies() < s.getArmies()-1)
-                                  output= "attack " + s.getColor() + " " + r.getColor();
-                            }
-                        }
-                     }
-                  }
-               }
-
-               if ( (m.getContinent1() != null && m.getContinent2() == null) ) {
-                  for (int i=0; i<t.size(); i++) {
-                     Country s = (Country) t.elementAt(i);
-                     if (s.getContinent() == m.getContinent1() && ((Continent) m.getContinent1()).isOwned(player) == false) {
-                         Vector neighbours = s.getNeighbours();
-                         for (int j=0; j<neighbours.size(); j++) {
-                            Country r = (Country) neighbours.elementAt(j);
-                            if (r.getOwner() != player && r.getArmies() < s.getArmies()-1)
-                               output= "attack " + s.getColor() + " " + r.getColor();
-                         }
-                     }
-                  }
-               }
-
-               /* attacking strategy for mission type C */
-
-               if (m.getPlayer() != null && m.getPlayer() != player && playerKilled(player)) {
-                  for (int i=0; i<t.size(); i++) {
-                     Country s = (Country) t.elementAt(i);
-                     Vector neighbours = s.getNeighbours();
-                     for (int j=0; j<neighbours.size(); j++) {
-                        Country r = (Country) neighbours.elementAt(j);
-                        if (r.getOwner() == m.getPlayer() && r.getArmies() < s.getArmies()-1)
-                               output= "attack " + s.getColor() + " " + r.getColor();
-                     }
-                  }
-               }
-
-            if ( output==null ) {
-		  output="endattack";
-            }
-
-		return output;
-
+	
+	protected boolean shouldEndAttack(GameState gameState) {
+		boolean result = super.shouldEndAttack(gameState);
+		if (result && isCloseToTerritoryTarget()) {
+			return false;
+		}
+		return result;
 	}
-
-
-
-	public String getBattleWon() {
-
-		String output;
-
-                  Country attacker = game.getAttacker();
-                  Mission m = player.getMission();
-                  //System.out.println("Check 1"); TESTING
-
-                  if ( m.getNoofarmies() > 1 && attacker.getArmies() > m.getNoofarmies() && (attacker.getArmies()-m.getNoofarmies()) >= game.getMustMove() ) {
-                      output = "move " + (attacker.getArmies()-m.getNoofarmies());
-                  }
-                  else {
-                     output = "move all";
-		  }
-
-		return output;
-
+	
+	protected int scoreCountry(Country country) {
+		int result = super.scoreCountry(country);
+		if (player.getMission().getPlayer() != null && !isTargetMoot()) {
+			Vector n = country.getNeighbours();
+			for (int i = 0; i < n.size(); i++) {
+				Country nc = (Country)n.get(i);
+				if (nc.getOwner() == player.getMission().getPlayer()) {
+					result--;
+				}
+			}
+		}
+		return result;
 	}
-
-
-    /**
-     * Checks if the player can choose a country in a continent in Mission Risk
-     * @param p player object, c Continent object
-     * @return String name
-     */
-    public String missionPlacement0(Continent c) {
-
-        String name = null;
-        Vector territories = c.getTerritoriesContained();
-
-        for (int i=0; i<territories.size(); i++) {
-           if ( ((Country)territories.elementAt(i)).getOwner() == null && ((Country) territories.elementAt(i)).getArmies() < 13 ) {
-               name = ((Country)territories.elementAt(i)).getColor()+"";
-               break;
-           }
-        }
-        return name;
-     }
-
-
-    /**
-     * Checks if the player can place armies in a continent in Mission Risk
-     * @param p player object, c Continent object
-     * @return String name
-     */
-    public String missionPlacement1(Continent c) {
-
-        String name = null;
-        Vector territories = c.getTerritoriesContained();
-
-        for (int i=0; i<territories.size(); i++) {
-           if ( ((Country)territories.elementAt(i)).getOwner() == player && ((Country) territories.elementAt(i)).getArmies() < 13
-              && ownsNeighbours( (Country)territories.elementAt(i)) == false ) {
-               name = ((Country)territories.elementAt(i)).getColor()+"";
-               break;
-           }
-        }
-        return name;
-     }
-
-    /**
-     * Checks if the player can place armies in a adjacent territory in Mission Risk
-     * @param p player object, c Continent object
-     * @return String name
-     */
-    public String missionPlacement2(Continent c) {
-
-        String name = null;
-        Vector territories = c.getTerritoriesContained();
-
-        for (int i=0; i<territories.size(); i++) {
-           Vector neighbours = ((Country)territories.elementAt(i)).getNeighbours();
-           for (int j=0; j<neighbours.size(); j++) {
-             if ( ((Country) neighbours.elementAt(j)).getOwner() == player && ((Country) neighbours.elementAt(j)).getArmies() < 13
-                && ownsNeighbours( (Country)territories.elementAt(i)) == false ) {
-                 name = ((Country) neighbours.elementAt(j)).getColor()+"";
-                 break;
-             }
-           }
-        }
-        return name;
-     }
-
-
+	
+	private boolean isCloseToTerritoryTarget() {
+		return player.getMission().getNoofcountries() > 0 
+		&& (player.getMission().getPlayer() == null || isTargetMoot())
+		&& player.getTerritoriesOwned().size() - 3 >= player.getMission().getNoofcountries();
+	}
+	
+	protected boolean pressAttack(GameState gameState) {
+		boolean result = super.pressAttack(gameState);
+		if (!result && isCloseToTerritoryTarget()) {
+			return true;
+		}
+		return result;
+	}
+	
+	protected int getMinPlacement() {
+		return Math.max(1, player.getMission().getNoofarmies());
+	}
+	
+	public GameState getGameState(Player p) {
+		GameState g = super.getGameState(p);
+		if (player.getMission().getPlayer() != null && !isTargetMoot() && player.getMission().getPlayer() != ((PlayerState)g.orderedPlayers.get(0)).p) {
+			g.targetPlayers = Arrays.asList(new Object[] {player.getMission().getPlayer(), ((PlayerState)g.orderedPlayers.get(0)).p});
+		}
+		return g;
+	}
+	
+	private boolean isTargetMoot() {
+		return player.getMission().getPlayer() != null && (player.getMission().getPlayer() == player || player.getMission().getPlayer().getTerritoriesOwned().isEmpty());
+	}
+	
+	protected double getContinentValue(Continent co) {
+		double result = super.getContinentValue(co);
+		if (player.getMission().getContinent1() == co
+				|| player.getMission().getContinent2() == co
+				|| player.getMission().getContinent3() == co
+				) {
+			result *= 4;
+		}
+		return result;
+	}
 
 }
Index: src/net/yura/domination/engine/ai/AIEasy.java
===================================================================
--- src/net/yura/domination/engine/ai/AIEasy.java	(revision 1057)
+++ src/net/yura/domination/engine/ai/AIEasy.java	(working copy)
@@ -3,6 +3,7 @@
 package net.yura.domination.engine.ai;
 
 import java.util.Vector;
+
 import net.yura.domination.engine.core.Country;
 
 /**
@@ -12,161 +13,57 @@
 
 public class AIEasy extends AICrap {
 
-    protected class Attack {
-	Country source;
-	Country destination;
-
-	public Attack(Country s, Country d){
-	    source=s;
-	    destination=d;
-	}
-	public String toString(){
-	    if (source == null || destination == null) { return ""; }
-	    return "attack " + source.getColor() + " " + destination.getColor();
-	}
-
-    }
-
     public String getPlaceArmies() {
-
 		if ( game.NoEmptyCountries()==false ) {
 		    return "autoplace";
 		}
-		else {
-		    Vector t = player.getTerritoriesOwned();
-		    Vector n;
-		    String name=null;
-			name = findAttackableTerritory(player);
-			if ( name == null ) {
-			return "placearmies " + ((Country)t.elementAt(0)).getColor() +" "+player.getExtraArmies()  ;
-		    }
-
-		    if (game.getSetup() ) {
-			return "placearmies " + name +" "+player.getExtraArmies() ;
-		    }
-
-		    return "placearmies " + name +" 1";
-
-		}
-
+	    Vector t = player.getTerritoriesOwned();
+	    Vector n = findAttackableTerritories(player, false);
+	    Country c = null;
+	    if (n.isEmpty()) {
+	    	c = (Country)t.elementAt(0);
+	    } else {
+	    	c = randomCountry(n);
+	    }
+	    return getPlaceCommand(c, player.getExtraArmies());
     }
 
-    public String getAttack() {
-	//Vector t = player.getTerritoriesOwned();
-	Vector outputs = new Vector();
-	Attack move;
-
-	/*  // Extract method: findAttackableNeighbors() 
-	Vector n;
-	for (int a=0; a< t.size() ; a++) {
-	    if ( ((Country)t.elementAt(a)).getArmies() > 1 ) {
-		n = ((Country)t.elementAt(a)).getNeighbours();
-		for (int b=0; b< n.size() ; b++) {
-		    if ( ((Country)n.elementAt(b)).getOwner() != player ) {
-			outputs.add( "attack " + ((Country)t.elementAt(a)).getColor() + " " + ((Country)n.elementAt(b)).getColor() );
-		    }
+	public String getAttack() {
+		Vector v = findAttackableTerritories(player, true);
+		
+		while (!v.isEmpty()) {
+			Country c = (Country)v.remove( r.nextInt(v.size()) );
+			Vector n = c.getNeighbours();
+			for (int i = 0; i < n.size(); i++) {
+				Country other = (Country)n.get(i);
+				if (other.getOwner() != player && c.getArmies() > other.getArmies()) {
+					return "attack " + c.getColor() + " " + other.getColor();
+				}
+			}
 		}
-	    }
-	}  */
-	outputs = findAttackableNeighbors(player.getTerritoriesOwned(),0);
-	if (outputs.size() > 0) {
-		move = (Attack) outputs.elementAt( (int)Math.round(Math.random() * (outputs.size()-1) ) );
-		//System.out.println(player.getName() + ": "+ move.toString());    //TESTING
-		return move.toString();
-		//return (String)outputs.elementAt( (int)Math.round(Math.random() * (outputs.size()-1) ) );
+		
+		return "endattack";
 	}
-	return "endattack";
-    }
-
-
 
     public String getRoll() {
-	    int n=((Country)game.getAttacker()).getArmies() - 1;
-	    if (n > 3) {
-		    return "roll "+3;
-	    }
-	    return "roll "+n;
+	    int n=game.getAttacker().getArmies() - 1;
+	    return "roll " + Math.min(3, n);
     }
-
-
-    /******************
-     * Helper Methods *
-     ******************/
-
-    /************
-     * @name findAttackableNeighbors
-     * @param t Vector of teritories
-     * @param ratio - threshold of attack to defence armies to filter out
-     * @return a Vector of possible attacks for a given list of territories
-     * 	where the ratio of source/target armies is above ratio
-     **************/
-    public Vector findAttackableNeighbors(Vector t, double ratio){
-	Vector output = new Vector();
-	Vector n=new Vector();
-    	Country source,target;
-	if (ratio<0) { ratio = 0;}
-	for (int a=0; a< t.size() ; a++) {
-	    source=(Country)t.elementAt(a);
-	    if ( source.getOwner() == player && source.getArmies() > 1 ) {
-		n = source.getNeighbours();
-		for (int b=0; b< n.size() ; b++) {
-		    target=(Country)n.elementAt(b);
-		    if ( target.getOwner() != player && 
-			( (double)(source.getArmies()/target.getArmies()) > ratio) 
-		      	) {     // simplify logic
-			//output.add( "attack " + source.getColor() + " " + target.getColor() );
-			output.add(new Attack(source,target));
-		    }
-		}
-	    }
-	}
-	return output;
+    
+    @Override
+    public String getBattleWon() {
+    	if (player.getCapital() == game.getAttacker()) {
+    		return "move " + game.getMustMove(); 
+    	}
+    	return super.getBattleWon();
     }
 
-    /************
-     * @name findAttackableNeighbors
-     * @param t Vector of teritories
-     * @param ratio - threshold of attack to defence armies to filter out
-     * @return a Vector of possible attacks for a given list of territories
-     * 	where the ratio of source/target armies is above ratio
-     **************/
-    public Vector getPossibleAttacks(Vector t){
-	Vector output = new Vector();
-	Vector n=new Vector();
-    	Country source,target;
-	for (int a=0; a< t.size() ; a++) {
-	    source=(Country)t.elementAt(a);
-	    if ( source.getOwner() == player && source.getArmies() > 1 ) {
-		n = source.getNeighbours();
-		for (int b=0; b< n.size() ; b++) {
-		    target=(Country)n.elementAt(b);
-		    if ( target.getOwner() != player ) {     // simplify logic
-			//output.add( "attack " + source.getColor() + " " + target.getColor() );
-			output.add(new Attack(source,target));
-		    }
-		}
-	    }
-	}
-	return output;
+    public int tradeCombinationsToScan() {
+    	return 10000;
     }
-
-    /*******************
-     * @name filterAttacks
-     * @param options - Vector of Attacks
-     * @param advantage - how much of an absolute advantage to have
-     * @return Vector of attacks with specified advantage
-     *******************/
-
-    public Vector filterAttacks(Vector options, int advantage){
-	Attack temp = null;
-	Vector moves = new Vector();
-	for(int j=0; j<options.size(); j++){
-		temp=(Attack)options.get(j);
-		if ( ( ((Country)temp.source).getArmies() - ((Country)temp.destination).getArmies()) > advantage) {
-			moves.add(temp);
-		}
+    
+	protected String getPlaceCommand(Country country, int armies) {
+		return "placearmies " + country.getColor() + " " + (!game.getSetup()?1:Math.min(player.getExtraArmies(), armies));
 	}
-	return moves;
-    }
 
 }
Index: src/net/yura/domination/engine/ai/AIPlayer.java
===================================================================
--- src/net/yura/domination/engine/ai/AIPlayer.java	(revision 1057)
+++ src/net/yura/domination/engine/ai/AIPlayer.java	(working copy)
@@ -77,8 +77,7 @@
 
 	public static String getOutput(RiskGame game,AICrap usethisAI) {
 
-		usethisAI.game = game;
-		usethisAI.player = game.getCurrentPlayer();
+		usethisAI.setPlayer(game);
 
 		String output=null;
 
Index: src/net/yura/domination/engine/core/RiskGame.java
===================================================================
--- src/net/yura/domination/engine/core/RiskGame.java	(revision 1057)
+++ src/net/yura/domination/engine/core/RiskGame.java	(working copy)
@@ -14,6 +14,7 @@
 import java.util.Random;
 import java.util.StringTokenizer;
 import java.util.Vector;
+
 import net.yura.domination.engine.ColorUtil;
 import net.yura.domination.engine.RiskUtil;
 import net.yura.domination.engine.translation.MapTranslator;
@@ -139,6 +140,8 @@
 
 	private int attackerDice;
 	private int defenderDice;
+	
+	private int battleRounds;
 
 	private String ImagePic;
 	private String ImageMap;
@@ -423,6 +426,10 @@
 			return "";
 		}
 	}
+	
+	public boolean isCapturedCountry() {
+		return capturedCountry;
+	}
 
 	/**
 	 * Ends a player's go
@@ -629,39 +636,53 @@
     }
 
 	public boolean canTrade() {
-
-		Vector cards = currentPlayer.getCards();
-		Card card1=null, card2=null, card3=null;
-
-		if (setup == Players.size() && cards.size() >= 3 ) { // ie the initial setup has been compleated and there are 3 cards or more
-
-			for (int a=0; a< cards.size() ; a++) {
-				if (card1 != null && card2 != null && card3 != null) { break; }
-				card1 = (Card)cards.elementAt(a);
-
-				for (int b=(a+1); b< cards.size() ; b++) {
-					if (card1 != null && card2 != null && card3 != null) { break; }
-					card2 = (Card)cards.elementAt(b);
-
-					for (int c=(b+1); c< cards.size() ; c++) {
-						if (card1 != null && card2 != null && card3 != null) { break; }
-						card3 = (Card)cards.elementAt(c);
-
-						if ( checkTrade(card1, card2, card3) ) { break; }
-						else { card3=null; }
-
+		return getBestTrade(currentPlayer.getCards(), 0) != null;
+	}
+	
+	public Card[] getBestTrade(Vector cards, int tradesToScan) {
+		Card[] result = new Card[3];
+		int bestValue = 0;
+		Card[] bestResult = new Card[3];
+		int orig = tradesToScan;
+		for (int a = 0; a < cards.size() - 2; a++) {
+			result[0] = (Card) cards.elementAt(a);
+			for (int b = (a + 1); b < cards.size() - 1; b++) {
+				result[1] = (Card) cards.elementAt(b);
+				for (int c = (b + 1); c < cards.size(); c++) {
+					result[2] = (Card) cards.elementAt(c);
+					tradesToScan--;
+					int value = getTradeAbsValue( result[0].getName(), result[1].getName(), result[2].getName(), getCardMode());
+					if (value == 0) {
+						if (tradesToScan < 0 && bestValue > 0) {
+							return bestResult;
+						}
+						continue;
+					}
+					//dynamic programming if there are a lot of cards
+					if (cards.size() > 5 && orig > 0) {
+						Vector remainingCards = new Vector(cards);
+						for (int i = 0; i < result.length; i++) {
+							remainingCards.remove(result[i]);
+						}
+						Card[] next = getBestTrade(remainingCards, orig/2);
+						if (next != null) {
+							value += getTradeAbsValue( next[0].getName(), next[1].getName(), next[2].getName(), getCardMode());
+						}
+					}
+					if (value > bestValue) {
+						bestValue = value;
+						System.arraycopy(result, 0, bestResult, 0, result.length);
+					}
+					if (tradesToScan < 0) {
+						return bestResult;
 					}
 				}
 			}
 		}
-
-		if (card3 == null) {
-			return false;
-		}
-		else {
-			return true;
+		if (bestValue == 0) {
+			return null;
 		}
-
+		return bestResult;
 	}
 
 	public int getNewCardState() {
@@ -870,7 +891,7 @@
 
 				attacker=t1;
 				defender=t2;
-
+				battleRounds = 0;
 				gameState=STATE_ROLLING;
 				//System.out.print("Attacking "+t2.getName()+" ("+t2.getArmies()+") with "+t1.getName()+" ("+t1.getArmies()+").\n"); // testing
 
@@ -955,6 +976,10 @@
 	public int getDefenderDice() {
 		return defenderDice;
 	}
+	
+	public int getBattleRounds() {
+		return battleRounds;
+	}
 
 	/**
 	 * Rolls the defenders dice
@@ -973,7 +998,7 @@
 		result[5]=0; // max move
 
 		if (gameState==STATE_DEFEND_YOURSELF) { // if we were in the defending phase
-
+			battleRounds++;
 			// battle away!
 			for (int c=0; c< Math.min(attackerResults.length, defenderResults.length) ; c++) {
 
@@ -1046,8 +1071,6 @@
 			}
 			else { gameState=STATE_ROLLING; }
 
-			defenderDice = 0;
-			attackerDice = 0;
 			result[0]=1;
 
 		}
@@ -2625,6 +2648,10 @@
 	public int getNoCards() {
 		return Cards.size();
 	}
+	
+	public boolean isRecycleCards() {
+		return recycleCards;
+	}
 
 	/**
 	 * Set the Default Map and Cards File
Index: src/net/yura/domination/engine/core/Continent.java
===================================================================
--- src/net/yura/domination/engine/core/Continent.java	(revision 1057)
+++ src/net/yura/domination/engine/core/Continent.java	(working copy)
@@ -21,6 +21,7 @@
 	private int color;
 	private int armyValue;
 	private Vector territoriesContained = new Vector();
+	private transient Vector borderCountries;
 
 	/**
 	 * Creates a continent object
@@ -104,6 +105,22 @@
 	 * otherwise false if the player does not own the all the territories
 	 */
 	public boolean isOwned(Player p) {
+		for (int c=0; c< territoriesContained.size() ; c++) {
+
+			if ( ((Country)territoriesContained.elementAt(c)).getOwner() != p ) {
+				return false;
+			}
+
+		}
+		return true;
+	}
+	
+	/**
+	 * Checks the percent of countries the player owns within a continent
+	 * @param p player object
+	 * @return the percentage
+	 */
+	public int getNumberOwned(Player p) {
 
 		int ownedByPlayer=0;
 
@@ -114,14 +131,7 @@
 			}
 
 		}
-
-		if ( ownedByPlayer==territoriesContained.size() ) {
-			return true;
-		}
-		else {
-			return false;
-		}
-
+		return ownedByPlayer;
 	}
 
 	/*****
@@ -130,16 +140,33 @@
 	 *  else null if no one owns the continent
 	 ****/
 	public Player getOwner(){
-		Player owner;
-		owner = ((Country)territoriesContained.elementAt(0)).getOwner();
-		for (int c=1; c< territoriesContained.size() ; c++) {
+		Player owner = ((Country)territoriesContained.elementAt(0)).getOwner();
+		for (int c=1; c< territoriesContained.size() && owner != null ; c++) {
 			if ( ((Country)territoriesContained.elementAt(c)).getOwner() != owner ) {
 				owner = null;
-				break;
 			}
 		}
 		return owner;
 	}
+	
+	public Vector getBorderCountries() {
+		if (borderCountries == null) {
+			Vector b = new Vector(2);
+			for (int i = 0; i < territoriesContained.size(); i++) {
+				Country country = (Country) territoriesContained.get(i);
+				Vector w = country.getNeighbours();
+				for (int k = 0; k < w.size(); k++) {
+					if (((Country) w.elementAt(k)).getContinent() != this) {
+						/* This is a territory to protect from */
+						b.add(country);
+						break;
+					}
+				}
+			}
+			this.borderCountries = b; 
+		}
+		return this.borderCountries;
+	}
 
 	/**
 	 * Returns a vector of the territories contained within a continent
@@ -154,6 +181,7 @@
 	 * @param t the country object
 	 */
 	public void addTerritoriesContained(Country t) {
+		this.borderCountries = null;
 		territoriesContained.add(t);
 	}
 
