use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProTransportUtils method getUnitsToTransportThatCantMoveToHigherValue.
public static List<Unit> getUnitsToTransportThatCantMoveToHigherValue(final PlayerID player, final Unit transport, final Set<Territory> territoriesToLoadFrom, final List<Unit> unitsToIgnore, final Map<Territory, ProTerritory> moveMap, final Map<Unit, Set<Territory>> unitMoveMap, final double value) {
final List<Unit> unitsToIgnoreOrHaveBetterLandMove = new ArrayList<>(unitsToIgnore);
if (!TransportTracker.isTransporting(transport)) {
// Get all units that can be transported
final List<Unit> units = new ArrayList<>();
for (final Territory loadFrom : territoriesToLoadFrom) {
units.addAll(loadFrom.getUnits().getMatches(ProMatches.unitIsOwnedTransportableUnitAndCanBeLoaded(player, transport, true)));
}
units.removeAll(unitsToIgnore);
// Check to see which have higher land move value
for (final Unit u : units) {
if (unitMoveMap.get(u) != null) {
for (final Territory t : unitMoveMap.get(u)) {
if (moveMap.get(t) != null && moveMap.get(t).getValue() > value) {
unitsToIgnoreOrHaveBetterLandMove.add(u);
break;
}
}
}
}
}
return getUnitsToTransportFromTerritories(player, transport, territoriesToLoadFrom, unitsToIgnoreOrHaveBetterLandMove);
}
use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProCombatMoveAi method prioritizeAttackOptions.
private List<ProTerritory> prioritizeAttackOptions(final PlayerID player, final List<ProTerritory> attackOptions) {
ProLogger.info("Prioritizing territories to try to attack");
// Calculate value of attacking territory
for (final Iterator<ProTerritory> it = attackOptions.iterator(); it.hasNext(); ) {
final ProTerritory patd = it.next();
final Territory t = patd.getTerritory();
// Determine territory attack properties
final int isLand = !t.isWater() ? 1 : 0;
final int isNeutral = (!t.isWater() && t.getOwner().isNull()) ? 1 : 0;
final int isCanHold = patd.isCanHold() ? 1 : 0;
final int isAmphib = patd.isNeedAmphibUnits() ? 1 : 0;
final List<Unit> defendingUnits = CollectionUtils.getMatches(patd.getMaxEnemyDefenders(player, data), ProMatches.unitIsEnemyAndNotInfa(player, data));
final int isEmptyLand = (defendingUnits.isEmpty() && !patd.isNeedAmphibUnits()) ? 1 : 0;
final boolean isAdjacentToMyCapital = !data.getMap().getNeighbors(t, Matches.territoryIs(ProData.myCapital)).isEmpty();
final int isNotNeutralAdjacentToMyCapital = (isAdjacentToMyCapital && ProMatches.territoryIsEnemyNotNeutralLand(player, data).test(t)) ? 1 : 0;
final int isFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t) ? 1 : 0;
final int isFfa = ProUtils.isFfa(data, player) ? 1 : 0;
// Determine production value and if it is an enemy capital
int production = 0;
int isEnemyCapital = 0;
final TerritoryAttachment ta = TerritoryAttachment.get(t);
if (ta != null) {
production = ta.getProduction();
if (ta.isCapital()) {
isEnemyCapital = 1;
}
}
// Calculate attack value for prioritization
double tuvSwing = patd.getMaxBattleResult().getTuvSwing();
if (isFfa == 1 && tuvSwing > 0) {
tuvSwing *= 0.5;
}
final double territoryValue = (1 + isLand + isCanHold * (1 + 2 * isFfa)) * (1 + isEmptyLand) * (1 + isFactory) * (1 - 0.5 * isAmphib) * production;
double attackValue = (tuvSwing + territoryValue) * (1 + 4 * isEnemyCapital) * (1 + 2 * isNotNeutralAdjacentToMyCapital) * (1 - 0.9 * isNeutral);
// Check if a negative value neutral territory should be attacked
if (attackValue <= 0 && !patd.isNeedAmphibUnits() && !t.isWater() && t.getOwner().isNull()) {
// Determine enemy neighbor territory production value for neutral land territories
double nearbyEnemyValue = 0;
final List<Territory> cantReachEnemyTerritories = new ArrayList<>();
final Set<Territory> nearbyTerritories = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveLandUnits(player, data, true));
final List<Territory> nearbyEnemyTerritories = CollectionUtils.getMatches(nearbyTerritories, Matches.isTerritoryEnemy(player, data));
final List<Territory> nearbyTerritoriesWithOwnedUnits = CollectionUtils.getMatches(nearbyTerritories, Matches.territoryHasUnitsOwnedBy(player));
for (final Territory nearbyEnemyTerritory : nearbyEnemyTerritories) {
boolean allAlliedNeighborsHaveRoute = true;
for (final Territory nearbyAlliedTerritory : nearbyTerritoriesWithOwnedUnits) {
final int distance = data.getMap().getDistance_IgnoreEndForCondition(nearbyAlliedTerritory, nearbyEnemyTerritory, ProMatches.territoryIsEnemyNotNeutralOrAllied(player, data));
if (distance < 0 || distance > 2) {
allAlliedNeighborsHaveRoute = false;
break;
}
}
if (!allAlliedNeighborsHaveRoute) {
final double value = ProTerritoryValueUtils.findTerritoryAttackValue(player, nearbyEnemyTerritory);
if (value > 0) {
nearbyEnemyValue += value;
}
cantReachEnemyTerritories.add(nearbyEnemyTerritory);
}
}
ProLogger.debug(t.getName() + " calculated nearby enemy value=" + nearbyEnemyValue + " from " + cantReachEnemyTerritories);
if (nearbyEnemyValue > 0) {
ProLogger.trace(t.getName() + " updating negative neutral attack value=" + attackValue);
attackValue = nearbyEnemyValue * .001 / (1 - attackValue);
} else {
// Check if overwhelming attack strength (more than 5 times)
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, patd.getMaxUnits(), patd.getMaxEnemyDefenders(player, data));
ProLogger.debug(t.getName() + " calculated strengthDifference=" + strengthDifference);
if (strengthDifference > 500) {
ProLogger.trace(t.getName() + " updating negative neutral attack value=" + attackValue);
attackValue = strengthDifference * .00001 / (1 - attackValue);
}
}
}
// Remove negative value territories
patd.setValue(attackValue);
if (attackValue <= 0 || (isDefensive && attackValue <= 8 && data.getMap().getDistance(ProData.myCapital, t) <= 3)) {
ProLogger.debug("Removing territory that has a negative attack value: " + t.getName() + ", AttackValue=" + patd.getValue());
it.remove();
}
}
// Sort attack territories by value
attackOptions.sort(Comparator.comparingDouble(ProTerritory::getValue));
// Log prioritized territories
for (final ProTerritory patd : attackOptions) {
ProLogger.debug("AttackValue=" + patd.getValue() + ", TUVSwing=" + patd.getMaxBattleResult().getTuvSwing() + ", isAmphib=" + patd.isNeedAmphibUnits() + ", " + patd.getTerritory().getName());
}
return attackOptions;
}
use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProCombatMoveAi method determineTerritoriesToAttack.
private void determineTerritoriesToAttack(final List<ProTerritory> prioritizedTerritories) {
ProLogger.info("Determine which territories to attack");
// Assign units to territories by prioritization
int numToAttack = Math.min(1, prioritizedTerritories.size());
boolean haveRemovedAllAmphibTerritories = false;
while (true) {
final List<ProTerritory> territoriesToTryToAttack = prioritizedTerritories.subList(0, numToAttack);
ProLogger.debug("Current number of territories: " + numToAttack);
tryToAttackTerritories(territoriesToTryToAttack, new ArrayList<>());
// Determine if all attacks are successful
boolean areSuccessful = true;
for (final ProTerritory patd : territoriesToTryToAttack) {
final Territory t = patd.getTerritory();
if (patd.getBattleResult() == null) {
patd.setBattleResult(calc.estimateAttackBattleResults(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data), patd.getBombardTerritoryMap().keySet()));
}
ProLogger.trace(patd.getResultString() + " with attackers: " + patd.getUnits());
final double estimate = ProBattleUtils.estimateStrengthDifference(t, patd.getUnits(), patd.getMaxEnemyDefenders(player, data));
final ProBattleResult result = patd.getBattleResult();
if (!patd.isStrafing() && estimate < patd.getStrengthEstimate() && (result.getWinPercentage() < ProData.minWinPercentage || !result.isHasLandUnitRemaining())) {
areSuccessful = false;
}
}
// Determine whether to try more territories, remove a territory, or end
if (areSuccessful) {
for (final ProTerritory patd : territoriesToTryToAttack) {
patd.setCanAttack(true);
final double estimate = ProBattleUtils.estimateStrengthDifference(patd.getTerritory(), patd.getUnits(), patd.getMaxEnemyDefenders(player, data));
if (estimate < patd.getStrengthEstimate()) {
patd.setStrengthEstimate(estimate);
}
}
// If already used all transports then remove any remaining amphib territories
if (!haveRemovedAllAmphibTerritories) {
if (territoryManager.haveUsedAllAttackTransports()) {
final List<ProTerritory> amphibTerritoriesToRemove = new ArrayList<>();
for (int i = numToAttack; i < prioritizedTerritories.size(); i++) {
if (prioritizedTerritories.get(i).isNeedAmphibUnits()) {
amphibTerritoriesToRemove.add(prioritizedTerritories.get(i));
ProLogger.debug("Removing amphib territory since already used all transports: " + prioritizedTerritories.get(i).getTerritory().getName());
}
}
prioritizedTerritories.removeAll(amphibTerritoriesToRemove);
haveRemovedAllAmphibTerritories = true;
}
}
// Can attack all territories in list so end
numToAttack++;
if (numToAttack > prioritizedTerritories.size()) {
break;
}
} else {
ProLogger.debug("Removing territory: " + prioritizedTerritories.get(numToAttack - 1).getTerritory().getName());
prioritizedTerritories.remove(numToAttack - 1);
if (numToAttack > prioritizedTerritories.size()) {
numToAttack--;
}
}
}
ProLogger.debug("Final number of territories: " + (numToAttack - 1));
}
use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProCombatMoveAi method removeAttacksUntilCapitalCanBeHeld.
private void removeAttacksUntilCapitalCanBeHeld(final List<ProTerritory> prioritizedTerritories, final List<ProPurchaseOption> landPurchaseOptions) {
ProLogger.info("Check capital defenses after attack moves");
final Map<Territory, ProTerritory> attackMap = territoryManager.getAttackOptions().getTerritoryMap();
final Territory myCapital = ProData.myCapital;
// Add max purchase defenders to capital for non-mobile factories (don't consider mobile factories since they may
// move elsewhere)
final List<Unit> placeUnits = new ArrayList<>();
if (ProMatches.territoryHasNonMobileInfraFactoryAndIsNotConqueredOwnedLand(player, data).test(myCapital)) {
placeUnits.addAll(ProPurchaseUtils.findMaxPurchaseDefenders(player, myCapital, landPurchaseOptions));
}
// Remove attack until capital can be defended
while (true) {
if (prioritizedTerritories.isEmpty()) {
break;
}
// Determine max enemy counter attack units
final List<Territory> territoriesToAttack = new ArrayList<>();
for (final ProTerritory t : prioritizedTerritories) {
territoriesToAttack.add(t.getTerritory());
}
ProLogger.trace("Remaining territories to attack=" + territoriesToAttack);
final List<Territory> territoriesToCheck = new ArrayList<>();
territoriesToCheck.add(myCapital);
territoryManager.populateEnemyAttackOptions(territoriesToAttack, territoriesToCheck);
final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
if (enemyAttackOptions.getMax(myCapital) == null) {
break;
}
// Find max remaining defenders
final Set<Territory> territoriesAdjacentToCapital = data.getMap().getNeighbors(myCapital, Matches.territoryIsLand());
final List<Unit> defenders = myCapital.getUnits().getMatches(Matches.isUnitAllied(player, data));
defenders.addAll(placeUnits);
for (final Territory t : territoriesAdjacentToCapital) {
defenders.addAll(t.getUnits().getMatches(ProMatches.unitCanBeMovedAndIsOwnedLand(player, false)));
}
for (final ProTerritory t : attackMap.values()) {
defenders.removeAll(t.getUnits());
}
// Determine counter attack results to see if I can hold it
final Set<Unit> enemyAttackingUnits = new HashSet<>(enemyAttackOptions.getMax(myCapital).getMaxUnits());
enemyAttackingUnits.addAll(enemyAttackOptions.getMax(myCapital).getMaxAmphibUnits());
final ProBattleResult result = calc.estimateDefendBattleResults(myCapital, new ArrayList<>(enemyAttackingUnits), defenders, enemyAttackOptions.getMax(myCapital).getMaxBombardUnits());
ProLogger.trace("Current capital result hasLandUnitRemaining=" + result.isHasLandUnitRemaining() + ", TUVSwing=" + result.getTuvSwing() + ", defenders=" + defenders.size() + ", attackers=" + enemyAttackingUnits.size());
// Determine attack that uses the most units per value from capital and remove it
if (result.isHasLandUnitRemaining()) {
double maxUnitsNearCapitalPerValue = 0.0;
Territory maxTerritory = null;
final Set<Territory> territoriesNearCapital = data.getMap().getNeighbors(myCapital, Matches.territoryIsLand());
territoriesNearCapital.add(myCapital);
for (final Territory t : attackMap.keySet()) {
int unitsNearCapital = 0;
for (final Unit u : attackMap.get(t).getUnits()) {
if (territoriesNearCapital.contains(ProData.unitTerritoryMap.get(u))) {
unitsNearCapital++;
}
}
final double unitsNearCapitalPerValue = unitsNearCapital / attackMap.get(t).getValue();
ProLogger.trace(t.getName() + " has unit near capital per value: " + unitsNearCapitalPerValue);
if (unitsNearCapitalPerValue > maxUnitsNearCapitalPerValue) {
maxUnitsNearCapitalPerValue = unitsNearCapitalPerValue;
maxTerritory = t;
}
}
if (maxTerritory != null) {
prioritizedTerritories.remove(attackMap.get(maxTerritory));
attackMap.get(maxTerritory).getUnits().clear();
attackMap.get(maxTerritory).getAmphibAttackMap().clear();
attackMap.get(maxTerritory).setBattleResult(null);
ProLogger.debug("Removing territory to try to hold capital: " + maxTerritory.getName());
} else {
break;
}
} else {
ProLogger.debug("Can hold capital: " + myCapital.getName());
break;
}
}
}
use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProCombatMoveAi method removeTerritoriesThatArentWorthAttacking.
private void removeTerritoriesThatArentWorthAttacking(final List<ProTerritory> prioritizedTerritories) {
ProLogger.info("Remove territories that aren't worth attacking");
final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
// Loop through all prioritized territories
for (final Iterator<ProTerritory> it = prioritizedTerritories.iterator(); it.hasNext(); ) {
final ProTerritory patd = it.next();
final Territory t = patd.getTerritory();
ProLogger.debug("Checking territory=" + patd.getTerritory().getName() + " with isAmphib=" + patd.isNeedAmphibUnits());
// Remove empty convoy zones that can't be held
if (!patd.isCanHold() && enemyAttackOptions.getMax(t) != null && t.isWater() && !t.getUnits().anyMatch(Matches.enemyUnit(player, data))) {
ProLogger.debug("Removing convoy zone that can't be held: " + t.getName() + ", enemyAttackers=" + enemyAttackOptions.getMax(t).getMaxUnits());
it.remove();
continue;
}
// Remove neutral and low value amphib land territories that can't be held
final boolean isNeutral = t.getOwner().isNull();
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, patd.getMaxUnits(), patd.getMaxEnemyDefenders(player, data));
if (!patd.isCanHold() && enemyAttackOptions.getMax(t) != null && !t.isWater()) {
if (isNeutral && strengthDifference <= 500) {
// Remove neutral territories that can't be held and don't have overwhelming attack strength
ProLogger.debug("Removing neutral territory that can't be held: " + t.getName() + ", enemyAttackers=" + enemyAttackOptions.getMax(t).getMaxUnits() + ", enemyAmphibAttackers=" + enemyAttackOptions.getMax(t).getMaxAmphibUnits() + ", strengthDifference=" + strengthDifference);
it.remove();
continue;
} else if (patd.isNeedAmphibUnits() && patd.getValue() < 2) {
// Remove amphib territories that aren't worth attacking
ProLogger.debug("Removing low value amphib territory that can't be held: " + t.getName() + ", enemyAttackers=" + enemyAttackOptions.getMax(t).getMaxUnits() + ", enemyAmphibAttackers=" + enemyAttackOptions.getMax(t).getMaxAmphibUnits());
it.remove();
continue;
}
}
// Remove neutral territories where attackers are adjacent to enemy territories that aren't being attacked
if (isNeutral && !t.isWater() && strengthDifference <= 500) {
// Get list of territories I'm attacking
final List<Territory> prioritizedTerritoryList = new ArrayList<>();
for (final ProTerritory prioritizedTerritory : prioritizedTerritories) {
prioritizedTerritoryList.add(prioritizedTerritory.getTerritory());
}
// Find all territories units are attacking from that are adjacent to territory
final Set<Territory> attackFromTerritories = new HashSet<>();
for (final Unit u : patd.getMaxUnits()) {
attackFromTerritories.add(ProData.unitTerritoryMap.get(u));
}
attackFromTerritories.retainAll(data.getMap().getNeighbors(t));
// Determine if any of the attacking from territories has enemy neighbors that aren't being attacked
boolean attackersHaveEnemyNeighbors = false;
Territory attackFromTerritoryWithEnemyNeighbors = null;
for (final Territory attackFromTerritory : attackFromTerritories) {
final Set<Territory> enemyNeighbors = data.getMap().getNeighbors(attackFromTerritory, ProMatches.territoryIsEnemyNotNeutralLand(player, data));
if (!prioritizedTerritoryList.containsAll(enemyNeighbors)) {
attackersHaveEnemyNeighbors = true;
attackFromTerritoryWithEnemyNeighbors = attackFromTerritory;
break;
}
}
if (attackersHaveEnemyNeighbors) {
ProLogger.debug("Removing neutral territory that has attackers that are adjacent to enemies: " + t.getName() + ", attackFromTerritory=" + attackFromTerritoryWithEnemyNeighbors);
it.remove();
}
}
}
}
Aggregations