net.sf.colossus.ai
Class SimpleAI

java.lang.Object
  extended by net.sf.colossus.ai.AbstractAI
      extended by net.sf.colossus.ai.SimpleAI
All Implemented Interfaces:
AI
Direct Known Subclasses:
CowardSimpleAI, ExperimentalAI, RationalAI

public class SimpleAI
extends AbstractAI

Simple implementation of a Titan AI TODO somehow we call client.getOwningPlayer() a lot -- there should probably be a better link between AI and player, after all the AI either IS_A player or PLAYS_FOR a player

Author:
Bruce Sherrod, David Ripton, Romain Dolbeau

Nested Class Summary
protected  class SimpleAI.PowerSkill
           
private static class SimpleAI.TerrainBonuses
          Stores the skill and power bonuses for a single terrain.
protected  class SimpleAI.TriggerTimeIsUp
           
 
Nested classes/interfaces inherited from class net.sf.colossus.ai.AbstractAI
AbstractAI.AbstractAIOracle, AbstractAI.CreatureValueConstants, AbstractAI.MoveInfo
 
Field Summary
private static int DRAW
           
private static java.util.logging.Logger LOGGER
           
private static int LOSE
           
private static int LOSE_BUT_INFLICT_HEAVY_LOSSES
           
private  int MAX_LEGION_MOVES
           
protected static int MIN_ITERATIONS
           
private  java.util.List<java.lang.String> remainingMarkers
           
private  int splitsAcked
           
private  int splitsDone
           
private static java.util.Map<java.lang.String,SimpleAI.TerrainBonuses> TERRAIN_BONUSES
          Maps the terrain names to their matching bonuses.
(package private)  boolean timeIsUp
           
protected  int timeLimit
           
private static int WIN_WITH_HEAVY_LOSSES
           
private static int WIN_WITH_MINIMAL_LOSSES
           
 
Fields inherited from class net.sf.colossus.ai.AbstractAI
bec, client, cvc, hintSectionUsed, random, variant
 
Constructor Summary
SimpleAI(Client client)
           
 
Method Summary
 CreatureType acquireAngel(Legion legion, java.util.List<CreatureType> angels)
          choose whether to acquire an angel or archangel
 java.util.List<CritterMove> battleMove()
          Return a list of critter moves, in best move order.
private  SimpleAI.PowerSkill calcBonus(CreatureType creature, java.lang.String terrain, boolean defender)
           
private  java.util.List<CreatureType> chooseCreaturesToSplitOut(Legion legion)
          Decide how to split this legion, and return a list of Creatures to remove.
(package private)  CreatureType chooseRecruit(LegionClientSide legion, MasterHex hex, boolean considerReservations)
           
private  java.util.List<CreatureType> CMUsplit(boolean favorTitan, CreatureType splitCreature, CreatureType nonsplitCreature, MasterHex hex)
          Keep the gargoyles together.
 boolean concede(Legion legion, Legion enemy)
          choose whether legion should concede to enemy
(package private)  java.util.List<CreatureType> doInitialGameSplit(MasterHex hex)
          Return a list of exactly four creatures (including one lord) to split out.
private  boolean doMove(Legion legion, MasterHex hex)
           
private  int estimateBattleResults(Legion attacker, boolean attackerSplitsBeforeBattle, Legion defender, MasterHex hex)
           
private  int estimateBattleResults(Legion attacker, boolean attackerSplitsBeforeBattle, Legion defender, MasterHex hex, CreatureType recruit)
           
private  int estimateBattleResults(Legion attacker, Legion defender, MasterHex hex)
           
private  void evaluateCritterMove_Attacker(BattleCritter critter, ValueRecorder value, MasterBoardTerrain terrain, BattleHex hex, LegionClientSide legion, int turn)
          this compute for non-titan attacking critter
protected  void evaluateCritterMove_Defender(BattleCritter critter, ValueRecorder value, MasterBoardTerrain terrain, BattleHex hex, LegionClientSide legion, int turn)
          this compute for non-titan defending critter
protected  void evaluateCritterMove_Rangestrike(BattleCritter critter, java.util.Map<BattleHex,java.lang.Integer> strikeMap, ValueRecorder value, MasterBoardTerrain terrain, BattleHex hex, int power, int skill, LegionClientSide legion, int turn, java.util.Set<BattleHex> targetHexes)
           
