package net.sf.colossus.ai.objectives; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.logging.Logger; import net.sf.colossus.ai.AbstractAI; import net.sf.colossus.client.Client; import net.sf.colossus.game.Creature; import net.sf.colossus.game.Legion; import net.sf.colossus.variant.CreatureType; import net.sf.colossus.variant.RecruitingSubTree; import net.sf.colossus.variant.Variant; /** * A naive (basic!) implementation of @IObjectiveHelper. * This is still mostly for testing the code. * @author Romain Dolbeau */ public class BasicObjectiveHelper extends AbstractObjectiveHelper { private static final Logger LOGGER = Logger .getLogger(BasicObjectiveHelper.class.getName()); public BasicObjectiveHelper(Client client, AbstractAI ai, Variant variant) { super(client, ai, variant); } /** really stupid heuristic */ private AllThereIsToKnowAboutYourCreature findCreatureToDestroyInAttacker() { Creature creature = null; int mcount = 0; Legion attacker = client.getAttacker(); for (Creature lcritter : attacker.getCreatures()) { int count = ai.countCreatureAccrossAllLegionFromPlayer(lcritter); if (count == 0) { LOGGER.warning("Strange, we have at least a " + lcritter.getName() + " in legion " + attacker.getMarkerId() + " yet 0 in total..."); } LOGGER.finest("Found " + count + " " + lcritter.getName() + " in all ; we have " + attacker.numCreature(lcritter.getType()) + " in here"); if (!lcritter.isLord() && !lcritter.isDemiLord() && ((creature == null) || (count < mcount))) { creature = lcritter; mcount = count; } } LOGGER.finest("Less Common choice: " + (creature != null ? creature.getName() : "(NOBODY)")); List<AllThereIsToKnowAboutYourCreature> overkill = new ArrayList<AllThereIsToKnowAboutYourCreature>(); overkill.addAll(attackerToKnowledge.values()); Collections.sort(overkill, HEURISTIC_ORDER); StringBuffer buf = new StringBuffer(); for (AllThereIsToKnowAboutYourCreature atitkayc : overkill) { buf.append("\t" + atitkayc.toString() + "\n"); } LOGGER.finest("AllThereIsToKnowAboutYourCreature order:\n" + buf.toString()); if (overkill.size() > 0) { return overkill.get(overkill.size() - 1); } if (creature != null) { return new AllThereIsToKnowAboutYourCreature(ai, creature, attacker); } return null; } protected List<TacticalObjective> commonObjective(Legion myself) { List<TacticalObjective> lListObjectives = new ArrayList<TacticalObjective>(); Map<CreatureType, Creature> toConsider = new TreeMap<CreatureType, Creature>(); for (Creature lcritter : myself.getCreatures()) { // at most one entry per CreatureType ... toConsider.put(lcritter.getType(), lcritter); } for (CreatureType creature : toConsider.keySet()) { Creature lcritter = toConsider.get(creature); if (!lcritter.isLord() && RecruitingSubTree.isADeadEnd(variant, lcritter.getType())) { LOGGER.info("CommonObjective: " + lcritter.getName() + " is a dead end and non-lord, aka Cannon Fodder"); lListObjectives.add(new CreatureAttackTacticalObjective( oec.FIRST_WAVE_ATTACK_PRIORITY, client, myself, lcritter, ai, ai.bec)); } else if (lcritter.isLord() && !lcritter.isTitan()) { LOGGER.info("CommonObjective: " + lcritter.getName() + " is a non-titan lord, aka Cannon Fodder"); lListObjectives.add(new CreatureAttackTacticalObjective( oec.FIRST_WAVE_ATTACK_PRIORITY, client, myself, lcritter, ai, ai.bec)); } else if (!lcritter.isTitan()) { LOGGER.info("CommonObjective: " + lcritter.getName() + " matters (a bit)..."); lListObjectives.add(new CreatureAttackTacticalObjective( oec.SECOND_WAVE_ATTACK_PRIORITY, client, myself, lcritter, ai, ai.bec)); } } return lListObjectives; } /** Currently attackerObjective is very dumb: * try and kill the Titan (if there) and the biggest creature */ public List<TacticalObjective> attackerObjective() { List<TacticalObjective> lListObjectives = new ArrayList<TacticalObjective>(); lListObjectives.addAll(commonObjective(client.getAttacker())); Creature toKill = null; for (Creature lcritter : client.getDefender().getCreatures()) { if (lcritter.isTitan()) { lListObjectives.add(new DestroyCreatureTacticalObjective( oec.DESTROY_TITAN_PRIORITY, client, client.getDefender(), lcritter, 1)); } else { if (toKill == null) { toKill = lcritter; } else { if (toKill.getPointValue() < lcritter.getPointValue()) { toKill = lcritter; } } } } for (Creature lcritter : client.getAttacker().getCreatures()) { if (lcritter.isTitan()) { lListObjectives.add(new PreserveCreatureTacticalObjective( oec.ATTACKER_PRESERVE_TITAN_PRIORITY, client, client .getAttacker(), lcritter)); } } if (toKill != null) { lListObjectives.add(new DestroyCreatureTacticalObjective( oec.DESTROY_IMPORTANT_CRITTER_PRIORITY, client, client .getDefender(), toKill, 1)); } for (TacticalObjective to : lListObjectives) { LOGGER.info("Attacker Objective: " + to.getDescription()); } return lListObjectives; } public List<TacticalObjective> defenderObjective() { List<TacticalObjective> lListObjectives = new ArrayList<TacticalObjective>(); lListObjectives.addAll(commonObjective(client.getDefender())); for (Creature lcritter : client.getAttacker().getCreatures()) { if (lcritter.isTitan()) { lListObjectives.add(new DestroyCreatureTacticalObjective( oec.DESTROY_TITAN_PRIORITY, client, client.getAttacker(), lcritter, 1)); } } for (Creature lcritter : client.getDefender().getCreatures()) { if (lcritter.isTitan()) { lListObjectives.add(new PreserveCreatureTacticalObjective( oec.DEFENDER_PRESERVE_TITAN_PRIORITY, client, client .getDefender(), lcritter)); } } AllThereIsToKnowAboutYourCreature toKill = findCreatureToDestroyInAttacker(); if (toKill != null) { lListObjectives.add(new DestroyCreatureTacticalObjective( oec.DESTROY_IMPORTANT_CRITTER_PRIORITY, client, client .getAttacker(), toKill.creature, Math.min( toKill.stackNumber, toKill.numberNeededHere))); } for (TacticalObjective to : lListObjectives) { LOGGER.info("Defender Objective: " + to.getDescription()); } return lListObjectives; } private static final Comparator<AllThereIsToKnowAboutYourCreature> HEURISTIC_ORDER = new Comparator<AllThereIsToKnowAboutYourCreature>() { private int avoidNullPointerException( AllThereIsToKnowAboutYourCreature c1, AllThereIsToKnowAboutYourCreature c2) { if ((c1.bestRecruit != null) && (c2.bestRecruit == null)) { return 1; } if ((c1.bestRecruit == null) && (c2.bestRecruit != null)) { return -1; } if ((c1.bestRecruit != null) && (c2.bestRecruit != null)) { if (c1.bestRecruit.getPointValue() > c2.bestRecruit .getPointValue()) { return 1; } if (c1.bestRecruit.getPointValue() < c2.bestRecruit .getPointValue()) { return -1; } } if (c1.creature.getPointValue() > c2.creature.getPointValue()) { return 1; } if (c1.creature.getPointValue() < c2.creature.getPointValue()) { return -1; } return 0; } public int compare(AllThereIsToKnowAboutYourCreature c1, AllThereIsToKnowAboutYourCreature c2) { if (!c1.thisStackHasBetter && c2.thisStackHasBetter) { return 1; } if (c1.thisStackHasBetter && !c2.thisStackHasBetter) { return -1; } if (c1.thisStackHasBetter && c2.thisStackHasBetter) { int result = avoidNullPointerException(c1, c2); if (result != 0) { return result; } } if (c1.isImmediatelyUsefulKilling && !c2.isImmediatelyUsefulKilling) { return 1; } if (!c1.isImmediatelyUsefulKilling && c2.isImmediatelyUsefulKilling) { return -1; } if (c1.isImmediatelyUsefulKilling && c2.isImmediatelyUsefulKilling) { int result = avoidNullPointerException(c1, c2); if (result != 0) { return result; } } if (c1.onlyThisStackHasIt && !c2.onlyThisStackHasIt) { return 1; } if (!c1.onlyThisStackHasIt && c2.onlyThisStackHasIt) { return -1; } if (c1.onlyThisStackHasIt && c2.onlyThisStackHasIt) { int result = avoidNullPointerException(c1, c2); if (result != 0) { return result; } } if (c1.numberNeededHere > c2.numberNeededHere) { return 1; } if (c1.numberNeededHere < c2.numberNeededHere) { return -1; } return c1.creature.getName().compareTo(c2.creature.getName()); } }; }