use of games.strategy.triplea.ai.pro.data.ProTerritoryManager in project triplea by triplea-game.
the class ProPurchaseAi method bid.
/**
* Default settings for bidding:
* 1) Limit one bid unit in a territory or sea zone (until set in all territories then 2, etc).
* 2) The nation placing a unit in a territory or sea zone must have started with a unit in said territory or sea zone
* prior to placing the bid.
*/
Map<Territory, ProPurchaseTerritory> bid(final int pus, final IPurchaseDelegate purchaseDelegate, final GameData startOfTurnData) {
// Current data fields
data = ProData.getData();
this.startOfTurnData = startOfTurnData;
player = ProData.getPlayer();
resourceTracker = new ProResourceTracker(pus, data);
territoryManager = new ProTerritoryManager(calc);
isBid = true;
final ProPurchaseOptionMap purchaseOptions = ProData.purchaseOptions;
ProLogger.info("Starting bid phase with resources: " + resourceTracker);
if (!player.getUnits().getUnits().isEmpty()) {
ProLogger.info("Starting bid phase with unplaced units=" + player.getUnits().getUnits());
}
// Find all purchase/place territories
final Map<Territory, ProPurchaseTerritory> purchaseTerritories = ProPurchaseUtils.findBidTerritories(player);
int previousNumUnits = 0;
while (true) {
// Determine max enemy attack units and current allied defenders
territoryManager.populateEnemyAttackOptions(new ArrayList<>(), new ArrayList<>(purchaseTerritories.keySet()));
findDefendersInPlaceTerritories(purchaseTerritories);
// Prioritize land territories that need defended and purchase additional defenders
final List<ProPlaceTerritory> needToDefendLandTerritories = prioritizeTerritoriesToDefend(purchaseTerritories, true);
purchaseDefenders(purchaseTerritories, needToDefendLandTerritories, purchaseOptions.getLandFodderOptions(), purchaseOptions.getAirOptions(), true);
// Find strategic value for each territory
ProLogger.info("Find strategic value for place territories");
final Map<Territory, Double> territoryValueMap = ProTerritoryValueUtils.findTerritoryValues(player, new ArrayList<>(), new ArrayList<>());
for (final ProPurchaseTerritory t : purchaseTerritories.values()) {
for (final ProPlaceTerritory ppt : t.getCanPlaceTerritories()) {
ppt.setStrategicValue(territoryValueMap.get(ppt.getTerritory()));
ProLogger.debug(ppt.getTerritory() + ", strategicValue=" + territoryValueMap.get(ppt.getTerritory()));
}
}
// Prioritize land place options purchase AA then land units
final List<ProPlaceTerritory> prioritizedLandTerritories = prioritizeLandTerritories(purchaseTerritories);
purchaseAaUnits(purchaseTerritories, prioritizedLandTerritories, purchaseOptions.getAaOptions());
purchaseLandUnits(purchaseTerritories, prioritizedLandTerritories, purchaseOptions, territoryValueMap);
// Prioritize sea territories that need defended and purchase additional defenders
final List<ProPlaceTerritory> needToDefendSeaTerritories = prioritizeTerritoriesToDefend(purchaseTerritories, false);
purchaseDefenders(purchaseTerritories, needToDefendSeaTerritories, purchaseOptions.getSeaDefenseOptions(), purchaseOptions.getAirOptions(), false);
// Prioritize sea place options and purchase units
final List<ProPlaceTerritory> prioritizedSeaTerritories = prioritizeSeaTerritories(purchaseTerritories);
purchaseSeaAndAmphibUnits(purchaseTerritories, prioritizedSeaTerritories, territoryValueMap, purchaseOptions);
// Try to use any remaining PUs on high value units
purchaseUnitsWithRemainingProduction(purchaseTerritories, purchaseOptions.getLandOptions(), purchaseOptions.getAirOptions());
upgradeUnitsWithRemainingPUs(purchaseTerritories, purchaseOptions);
// Check if no remaining PUs or no unit built this iteration
final int numUnits = purchaseTerritories.values().stream().map(ProPurchaseTerritory::getCanPlaceTerritories).map(t -> t.get(0)).map(ProPlaceTerritory::getPlaceUnits).mapToInt(List::size).sum();
if (resourceTracker.isEmpty() || numUnits == previousNumUnits) {
break;
}
previousNumUnits = numUnits;
ProPurchaseUtils.incrementUnitProductionForBidTerritories(purchaseTerritories);
}
// Determine final count of each production rule
final IntegerMap<ProductionRule> purchaseMap = populateProductionRuleMap(purchaseTerritories, purchaseOptions);
// Purchase units
ProMetricUtils.collectPurchaseStats(purchaseMap);
final String error = purchaseDelegate.purchase(purchaseMap);
if (error != null) {
ProLogger.warn("Purchase error: " + error);
}
return purchaseTerritories;
}
use of games.strategy.triplea.ai.pro.data.ProTerritoryManager in project triplea by triplea-game.
the class ProNonCombatMoveAi method doNonCombatMove.
Map<Territory, ProTerritory> doNonCombatMove(Map<Territory, ProTerritory> factoryMoveMap, final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final IMoveDelegate moveDel) {
ProLogger.info("Starting non-combat move phase");
// Current data at the start of non-combat move
data = ProData.getData();
player = ProData.getPlayer();
unitTerritoryMap = ProData.unitTerritoryMap;
territoryManager = new ProTerritoryManager(calc);
// Find the max number of units that can move to each allied territory
territoryManager.populateDefenseOptions(new ArrayList<>());
// Find number of units in each move territory that can't move and all infra units
findUnitsThatCantMove(purchaseTerritories, ProData.purchaseOptions.getLandOptions());
final Map<Unit, Set<Territory>> infraUnitMoveMap = findInfraUnitsThatCanMove();
// Try to have one land unit in each territory that is bordering an enemy territory
final List<Territory> movedOneDefenderToTerritories = moveOneDefenderToLandTerritoriesBorderingEnemy();
// Determine max enemy attack units and if territories can be held
territoryManager.populateEnemyAttackOptions(movedOneDefenderToTerritories, territoryManager.getDefendTerritories());
determineIfMoveTerritoriesCanBeHeld();
// Get list of territories that can't be held and find move value for each territory
final List<Territory> territoriesThatCantBeHeld = territoryManager.getCantHoldTerritories();
final Map<Territory, Double> territoryValueMap = ProTerritoryValueUtils.findTerritoryValues(player, territoriesThatCantBeHeld, new ArrayList<>());
final Map<Territory, Double> seaTerritoryValueMap = ProTerritoryValueUtils.findSeaTerritoryValues(player, territoriesThatCantBeHeld);
// Prioritize territories to defend
final List<ProTerritory> prioritizedTerritories = prioritizeDefendOptions(factoryMoveMap, territoryValueMap);
// Determine which territories to defend and how many units each one needs
final int enemyDistance = ProUtils.getClosestEnemyLandTerritoryDistance(data, player, ProData.myCapital);
moveUnitsToDefendTerritories(prioritizedTerritories, enemyDistance, territoryValueMap);
// Copy data in case capital defense needs increased
final ProTerritoryManager territoryManagerCopy = new ProTerritoryManager(calc, territoryManager);
// Use loop to ensure capital is protected after moves
if (ProData.myCapital != null) {
int defenseRange = -1;
while (true) {
// Add value to territories near capital if necessary
for (final Territory t : territoryManager.getDefendTerritories()) {
double value = territoryValueMap.get(t);
final int distance = data.getMap().getDistance(ProData.myCapital, t, ProMatches.territoryCanMoveLandUnits(player, data, false));
if (distance >= 0 && distance <= defenseRange) {
value *= 10;
}
territoryManager.getDefendOptions().getTerritoryMap().get(t).setValue(value);
if (t.isWater()) {
territoryManager.getDefendOptions().getTerritoryMap().get(t).setSeaValue(seaTerritoryValueMap.get(t));
}
}
moveUnitsToBestTerritories();
// Check if capital has local land superiority
ProLogger.info("Checking if capital has local land superiority with enemyDistance=" + enemyDistance);
if (enemyDistance >= 2 && enemyDistance <= 3 && defenseRange == -1 && !ProBattleUtils.territoryHasLocalLandSuperiorityAfterMoves(ProData.myCapital, enemyDistance, player, territoryManager.getDefendOptions().getTerritoryMap())) {
defenseRange = enemyDistance - 1;
territoryManager = territoryManagerCopy;
ProLogger.debug("Capital doesn't have local land superiority so setting defensive stance");
} else {
break;
}
}
} else {
moveUnitsToBestTerritories();
}
// Determine where to move infra units
factoryMoveMap = moveInfraUnits(factoryMoveMap, infraUnitMoveMap);
// Log a warning if any units not assigned to a territory (skip infrastructure for now)
for (final Unit u : territoryManager.getDefendOptions().getUnitMoveMap().keySet()) {
if (Matches.unitIsInfrastructure().negate().test(u)) {
ProLogger.warn(player + ": " + unitTerritoryMap.get(u) + " has unmoved unit: " + u + " with options: " + territoryManager.getDefendOptions().getUnitMoveMap().get(u));
}
}
// Calculate move routes and perform moves
doMove(territoryManager.getDefendOptions().getTerritoryMap(), moveDel, data, player);
// Log results
ProLogger.info("Logging results");
logAttackMoves(prioritizedTerritories);
return factoryMoveMap;
}
use of games.strategy.triplea.ai.pro.data.ProTerritoryManager in project triplea by triplea-game.
the class ProCombatMoveAi method doCombatMove.
Map<Territory, ProTerritory> doCombatMove(final IMoveDelegate moveDel) {
ProLogger.info("Starting combat move phase");
// Current data at the start of combat move
data = ProData.getData();
player = ProData.getPlayer();
territoryManager = new ProTerritoryManager(calc);
// Determine whether capital is threatened and I should be in a defensive stance
isDefensive = !ProBattleUtils.territoryHasLocalLandSuperiority(ProData.myCapital, ProBattleUtils.MEDIUM_RANGE, player);
isBombing = false;
ProLogger.debug("Currently in defensive stance: " + isDefensive);
// Find the maximum number of units that can attack each territory and max enemy defenders
territoryManager.populateAttackOptions();
territoryManager.populateEnemyDefenseOptions();
// Remove territories that aren't worth attacking and prioritize the remaining ones
final List<ProTerritory> attackOptions = territoryManager.removeTerritoriesThatCantBeConquered();
List<Territory> clearedTerritories = new ArrayList<>();
for (final ProTerritory patd : attackOptions) {
clearedTerritories.add(patd.getTerritory());
}
territoryManager.populateEnemyAttackOptions(clearedTerritories, clearedTerritories);
Set<Territory> territoriesToCheck = new HashSet<>(clearedTerritories);
territoriesToCheck.addAll(ProData.myUnitTerritories);
Map<Territory, Double> territoryValueMap = ProTerritoryValueUtils.findTerritoryValues(player, new ArrayList<>(), clearedTerritories, territoriesToCheck);
determineTerritoriesThatCanBeHeld(attackOptions, territoryValueMap);
prioritizeAttackOptions(player, attackOptions);
removeTerritoriesThatArentWorthAttacking(attackOptions);
// Determine which territories to attack
determineTerritoriesToAttack(attackOptions);
// Determine which territories can be held and remove any that aren't worth attacking
clearedTerritories = new ArrayList<>();
final Set<Territory> possibleTransportTerritories = new HashSet<>();
for (final ProTerritory patd : attackOptions) {
clearedTerritories.add(patd.getTerritory());
if (!patd.getAmphibAttackMap().isEmpty()) {
possibleTransportTerritories.addAll(data.getMap().getNeighbors(patd.getTerritory(), Matches.territoryIsWater()));
}
}
possibleTransportTerritories.addAll(clearedTerritories);
territoryManager.populateEnemyAttackOptions(clearedTerritories, new ArrayList<>(possibleTransportTerritories));
territoriesToCheck = new HashSet<>(clearedTerritories);
territoriesToCheck.addAll(ProData.myUnitTerritories);
territoryValueMap = ProTerritoryValueUtils.findTerritoryValues(player, new ArrayList<>(), clearedTerritories, territoriesToCheck);
determineTerritoriesThatCanBeHeld(attackOptions, territoryValueMap);
removeTerritoriesThatArentWorthAttacking(attackOptions);
// Determine how many units to attack each territory with
final List<Unit> alreadyMovedUnits = moveOneDefenderToLandTerritoriesBorderingEnemy(attackOptions);
determineUnitsToAttackWith(attackOptions, alreadyMovedUnits);
// Get all transport final territories
ProMoveUtils.calculateAmphibRoutes(player, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), territoryManager.getAttackOptions().getTerritoryMap(), true);
// Determine max enemy counter attack units and remove territories where transports are exposed
removeTerritoriesWhereTransportsAreExposed();
// Determine if capital can be held if I still own it
if (ProData.myCapital != null && ProData.myCapital.getOwner().equals(player)) {
removeAttacksUntilCapitalCanBeHeld(attackOptions, ProData.purchaseOptions.getLandOptions());
}
// Check if any subs in contested territory that's not being attacked
checkContestedSeaTerritories();
// Calculate attack routes and perform moves
doMove(territoryManager.getAttackOptions().getTerritoryMap(), moveDel, data, player);
// Set strafing territories to avoid retreats
ai.setStoredStrafingTerritories(territoryManager.getStrafingTerritories());
ProLogger.info("Strafing territories: " + territoryManager.getStrafingTerritories());
// Log results
ProLogger.info("Logging results");
logAttackMoves(attackOptions);
return territoryManager.getAttackOptions().getTerritoryMap();
}
use of games.strategy.triplea.ai.pro.data.ProTerritoryManager in project triplea by triplea-game.
the class ProPoliticsAi method politicalActions.
List<PoliticalActionAttachment> politicalActions() {
final GameData data = ProData.getData();
final PlayerID player = ProData.getPlayer();
final float numPlayers = data.getPlayerList().getPlayers().size();
final double round = data.getSequence().getRound();
final ProTerritoryManager territoryManager = new ProTerritoryManager(calc);
final PoliticsDelegate politicsDelegate = DelegateFinder.politicsDelegate(data);
ProLogger.info("Politics for " + player.getName());
// Find valid war actions
final List<PoliticalActionAttachment> actionChoicesTowardsWar = AiPoliticalUtils.getPoliticalActionsTowardsWar(player, politicsDelegate.getTestedConditions(), data);
ProLogger.trace("War options: " + actionChoicesTowardsWar);
final List<PoliticalActionAttachment> validWarActions = CollectionUtils.getMatches(actionChoicesTowardsWar, Matches.abstractUserActionAttachmentCanBeAttempted(politicsDelegate.getTestedConditions()));
ProLogger.trace("Valid War options: " + validWarActions);
// Divide war actions into enemy and neutral
final Map<PoliticalActionAttachment, List<PlayerID>> enemyMap = new HashMap<>();
final Map<PoliticalActionAttachment, List<PlayerID>> neutralMap = new HashMap<>();
for (final PoliticalActionAttachment action : validWarActions) {
final List<PlayerID> warPlayers = new ArrayList<>();
for (final String relationshipChange : action.getRelationshipChange()) {
final String[] s = relationshipChange.split(":");
final PlayerID player1 = data.getPlayerList().getPlayerId(s[0]);
final PlayerID player2 = data.getPlayerList().getPlayerId(s[1]);
final RelationshipType oldRelation = data.getRelationshipTracker().getRelationshipType(player1, player2);
final RelationshipType newRelation = data.getRelationshipTypeList().getRelationshipType(s[2]);
if (!oldRelation.equals(newRelation) && Matches.relationshipTypeIsAtWar().test(newRelation) && (player1.equals(player) || player2.equals(player))) {
PlayerID warPlayer = player2;
if (warPlayer.equals(player)) {
warPlayer = player1;
}
warPlayers.add(warPlayer);
}
}
if (!warPlayers.isEmpty()) {
if (ProUtils.isNeutralPlayer(warPlayers.get(0))) {
neutralMap.put(action, warPlayers);
} else {
enemyMap.put(action, warPlayers);
}
}
}
ProLogger.debug("Neutral options: " + neutralMap);
ProLogger.debug("Enemy options: " + enemyMap);
final List<PoliticalActionAttachment> results = new ArrayList<>();
if (!enemyMap.isEmpty()) {
// Find all attack options
territoryManager.populatePotentialAttackOptions();
final List<ProTerritory> attackOptions = territoryManager.removePotentialTerritoriesThatCantBeConquered();
ProLogger.trace(player.getName() + ", numAttackOptions=" + attackOptions.size() + ", options=" + attackOptions);
// Find attack options per war action
final Map<PoliticalActionAttachment, Double> attackPercentageMap = new HashMap<>();
for (final PoliticalActionAttachment action : enemyMap.keySet()) {
int count = 0;
final List<PlayerID> enemyPlayers = enemyMap.get(action);
for (final ProTerritory patd : attackOptions) {
if (Matches.isTerritoryOwnedBy(enemyPlayers).test(patd.getTerritory()) || Matches.territoryHasUnitsThatMatch(Matches.unitOwnedBy(enemyPlayers)).test(patd.getTerritory())) {
count++;
}
}
final double attackPercentage = count / (attackOptions.size() + 1.0);
attackPercentageMap.put(action, attackPercentage);
ProLogger.trace(enemyPlayers + ", count=" + count + ", attackPercentage=" + attackPercentage);
}
// Decide whether to declare war on an enemy
final List<PoliticalActionAttachment> options = new ArrayList<>(attackPercentageMap.keySet());
Collections.shuffle(options);
for (final PoliticalActionAttachment action : options) {
// 0, .05, .1, .15, etc
final double roundFactor = (round - 1) * .05;
final double warChance = roundFactor + attackPercentageMap.get(action) * (1 + 10 * roundFactor);
final double random = Math.random();
ProLogger.trace(enemyMap.get(action) + ", warChance=" + warChance + ", random=" + random);
if (random <= warChance) {
results.add(action);
ProLogger.debug("---Declared war on " + enemyMap.get(action));
break;
}
}
} else if (!neutralMap.isEmpty()) {
// Decide whether to declare war on a neutral
final List<PoliticalActionAttachment> options = new ArrayList<>(neutralMap.keySet());
Collections.shuffle(options);
final double random = Math.random();
final double warChance = .01;
ProLogger.debug("warChance=" + warChance + ", random=" + random);
if (random <= warChance) {
results.add(options.get(0));
ProLogger.debug("Declared war on " + enemyMap.get(options.get(0)));
}
}
// Old code used for non-war actions
if (Math.random() < .5) {
final List<PoliticalActionAttachment> actionChoicesOther = AiPoliticalUtils.getPoliticalActionsOther(player, politicsDelegate.getTestedConditions(), data);
if (actionChoicesOther != null && !actionChoicesOther.isEmpty()) {
Collections.shuffle(actionChoicesOther);
int i = 0;
final double random = Math.random();
final int maxOtherActionsPerTurn = (random < .3 ? 0 : (random < .6 ? 1 : (random < .9 ? 2 : (random < .99 ? 3 : (int) numPlayers))));
final Iterator<PoliticalActionAttachment> actionOtherIter = actionChoicesOther.iterator();
while (actionOtherIter.hasNext() && maxOtherActionsPerTurn > 0) {
final PoliticalActionAttachment action = actionOtherIter.next();
if (!Matches.abstractUserActionAttachmentCanBeAttempted(politicsDelegate.getTestedConditions()).test(action)) {
continue;
}
if (action.getCostPu() > 0 && action.getCostPu() > player.getResources().getQuantity(Constants.PUS)) {
continue;
}
i++;
if (i > maxOtherActionsPerTurn) {
break;
}
results.add(action);
}
}
}
doActions(results);
return results;
}
use of games.strategy.triplea.ai.pro.data.ProTerritoryManager in project triplea by triplea-game.
the class ProPurchaseAi method place.
void place(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final IAbstractPlaceDelegate placeDelegate) {
ProLogger.info("Starting place phase");
data = ProData.getData();
player = ProData.getPlayer();
territoryManager = new ProTerritoryManager(calc);
if (purchaseTerritories != null) {
// Place all units calculated during purchase phase (land then sea to reduce failed placements)
for (final ProPurchaseTerritory t : purchaseTerritories.values()) {
for (final ProPlaceTerritory ppt : t.getCanPlaceTerritories()) {
if (!ppt.getTerritory().isWater()) {
final List<Unit> unitsToPlace = new ArrayList<>();
for (final Unit placeUnit : ppt.getPlaceUnits()) {
for (final Unit myUnit : player.getUnits()) {
if (myUnit.getType().equals(placeUnit.getType()) && !unitsToPlace.contains(myUnit)) {
unitsToPlace.add(myUnit);
break;
}
}
}
doPlace(data.getMap().getTerritory(ppt.getTerritory().getName()), unitsToPlace, placeDelegate);
ProLogger.debug(ppt.getTerritory() + " placed units: " + unitsToPlace);
}
}
}
for (final ProPurchaseTerritory t : purchaseTerritories.values()) {
for (final ProPlaceTerritory ppt : t.getCanPlaceTerritories()) {
if (ppt.getTerritory().isWater()) {
final List<Unit> unitsToPlace = new ArrayList<>();
for (final Unit placeUnit : ppt.getPlaceUnits()) {
for (final Unit myUnit : player.getUnits()) {
if (myUnit.getType().equals(placeUnit.getType()) && !unitsToPlace.contains(myUnit)) {
unitsToPlace.add(myUnit);
break;
}
}
}
doPlace(data.getMap().getTerritory(ppt.getTerritory().getName()), unitsToPlace, placeDelegate);
ProLogger.debug(ppt.getTerritory() + " placed units: " + unitsToPlace);
}
}
}
}
// Place remaining units (currently only implemented to handle land units, ex. WW2v3 China)
if (player.getUnits().getUnits().isEmpty()) {
return;
}
// Current data at the start of place
ProLogger.debug("Remaining units to place: " + player.getUnits().getUnits());
// Find all place territories
final Map<Territory, ProPurchaseTerritory> placeNonConstructionTerritories = ProPurchaseUtils.findPurchaseTerritories(player);
// Determine max enemy attack units and current allied defenders
findDefendersInPlaceTerritories(placeNonConstructionTerritories);
// Prioritize land territories that need defended and place additional defenders
final List<ProPlaceTerritory> needToDefendLandTerritories = prioritizeTerritoriesToDefend(placeNonConstructionTerritories, true);
placeDefenders(placeNonConstructionTerritories, needToDefendLandTerritories, placeDelegate);
// Find strategic value for each territory
ProLogger.info("Find strategic value for place territories");
final Map<Territory, Double> territoryValueMap = ProTerritoryValueUtils.findTerritoryValues(player, new ArrayList<>(), new ArrayList<>());
for (final ProPurchaseTerritory t : placeNonConstructionTerritories.values()) {
for (final ProPlaceTerritory ppt : t.getCanPlaceTerritories()) {
ppt.setStrategicValue(territoryValueMap.get(ppt.getTerritory()));
ProLogger.debug(ppt.getTerritory() + ", strategicValue=" + territoryValueMap.get(ppt.getTerritory()));
}
}
// Prioritize land place territories, add all territories, and then place units
final List<ProPlaceTerritory> prioritizedLandTerritories = prioritizeLandTerritories(placeNonConstructionTerritories);
for (final ProPurchaseTerritory ppt : placeNonConstructionTerritories.values()) {
for (final ProPlaceTerritory placeTerritory : ppt.getCanPlaceTerritories()) {
final Territory t = placeTerritory.getTerritory();
if (!t.isWater() && !prioritizedLandTerritories.contains(placeTerritory)) {
prioritizedLandTerritories.add(placeTerritory);
}
}
}
// Place regular land units
placeLandUnits(prioritizedLandTerritories, placeDelegate, false);
// Place isConstruction land units (needs separated since placeDelegate.getPlaceableUnits doesn't handle combined)
placeLandUnits(prioritizedLandTerritories, placeDelegate, true);
}
Aggregations