protected  void evaluateCritterMove_Strike(BattleCritter critter, java.util.Map<BattleHex,java.lang.Integer> strikeMap, ValueRecorder value, MasterBoardTerrain terrain, BattleHex hex, int power, int skill, LegionClientSide legion, int turn, java.util.Set<BattleHex> targetHexes)
           
private  void evaluateCritterMove_Terrain(BattleCritter critter, ValueRecorder value, MasterBoardTerrain terrain, BattleHex hex, int power, int skill)
          This compute the influence of terrain
protected  void evaluateCritterMove_Titan(BattleCritter critter, ValueRecorder value, MasterBoardTerrain terrain, BattleHex hex, Legion legion, int turn)
          this compute the special case of the Titan critter
private  int evaluateCritterMove(BattleCritter critter, java.util.Map<BattleHex,java.lang.Integer> strikeMap, ValueRecorder value)
          strikeMap is optional
private  int evaluateEngagement(MasterHex hex)
           
protected  int evaluateLegionBattleMove(LegionMove lm)
           
protected  int evaluateLegionBattleMoveAsAWhole(LegionMove lm, java.util.Map<BattleHex,java.lang.Integer> strikeMap, ValueRecorder value)
           
private  int evaluateMove(LegionClientSide legion, MasterHex hex, boolean moved, java.util.Map<MasterHex,java.util.List<Legion>>[] enemyAttackMap, ValueRecorder value)
          cheap, inaccurate evaluation function.
private  java.util.Collection<LegionMove> findBattleMoves()
           
private  java.util.List<CritterMove> findBattleMovesOneCritter(BattleCritter critter)
           
private  BattleCritter findBestAttacker(BattleCritter target)
           
protected  LegionMove findBestLegionMove(java.util.Collection<LegionMove> legionMoves)
          Evaluate all legion moves in the list, and return the best one.
private  BattleCritter findBestTarget()
           
(package private)  java.util.Collection<LegionMove> findLegionMoves(java.util.List<java.util.List<CritterMove>> allCritterMoves)
          allCritterMoves is a List of sorted MoveLists.
private  java.util.List<CritterMove> findMoveOrder(LegionMove lm)
           
(package private)  java.util.List<CreatureType> findWeakestTwoCritters(LegionClientSide legion)
          Find the two weakest creatures in a legion according to
 boolean flee(Legion legion, Legion enemy)
          choose whether legion should flee from enemy
private  CreatureType getBestCreature(java.util.List<CreatureType> creatures)
          Return the most important Creature in the list of Creatures.
private static int getCombatValue(BattleCritter battleUnit, MasterBoardTerrain terrain)
           
private  int getCombatValue(CreatureType creature, MasterBoardTerrain terrain)
          XXX Inaccurate for titans.
private  int getCombatValue(Legion legion, MasterBoardTerrain terrain)
           
protected  int getCreatureMoveLimit()
          Find the maximum number of moves per creature to test, such that numMobileCreaturesInLegion ^ N <= LEGION_MOVE_LIMIT, but we must have at least as many moves as mobile creatures to ensure that every creature has somewhere to go.
protected  SimpleAI.PowerSkill getNativeValue(CreatureType creature, MasterBoardTerrain terrain, boolean defender)
           
private  int getTitanCombatValue(int power)
           
 void handleCarries(int carryDamage, java.util.Set<java.lang.String> carryTargets)
          Apply carries first to the biggest creature that could be killed with them, then to the biggest creature.
private  boolean handleForcedSingleMove(Player player, java.util.Map<Legion,java.util.List<AbstractAI.MoveInfo>> moveMap)
           
private  boolean handleForcedSplitMoves(Player player, java.util.Map<Legion,java.util.List<AbstractAI.MoveInfo>> moveMap)
          Return true if we moved something.
(package private)  boolean handleMulligans(Player player)
          Take a mulligan if roll is 2 or 5 in first turn, and can still take a mulligan.
private  boolean handleVoluntaryMoves(PlayerClientSide player, java.util.Map<Legion,java.util.List<AbstractAI.MoveInfo>> moveMap, java.util.Map<MasterHex,java.util.List<Legion>>[] enemyAttackMap)
          Return true if we moved something.
 boolean masterMove()
          Do a masterboard move (or consider taking mulligan, if feasible).
