use of games.strategy.engine.data.Territory in project triplea by triplea-game.
the class ProTechAi method findUnitTerr.
/**
* Return Territories containing any unit depending on unitCondition
* Differs from findCertainShips because it doesn't require the units be owned.
*/
private static List<Territory> findUnitTerr(final GameData data, final Predicate<Unit> unitCondition) {
// Return territories containing a certain unit or set of Units
final List<Territory> shipTerr = new ArrayList<>();
final Collection<Territory> neighbors = data.getMap().getTerritories();
for (final Territory t2 : neighbors) {
if (t2.getUnits().anyMatch(unitCondition)) {
shipTerr.add(t2);
}
}
return shipTerr;
}
use of games.strategy.engine.data.Territory in project triplea by triplea-game.
the class ProTechAi method getNeighboringLandTerritories.
/**
* All Allied Territories which neighbor a territory
* This duplicates getNeighbors(check, Matches.isTerritoryAllied(player, data))
*/
private static List<Territory> getNeighboringLandTerritories(final GameData data, final PlayerID player, final Territory check) {
final List<Territory> territories = new ArrayList<>();
final List<Territory> checkList = getExactNeighbors(check, data);
for (final Territory t : checkList) {
if (Matches.isTerritoryAllied(player, data).test(t) && Matches.territoryIsNotImpassableToLandUnits(player, data).test(t)) {
territories.add(t);
}
}
return territories;
}
use of games.strategy.engine.data.Territory 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.engine.data.Territory 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.engine.data.Territory 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;
}
}
}
Aggregations