package net.sf.colossus.ai.objectives;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import net.sf.colossus.ai.AbstractAI;
import net.sf.colossus.client.Client;
import net.sf.colossus.common.Constants;
import net.sf.colossus.game.Creature;
import net.sf.colossus.game.Legion;
import net.sf.colossus.variant.CreatureType;
import net.sf.colossus.variant.MasterBoardTerrain;
import net.sf.colossus.variant.RecruitingSubTree;
import net.sf.colossus.variant.Variant;
/**
*
* @author dolbeau
*/
public abstract class AbstractObjectiveHelper implements IObjectiveHelper
{
protected final ObjectiveEvalConstants oec;
protected final Client client;
protected final AbstractAI ai;
protected final Variant variant;
protected final Map<Creature, AllThereIsToKnowAboutYourCreature> attackerToKnowledge;
protected final Map<Creature, AllThereIsToKnowAboutYourCreature> defenderToKnowledge;
protected AbstractObjectiveHelper(Client client, AbstractAI ai,
Variant variant)
{
this.client = client;
this.ai = ai;
this.variant = variant;
oec = new ObjectiveEvalConstants();
attackerToKnowledge = new HashMap<Creature, AllThereIsToKnowAboutYourCreature>();
defenderToKnowledge = new HashMap<Creature, AllThereIsToKnowAboutYourCreature>();
Legion attacker = client.getAttacker();
for (Creature lcritter : attacker.getCreatures())
{
if (!lcritter.isTitan())
{
attackerToKnowledge.put(lcritter,
new AllThereIsToKnowAboutYourCreature(ai, lcritter,
attacker));
}
}
Legion defender = client.getDefender();
for (Creature lcritter : defender.getCreatures())
{
if (!lcritter.isTitan())
{
defenderToKnowledge.put(lcritter,
new AllThereIsToKnowAboutYourCreature(ai, lcritter,
defender));
}
}
}
protected class ObjectiveEvalConstants
{
final float DESTROY_TITAN_PRIORITY = 5.f;
final float ATTACKER_PRESERVE_TITAN_PRIORITY = 2.f;
final float DEFENDER_PRESERVE_TITAN_PRIORITY = 5.f;
final float DESTROY_IMPORTANT_CRITTER_PRIORITY = 1.f;
final float FIRST_WAVE_ATTACK_PRIORITY = 1.f;
final float SECOND_WAVE_ATTACK_PRIORITY = 0.5f;
}
/**
* Helper class holding some knowledge about a given creature.
*/
protected class AllThereIsToKnowAboutYourCreature
{
/** The creature this knowledged is about */
final Creature creature;
/** How many creature of the same type the player owns (in all its Legion) */
final int playerNumber;
/** How many creature of the same type are in this legion (including this one) */
final int stackNumber;
/** What can this creature recruits */
final Set<CreatureType> recruits;
/** The best possible recruit (by points value) this creature could someday recruit (anywhere) */
final CreatureType bestRecruit;
/** How many we need in the current terrain to recruit (BIGNUM if we can't recruit) */
final int numberNeededHere;
/** Whether the current Legion already has something better in the recruit tree (of this terrain) */
final boolean thisStackHasBetter;
/** Whether it's immediately useful to kill, i.e. we already have just enough to
* recruit and nothing better in this terrain.
*/
final boolean isImmediatelyUsefulKilling;
/** Whether this creature type appears in this stack, and in this stack only */
final boolean onlyThisStackHasIt;
/** How many are left in the Caretaker's stack */
final int numberLeftToRecruit;
/** Whether we can still recruit here or we are already out of luck (always true if we can't recruit here...) */
final boolean enoughLeftToRecruitHere;
/** Whether we can still recruit here with no room to spare (always true if we can't recruit here...) */
final boolean justEnoughLeftToRecruitHere;
@Override
public String toString()
{
StringBuffer buf = new StringBuffer();
buf.append(creature.getName());
buf.append(" playerNumber=" + playerNumber);
buf.append(" stackNumber=" + stackNumber);
buf.append(" bestRecruit="
+ (bestRecruit != null ? bestRecruit.getName() : "(NONE)"));
buf.append(" numberNeededHere=" + numberNeededHere);
buf.append(" thisStackHasBetter=" + thisStackHasBetter);
buf.append(" isImmediatelyUsefulKilling="
+ isImmediatelyUsefulKilling);
buf.append(" onlyThisStackHasIt=" + onlyThisStackHasIt);
buf.append(" numberLeftToRecruit=" + numberLeftToRecruit);
return buf.toString();
}
AllThereIsToKnowAboutYourCreature(AbstractAI ai, Creature creature,
Legion legion)
{
this.creature = creature;
MasterBoardTerrain terrain = legion.getCurrentHex().getTerrain();
playerNumber = ai
.countCreatureAccrossAllLegionFromPlayer(creature);
int count = 0;
for (Creature creature2 : legion.getCreatures())
{
if (creature.getType().equals(creature2.getType()))
{
count++;
}
}
stackNumber = count;
recruits = RecruitingSubTree.getAllInAllSubtreesIgnoringSpecials(
variant, creature.getType());
CreatureType temp = null;
for (CreatureType ct : recruits)
{
if (temp == null)
{
temp = ct;
}
else
{
if (temp.getPointValue() < ct.getPointValue())
{
temp = ct;
}
}
}
bestRecruit = temp;
int nnh = terrain.getRecruitingSubTree().maximumNumberNeededOf(
creature.getType(), legion.getCurrentHex());
if (nnh == -1)
{
numberNeededHere = Constants.BIGNUM;
}
else
{
numberNeededHere = nnh;
}
boolean hasBetter = false;
for (CreatureType recruit : recruits)
{
if (recruit.getPointValue() > creature.getPointValue())
{
for (Creature c : legion.getCreatures())
{
if (c.getType().equals(recruit))
{
hasBetter = true;
}
}
}
}
thisStackHasBetter = hasBetter;
if (!hasBetter && (numberNeededHere == stackNumber))
{
isImmediatelyUsefulKilling = true;
}
else
{
isImmediatelyUsefulKilling = false;
}
if (playerNumber == stackNumber)
{
onlyThisStackHasIt = true;
}
else
{
onlyThisStackHasIt = false;
}
numberLeftToRecruit = ai.getCaretaker().getAvailableCount(
creature.getType());
if (numberNeededHere < Constants.BIGNUM)
{
enoughLeftToRecruitHere = (stackNumber + numberLeftToRecruit) >= numberNeededHere;
justEnoughLeftToRecruitHere = (stackNumber + numberLeftToRecruit) == numberNeededHere;
}
else
{
enoughLeftToRecruitHere = true;
justEnoughLeftToRecruitHere = true;
}
}
}
}