private  java.util.List<CreatureType> MITsplit(boolean favorTitan, CreatureType splitCreature, CreatureType nonsplitCreature, MasterHex hex)
          Split the gargoyles.
 void muster()
          make recruits for current player
 PlayerColor pickColor(java.util.List<PlayerColor> colors, java.util.List<PlayerColor> favoriteColors)
          pick a color of legion markers
 MasterHex pickEngagement()
          pick an engagement to resolve
 EntrySide pickEntrySide(MasterHex hex, Legion legion, java.util.Set<EntrySide> entrySides)
          pick an entry side
 java.lang.String pickMarker(java.util.Set<java.lang.String> markerIds, java.lang.String preferredShortColor)
          pick a legion marker
 java.lang.String pickStrikePenalty(java.util.List<java.lang.String> choices)
          Pick one of the list of String strike penalty options.
private  java.util.List<java.lang.String> prepareMarkers(java.util.Set<java.lang.String> markerIds, java.lang.String preferredShortColor)
           
(package private)  double RATIO_DRAW()
           
(package private)  double RATIO_LOSE_HEAVY_LOSS()
           
(package private)  double RATIO_WIN_HEAVY_LOSS()
           
(package private)  double RATIO_WIN_MINIMAL_LOSS()
           
 void reinforce(Legion legion)
          pick one reinforcement for legion
 void retryFailedBattleMoves(java.util.List<CritterMove> bestMoveOrder)
          Try another move for creatures whose moves failed.
(package private)  java.util.Timer setupTimer()
           
 boolean split()
          make splits for current player.
 boolean splitCallback(Legion parent, Legion child)
          Unused in this AI; just return true to indicate done.
private  void splitOneLegion(Player player, Legion legion)
           
 boolean strike(Legion legion)
          Simple one-ply group strike algorithm.
 SummonInfo summonAngel(Legion summoner, java.util.List<Legion> donors)
          Return a SummonInfo object, containing the summoner, donor and unittype.
private  int testMoveOrder(java.util.List<CritterMove> order, java.util.List<CritterMove> newOrder)
          Try each of the moves in order.
 
Methods inherited from class net.sf.colossus.ai.AbstractAI
buildEnemyAttackMap, cleanupBattle, couldRecruitUp, countCreatureAccrossAllLegionFromPlayer, findStrikeMap, generateDamageMap, generateLegionMoves, getAcqStepValue, getBattleUnit, getHintedRecruitmentValue, getHintedRecruitmentValueNonTitan, getHintedRecruitmentValueNonTitan, getInitialSplitHint, getKillValue, getKillValue, getNumberOfWaysToTerrain, getVariantRecruitHint, hasOpponentNativeCreature, initBattle, isHumanLegion, makeLegionMove, rangeToClosestOpponent, setVariant
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

LOGGER

private static final java.util.logging.Logger LOGGER

TERRAIN_BONUSES

private static final java.util.Map<java.lang.String,SimpleAI.TerrainBonuses> TERRAIN_BONUSES
Maps the terrain names to their matching bonuses. Only the terrains that have bonuses are in this map, so users have to expect to retrieve null values. Note that the terrain names include names for master board and hazard terrains, so it can be used for lookup up either type. TODO there seems to be some overlap with HazardTerrain.isNativeBonusTerrain() and HazardTerrain.isNonNativePenaltyTerrain(). This is a Map. TODO: this shouldn't be here, this is a property of the Variant player (well, not yet for Hazard, but it should be, someday). Actually, this doesn't make sense to me (RD). tower has bonus for both attacker & defender (because of walls, I assume), but is special- cased for attacker & defender. Brush and Jungle assumes Brushes, but Jungle has Tree, too. And the comments themselves makes clear that 'Sand' is actually 'Slope', but mixing up Attacker & Native and Defender & non-native. This and calcBonus should be reviewed thoroughly.


timeLimit

protected int timeLimit

timeIsUp

boolean timeIsUp

splitsDone

private int splitsDone

splitsAcked

private int splitsAcked

remainingMarkers

private java.util.List<java.lang.String> remainingMarkers

WIN_WITH_MINIMAL_LOSSES

private static final int WIN_WITH_MINIMAL_LOSSES
See Also:
Constant Field Values

WIN_WITH_HEAVY_LOSSES

private static final int WIN_WITH_HEAVY_LOSSES
See Also:
Constant Field Values

DRAW

private static final int DRAW
See Also:
Constant Field Values

LOSE_BUT_INFLICT_HEAVY_LOSSES

private static final int LOSE_BUT_INFLICT_HEAVY_LOSSES
See Also:
Constant Field Values

LOSE

private static final int LOSE
See Also:
Constant Field Values

MAX_LEGION_MOVES

private final int MAX_LEGION_MOVES
See Also:
Constant Field Values

MIN_ITERATIONS

protected static final int MIN_ITERATIONS
See Also:
Constant Field Values
Constructor Detail

SimpleAI

public SimpleAI(Client client)
Method Detail

pickColor

public PlayerColor pickColor(java.util.List<PlayerColor> colors,
                             java.util.List<PlayerColor> favoriteColors)
Description copied from interface: AI
pick a color of legion markers


prepareMarkers

private java.util.List<java.lang.String> prepareMarkers(java.util.Set<java.lang.String> markerIds,
                                                        java.lang.String preferredShortColor)

pickMarker

public java.lang.String pickMarker(java.util.Set<java.lang.String> markerIds,
                                   java.lang.String preferredShortColor)
Description copied from interface: AI
pick a legion marker


muster

public void muster()
Description copied from interface: AI
make recruits for current player


reinforce

public void reinforce(Legion legion)
Description copied from interface: AI
pick one reinforcement for legion


chooseRecruit

CreatureType chooseRecruit(LegionClientSide legion,
                           MasterHex hex,
                           boolean considerReservations)

split

public boolean split()
Description copied from interface: AI
make splits for current player. Return true if done


splitCallback

public boolean splitCallback(Legion parent,
                             Legion child)
Unused in this AI; just return true to indicate done.


splitOneLegion

private void splitOneLegion(Player player,
                            Legion legion)

chooseCreaturesToSplitOut

private java.util.List<CreatureType> chooseCreaturesToSplitOut(Legion legion)
Decide how to split this legion, and return a list of Creatures to remove.


findWeakestTwoCritters

java.util.List<CreatureType> findWeakestTwoCritters(LegionClientSide legion)
Find the two weakest creatures in a legion according to

Parameters:
legion -
Returns:
List containing the CreatureTypes of the two weakest critters

doInitialGameSplit

java.util.List<CreatureType> doInitialGameSplit(MasterHex hex)
Return a list of exactly four creatures (including one lord) to split out.


CMUsplit

private java.util.List<CreatureType> CMUsplit(boolean favorTitan,
                                              CreatureType splitCreature,
                                              CreatureType nonsplitCreature,
                                              MasterHex hex)
Keep the gargoyles together.


MITsplit

private java.util.List<CreatureType> MITsplit(boolean favorTitan,
                                              CreatureType splitCreature,
                                              CreatureType nonsplitCreature,
                                              MasterHex hex)
Split the gargoyles.


masterMove

public boolean masterMove()
Do a masterboard move (or consider taking mulligan, if feasible). Returns true if we need to run this method again after the server updates the client with the results of a move or mulligan.


handleMulligans

boolean handleMulligans(Player player)
Take a mulligan if roll is 2 or 5 in first turn, and can still take a mulligan. Returns true if AI took a mulligan, false otherwise.


handleVoluntaryMoves

private boolean handleVoluntaryMoves(PlayerClientSide player,
                                     java.util.Map<Legion,java.util.List<AbstractAI.MoveInfo>> moveMap,
                                     java.util.Map<MasterHex,java.util.List<Legion>>[] enemyAttackMap)
Return true if we moved something.


handleForcedSplitMoves

private boolean handleForcedSplitMoves(Player player,
                                       java.util.Map<Legion,java.util.List<AbstractAI.MoveInfo>> moveMap)
Return true if we moved something.


handleForcedSingleMove

private boolean handleForcedSingleMove(Player player,
                                       java.util.Map<Legion,java.util.List<AbstractAI.MoveInfo>> moveMap)

doMove

private boolean doMove(Legion legion,
                       MasterHex hex)

evaluateMove

private int evaluateMove(LegionClientSide legion,
                         MasterHex hex,
                         boolean moved,
                         java.util.Map<MasterHex,java.util.List<Legion>>[] enemyAttackMap,
                         ValueRecorder value)
cheap, inaccurate evaluation function. Returns a value for moving this legion to this hex. The value defines a distance metric over the set of all possible moves. TODO: should be parameterized with weights TODO: the hex parameter is probably not needed anymore now that we pass the legion instead of just the marker [RD: actually, handleVoluntaryMove sees to call this one with several different hexes, so we probably can't remove it]


RATIO_WIN_MINIMAL_LOSS

double RATIO_WIN_MINIMAL_LOSS()

RATIO_WIN_HEAVY_LOSS

double RATIO_WIN_HEAVY_LOSS()

RATIO_DRAW

double RATIO_DRAW()

RATIO_LOSE_HEAVY_LOSS

double RATIO_LOSE_HEAVY_LOSS()

estimateBattleResults

private int estimateBattleResults(Legion attacker,
                                  Legion defender,
                                  MasterHex hex)

estimateBattleResults

private int estimateBattleResults(Legion attacker,
                                  boolean attackerSplitsBeforeBattle,
                                  Legion defender,
                                  MasterHex hex)

estimateBattleResults

private int estimateBattleResults(Legion attacker,
                                  boolean attackerSplitsBeforeBattle,
                                  Legion defender,
                                  MasterHex hex,
                                  CreatureType recruit)

pickEntrySide

public EntrySide pickEntrySide(MasterHex hex,
                               Legion legion,
                               java.util.Set<EntrySide> entrySides)
Description copied from interface: AI
pick an entry side


pickEngagement

public MasterHex pickEngagement()
Description copied from interface: AI
pick an engagement to resolve


evaluateEngagement

private int evaluateEngagement(MasterHex hex)

flee

public boolean flee(Legion legion,
                    Legion enemy)
Description copied from interface: AI
choose whether legion should flee from enemy


concede

public boolean concede(Legion legion,
                       Legion enemy)
Description copied from interface: AI
choose whether legion should concede to enemy


acquireAngel

public CreatureType acquireAngel(Legion legion,
                                 java.util.List<CreatureType> angels)
Description copied from interface: AI
choose whether to acquire an angel or archangel


getBestCreature

private CreatureType getBestCreature(java.util.List<CreatureType> creatures)
Return the most important Creature in the list of Creatures.


summonAngel

public SummonInfo summonAngel(Legion summoner,
                              java.util.List<Legion> donors)
Return a SummonInfo object, containing the summoner, donor and unittype.


findBestTarget

private BattleCritter findBestTarget()

findBestAttacker

private BattleCritter findBestAttacker(BattleCritter target)

handleCarries

public void handleCarries(int carryDamage,
                          java.util.Set<java.lang.String> carryTargets)
Apply carries first to the biggest creature that could be killed with them, then to the biggest creature. carryTargets are hexLabel description strings.


pickStrikePenalty

public java.lang.String pickStrikePenalty(java.util.List<java.lang.String> choices)
Pick one of the list of String strike penalty options.


strike

public boolean strike(Legion legion)
Simple one-ply group strike algorithm. Return false if there were no strike targets.


getCombatValue

private static int getCombatValue(BattleCritter battleUnit,
                                  MasterBoardTerrain terrain)

getCombatValue

private int getCombatValue(CreatureType creature,
                           MasterBoardTerrain terrain)
XXX Inaccurate for titans.


getTitanCombatValue

private int getTitanCombatValue(int power)

getCombatValue

private int getCombatValue(Legion legion,
                           MasterBoardTerrain terrain)

calcBonus

private SimpleAI.PowerSkill calcBonus(CreatureType creature,
                                      java.lang.String terrain,
                                      boolean defender)

getNativeValue

protected SimpleAI.PowerSkill getNativeValue(CreatureType creature,
                                             MasterBoardTerrain terrain,
                                             boolean defender)

battleMove

public java.util.List<CritterMove> battleMove()
Return a list of critter moves, in best move order.


retryFailedBattleMoves

public void retryFailedBattleMoves(java.util.List<CritterMove> bestMoveOrder)
Try another move for creatures whose moves failed.


findMoveOrder

private java.util.List<CritterMove> findMoveOrder(LegionMove lm)

testMoveOrder

private int testMoveOrder(java.util.List<CritterMove> order,
                          java.util.List<CritterMove> newOrder)
Try each of the moves in order. Return the number that succeed, scaled by the importance of each critter. In newOrder, if not null, place the moves that are valid.


getCreatureMoveLimit

protected int getCreatureMoveLimit()
Find the maximum number of moves per creature to test, such that numMobileCreaturesInLegion ^ N <= LEGION_MOVE_LIMIT, but we must have at least as many moves as mobile creatures to ensure that every creature has somewhere to go.


findBattleMoves

private java.util.Collection<LegionMove> findBattleMoves()

findBattleMovesOneCritter

private java.util.List<CritterMove> findBattleMovesOneCritter(BattleCritter critter)

setupTimer

java.util.Timer setupTimer()

findBestLegionMove

protected LegionMove findBestLegionMove(java.util.Collection<LegionMove> legionMoves)
Evaluate all legion moves in the list, and return the best one. Break out early if the time limit is exceeded.


findLegionMoves

java.util.Collection<LegionMove> findLegionMoves(java.util.List<java.util.List<CritterMove>> allCritterMoves)
allCritterMoves is a List of sorted MoveLists. A MoveList is a sorted List of CritterMoves for one critter. Return a sorted List of LegionMoves. A LegionMove is a List of one CritterMove per mobile critter in the legion, where no two critters move to the same hex.


evaluateLegionBattleMoveAsAWhole

protected int evaluateLegionBattleMoveAsAWhole(LegionMove lm,
                                               java.util.Map<BattleHex,java.lang.Integer> strikeMap,
                                               ValueRecorder value)

evaluateCritterMove_Titan

protected void evaluateCritterMove_Titan(BattleCritter critter,
                                         ValueRecorder value,
                                         MasterBoardTerrain terrain,
                                         BattleHex hex,
                                         Legion legion,
                                         int turn)
this compute the special case of the Titan critter


evaluateCritterMove_Terrain

private void evaluateCritterMove_Terrain(BattleCritter critter,
                                         ValueRecorder value,
                                         MasterBoardTerrain terrain,
                                         BattleHex hex,
                                         int power,
                                         int skill)
This compute the influence of terrain


evaluateCritterMove_Attacker

private void evaluateCritterMove_Attacker(BattleCritter critter,
                                          ValueRecorder value,
                                          MasterBoardTerrain terrain,
                                          BattleHex hex,
                                          LegionClientSide legion,
                                          int turn)
this compute for non-titan attacking critter


evaluateCritterMove_Defender

protected void evaluateCritterMove_Defender(BattleCritter critter,
                                            ValueRecorder value,
                                            MasterBoardTerrain terrain,
                                            BattleHex hex,
                                            LegionClientSide legion,
                                            int turn)
this compute for non-titan defending critter


evaluateCritterMove_Rangestrike

protected void evaluateCritterMove_Rangestrike(BattleCritter critter,
                                               java.util.Map<BattleHex,java.lang.Integer> strikeMap,
                                               ValueRecorder value,
                                               MasterBoardTerrain terrain,
                                               BattleHex hex,
                                               int power,
                                               int skill,
                                               LegionClientSide legion,
                                               int turn,
                                               java.util.Set<BattleHex> targetHexes)

evaluateCritterMove_Strike

protected void evaluateCritterMove_Strike(BattleCritter critter,
                                          java.util.Map<BattleHex,java.lang.Integer> strikeMap,
                                          ValueRecorder value,
                                          MasterBoardTerrain terrain,
                                          BattleHex hex,
                                          int power,
                                          int skill,
                                          LegionClientSide legion,
                                          int turn,
                                          java.util.Set<BattleHex> targetHexes)

evaluateCritterMove

private int evaluateCritterMove(BattleCritter critter,
                                java.util.Map<BattleHex,java.lang.Integer> strikeMap,
                                ValueRecorder value)
strikeMap is optional


evaluateLegionBattleMove

protected int evaluateLegionBattleMove(LegionMove lm)