use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProCombatMoveAi method logAttackMoves.
private void logAttackMoves(final List<ProTerritory> prioritizedTerritories) {
final Map<Territory, ProTerritory> attackMap = territoryManager.getAttackOptions().getTerritoryMap();
// Print prioritization
ProLogger.debug("Prioritized territories:");
for (final ProTerritory attackTerritoryData : prioritizedTerritories) {
ProLogger.trace(" " + attackTerritoryData.getMaxBattleResult().getTuvSwing() + " " + attackTerritoryData.getValue() + " " + attackTerritoryData.getTerritory().getName());
}
// Print enemy territories with enemy units vs my units
ProLogger.debug("Territories that can be attacked:");
int count = 0;
for (final Territory t : attackMap.keySet()) {
count++;
ProLogger.trace(count + ". ---" + t.getName());
final Set<Unit> combinedUnits = new HashSet<>(attackMap.get(t).getMaxUnits());
combinedUnits.addAll(attackMap.get(t).getMaxAmphibUnits());
ProLogger.trace(" --- My max units ---");
final Map<String, Integer> printMap = new HashMap<>();
for (final Unit unit : combinedUnits) {
if (printMap.containsKey(unit.toStringNoOwner())) {
printMap.put(unit.toStringNoOwner(), printMap.get(unit.toStringNoOwner()) + 1);
} else {
printMap.put(unit.toStringNoOwner(), 1);
}
}
for (final String key : printMap.keySet()) {
ProLogger.trace(" " + printMap.get(key) + " " + key);
}
ProLogger.trace(" --- My max bombard units ---");
final Map<String, Integer> printBombardMap = new HashMap<>();
for (final Unit unit : attackMap.get(t).getMaxBombardUnits()) {
if (printBombardMap.containsKey(unit.toStringNoOwner())) {
printBombardMap.put(unit.toStringNoOwner(), printBombardMap.get(unit.toStringNoOwner()) + 1);
} else {
printBombardMap.put(unit.toStringNoOwner(), 1);
}
}
for (final String key : printBombardMap.keySet()) {
ProLogger.trace(" " + printBombardMap.get(key) + " " + key);
}
final List<Unit> units3 = attackMap.get(t).getUnits();
ProLogger.trace(" --- My actual units ---");
final Map<String, Integer> printMap3 = new HashMap<>();
for (final Unit unit : units3) {
if (printMap3.containsKey(unit.toStringNoOwner())) {
printMap3.put(unit.toStringNoOwner(), printMap3.get(unit.toStringNoOwner()) + 1);
} else {
printMap3.put(unit.toStringNoOwner(), 1);
}
}
for (final String key : printMap3.keySet()) {
ProLogger.trace(" " + printMap3.get(key) + " " + key);
}
ProLogger.trace(" --- Enemy units ---");
final Map<String, Integer> printMap2 = new HashMap<>();
final List<Unit> units2 = attackMap.get(t).getMaxEnemyDefenders(player, data);
for (final Unit unit : units2) {
if (printMap2.containsKey(unit.toStringNoOwner())) {
printMap2.put(unit.toStringNoOwner(), printMap2.get(unit.toStringNoOwner()) + 1);
} else {
printMap2.put(unit.toStringNoOwner(), 1);
}
}
for (final String key : printMap2.keySet()) {
ProLogger.trace(" " + printMap2.get(key) + " " + key);
}
ProLogger.trace(" --- Enemy Counter Attack Units ---");
final Map<String, Integer> printMap4 = new HashMap<>();
final List<Unit> units4 = attackMap.get(t).getMaxEnemyUnits();
for (final Unit unit : units4) {
if (printMap4.containsKey(unit.toStringNoOwner())) {
printMap4.put(unit.toStringNoOwner(), printMap4.get(unit.toStringNoOwner()) + 1);
} else {
printMap4.put(unit.toStringNoOwner(), 1);
}
}
for (final String key : printMap4.keySet()) {
ProLogger.trace(" " + printMap4.get(key) + " " + key);
}
ProLogger.trace(" --- Enemy Counter Bombard Units ---");
final Map<String, Integer> printMap5 = new HashMap<>();
final Set<Unit> units5 = attackMap.get(t).getMaxEnemyBombardUnits();
for (final Unit unit : units5) {
if (printMap5.containsKey(unit.toStringNoOwner())) {
printMap5.put(unit.toStringNoOwner(), printMap5.get(unit.toStringNoOwner()) + 1);
} else {
printMap5.put(unit.toStringNoOwner(), 1);
}
}
for (final String key : printMap5.keySet()) {
ProLogger.trace(" " + printMap4.get(key) + " " + key);
}
}
}
use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProCombatMoveAi method checkContestedSeaTerritories.
private void checkContestedSeaTerritories() {
final Map<Territory, ProTerritory> attackMap = territoryManager.getAttackOptions().getTerritoryMap();
for (final Territory t : ProData.myUnitTerritories) {
if (t.isWater() && Matches.territoryHasEnemyUnits(player, data).test(t) && (attackMap.get(t) == null || attackMap.get(t).getUnits().isEmpty())) {
// Move into random adjacent safe sea territory
final Set<Territory> possibleMoveTerritories = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnitsThrough(player, data, true));
if (!possibleMoveTerritories.isEmpty()) {
final Territory moveToTerritory = possibleMoveTerritories.iterator().next();
final List<Unit> mySeaUnits = t.getUnits().getMatches(ProMatches.unitCanBeMovedAndIsOwnedSea(player, true));
if (attackMap.containsKey(moveToTerritory)) {
attackMap.get(moveToTerritory).addUnits(mySeaUnits);
} else {
final ProTerritory moveTerritoryData = new ProTerritory(moveToTerritory);
moveTerritoryData.addUnits(mySeaUnits);
attackMap.put(moveToTerritory, moveTerritoryData);
}
ProLogger.info(t + " is a contested territory so moving subs to " + moveToTerritory);
}
}
}
}
use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProNonCombatMoveAi method moveUnitsToDefendTerritories.
private void moveUnitsToDefendTerritories(final List<ProTerritory> prioritizedTerritories, final int enemyDistance, final Map<Territory, Double> territoryValueMap) {
ProLogger.info("Determine units to defend territories with");
if (prioritizedTerritories.isEmpty()) {
return;
}
final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
final Map<Unit, Set<Territory>> unitMoveMap = territoryManager.getDefendOptions().getUnitMoveMap();
final Map<Unit, Set<Territory>> transportMoveMap = territoryManager.getDefendOptions().getTransportMoveMap();
final List<ProTransport> transportMapList = territoryManager.getDefendOptions().getTransportList();
// Assign units to territories by prioritization
int numToDefend = 1;
while (true) {
// Reset lists
for (final ProTerritory t : moveMap.values()) {
t.getTempUnits().clear();
t.getTempAmphibAttackMap().clear();
t.getTransportTerritoryMap().clear();
t.setBattleResult(null);
}
// Determine number of territories to defend
if (numToDefend <= 0) {
break;
}
final List<ProTerritory> territoriesToTryToDefend = prioritizedTerritories.subList(0, numToDefend);
// Loop through all units and determine defend options
final Map<Unit, Set<Territory>> unitDefendOptions = new HashMap<>();
for (final Unit unit : unitMoveMap.keySet()) {
// Find number of move options
final Set<Territory> canDefendTerritories = new LinkedHashSet<>();
for (final ProTerritory attackTerritoryData : territoriesToTryToDefend) {
if (unitMoveMap.get(unit).contains(attackTerritoryData.getTerritory())) {
canDefendTerritories.add(attackTerritoryData.getTerritory());
}
}
unitDefendOptions.put(unit, canDefendTerritories);
}
// Sort units by number of defend options and cost
final Map<Unit, Set<Territory>> sortedUnitMoveOptions = ProSortMoveOptionsUtils.sortUnitMoveOptions(unitDefendOptions);
// Set enough units in territories to have at least a chance of winning
for (final Iterator<Unit> it = sortedUnitMoveOptions.keySet().iterator(); it.hasNext(); ) {
final Unit unit = it.next();
final boolean isAirUnit = UnitAttachment.get(unit.getType()).getIsAir();
if (isAirUnit || Matches.unitIsCarrier().test(unit)) {
// skip air and carrier units
continue;
}
final TreeMap<Double, Territory> estimatesMap = new TreeMap<>();
for (final Territory t : sortedUnitMoveOptions.get(unit)) {
List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsAlliedNotOwnedAir(player, data).negate());
if (t.isWater()) {
defendingUnits = moveMap.get(t).getAllDefenders();
}
final double estimate = ProBattleUtils.estimateStrengthDifference(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits);
estimatesMap.put(estimate, t);
}
if (!estimatesMap.isEmpty() && estimatesMap.lastKey() > 60) {
final Territory minWinTerritory = estimatesMap.lastEntry().getValue();
moveMap.get(minWinTerritory).addTempUnit(unit);
it.remove();
}
}
// Set non-air units in territories
for (final Iterator<Unit> it = sortedUnitMoveOptions.keySet().iterator(); it.hasNext(); ) {
final Unit unit = it.next();
if (Matches.unitCanLandOnCarrier().test(unit)) {
continue;
}
Territory maxWinTerritory = null;
double maxWinPercentage = -1;
for (final Territory t : sortedUnitMoveOptions.get(unit)) {
List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsAlliedNotOwnedAir(player, data).negate());
if (t.isWater()) {
defendingUnits = moveMap.get(t).getAllDefenders();
}
if (moveMap.get(t).getBattleResult() == null) {
moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
}
final ProBattleResult result = moveMap.get(t).getBattleResult();
final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t);
if (result.getWinPercentage() > maxWinPercentage && ((t.equals(ProData.myCapital) && result.getWinPercentage() > (100 - ProData.winPercentage)) || (hasFactory && result.getWinPercentage() > (100 - ProData.minWinPercentage)) || result.getTuvSwing() >= 0)) {
maxWinTerritory = t;
maxWinPercentage = result.getWinPercentage();
}
}
if (maxWinTerritory != null) {
moveMap.get(maxWinTerritory).addTempUnit(unit);
moveMap.get(maxWinTerritory).setBattleResult(null);
it.remove();
// If carrier has dependent allied fighters then move them too
if (Matches.unitIsCarrier().test(unit)) {
final Territory unitTerritory = unitTerritoryMap.get(unit);
final Map<Unit, Collection<Unit>> carrierMustMoveWith = MoveValidator.carrierMustMoveWith(unitTerritory.getUnits().getUnits(), unitTerritory, data, player);
if (carrierMustMoveWith.containsKey(unit)) {
moveMap.get(maxWinTerritory).getTempUnits().addAll(carrierMustMoveWith.get(unit));
}
}
}
}
// Set air units in territories
for (final Iterator<Unit> it = sortedUnitMoveOptions.keySet().iterator(); it.hasNext(); ) {
final Unit unit = it.next();
Territory maxWinTerritory = null;
double maxWinPercentage = -1;
for (final Territory t : sortedUnitMoveOptions.get(unit)) {
if (t.isWater() && Matches.unitIsAir().test(unit)) {
if (!ProTransportUtils.validateCarrierCapacity(player, t, moveMap.get(t).getAllDefendersForCarrierCalcs(data, player), unit)) {
// skip moving air to water if not enough carrier capacity
continue;
}
}
if (!t.isWater() && !t.getOwner().equals(player) && Matches.unitIsAir().test(unit) && !ProMatches.territoryHasInfraFactoryAndIsLand().test(t)) {
// skip moving air units to allied land without a factory
continue;
}
List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsAlliedNotOwnedAir(player, data).negate());
if (t.isWater()) {
defendingUnits = moveMap.get(t).getAllDefenders();
}
if (moveMap.get(t).getBattleResult() == null) {
moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
}
final ProBattleResult result = moveMap.get(t).getBattleResult();
final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t);
if (result.getWinPercentage() > maxWinPercentage && ((t.equals(ProData.myCapital) && result.getWinPercentage() > (100 - ProData.winPercentage)) || (hasFactory && result.getWinPercentage() > (100 - ProData.minWinPercentage)) || result.getTuvSwing() >= 0)) {
maxWinTerritory = t;
maxWinPercentage = result.getWinPercentage();
}
}
if (maxWinTerritory != null) {
moveMap.get(maxWinTerritory).addTempUnit(unit);
moveMap.get(maxWinTerritory).setBattleResult(null);
it.remove();
}
}
// Loop through all my transports and see which territories they can defend from current list
final List<Unit> alreadyMovedTransports = new ArrayList<>();
if (!Properties.getTransportCasualtiesRestricted(data)) {
final Map<Unit, Set<Territory>> transportDefendOptions = new HashMap<>();
for (final Unit unit : transportMoveMap.keySet()) {
// Find number of defend options
final Set<Territory> canDefendTerritories = new HashSet<>();
for (final ProTerritory attackTerritoryData : territoriesToTryToDefend) {
if (transportMoveMap.get(unit).contains(attackTerritoryData.getTerritory())) {
canDefendTerritories.add(attackTerritoryData.getTerritory());
}
}
if (!canDefendTerritories.isEmpty()) {
transportDefendOptions.put(unit, canDefendTerritories);
}
}
// Loop through transports with move options and determine if any naval defense needs it
for (final Unit transport : transportDefendOptions.keySet()) {
// Find current naval defense that needs transport if it isn't transporting units
for (final Territory t : transportDefendOptions.get(transport)) {
if (!TransportTracker.isTransporting(transport)) {
final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
if (moveMap.get(t).getBattleResult() == null) {
moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
}
final ProBattleResult result = moveMap.get(t).getBattleResult();
if (result.getTuvSwing() > 0) {
moveMap.get(t).addTempUnit(transport);
moveMap.get(t).setBattleResult(null);
alreadyMovedTransports.add(transport);
ProLogger.trace("Adding defend transport to: " + t.getName());
break;
}
}
}
}
}
// Loop through all my transports and see which can make amphib move
final Map<Unit, Set<Territory>> amphibMoveOptions = new HashMap<>();
for (final ProTransport proTransportData : transportMapList) {
// If already used to defend then ignore
if (alreadyMovedTransports.contains(proTransportData.getTransport())) {
continue;
}
// Find number of amphib move options
final Set<Territory> canAmphibMoveTerritories = new HashSet<>();
for (final ProTerritory attackTerritoryData : territoriesToTryToDefend) {
if (proTransportData.getTransportMap().containsKey(attackTerritoryData.getTerritory())) {
canAmphibMoveTerritories.add(attackTerritoryData.getTerritory());
}
}
if (!canAmphibMoveTerritories.isEmpty()) {
amphibMoveOptions.put(proTransportData.getTransport(), canAmphibMoveTerritories);
}
}
// Loop through transports with amphib move options and determine if any land defense needs it
for (final Unit transport : amphibMoveOptions.keySet()) {
// Find current land defense results for territories that unit can amphib move
for (final Territory t : amphibMoveOptions.get(transport)) {
final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
if (moveMap.get(t).getBattleResult() == null) {
moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
}
final ProBattleResult result = moveMap.get(t).getBattleResult();
final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t);
if ((t.equals(ProData.myCapital) && result.getWinPercentage() > (100 - ProData.winPercentage)) || (hasFactory && result.getWinPercentage() > (100 - ProData.minWinPercentage)) || result.getTuvSwing() > 0) {
// Get all units that have already moved
final List<Unit> alreadyMovedUnits = new ArrayList<>();
for (final ProTerritory t2 : moveMap.values()) {
alreadyMovedUnits.addAll(t2.getUnits());
alreadyMovedUnits.addAll(t2.getTempUnits());
}
// Find units that haven't moved and can be transported
boolean addedAmphibUnits = false;
for (final ProTransport proTransportData : transportMapList) {
if (proTransportData.getTransport().equals(transport)) {
// Find units to transport
final Set<Territory> territoriesCanLoadFrom = proTransportData.getTransportMap().get(t);
final List<Unit> amphibUnitsToAdd = ProTransportUtils.getUnitsToTransportFromTerritories(player, transport, territoriesCanLoadFrom, alreadyMovedUnits);
if (amphibUnitsToAdd.isEmpty()) {
continue;
}
// Find safest territory to unload from
double minStrengthDifference = Double.POSITIVE_INFINITY;
Territory minTerritory = null;
final Set<Territory> territoriesToMoveTransport = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, false));
final Set<Territory> loadFromTerritories = new HashSet<>();
for (final Unit u : amphibUnitsToAdd) {
loadFromTerritories.add(unitTerritoryMap.get(u));
}
for (final Territory territoryToMoveTransport : territoriesToMoveTransport) {
if (proTransportData.getSeaTransportMap().containsKey(territoryToMoveTransport) && proTransportData.getSeaTransportMap().get(territoryToMoveTransport).containsAll(loadFromTerritories) && moveMap.get(territoryToMoveTransport) != null && (moveMap.get(territoryToMoveTransport).isCanHold() || hasFactory)) {
final List<Unit> attackers = moveMap.get(territoryToMoveTransport).getMaxEnemyUnits();
final List<Unit> defenders = moveMap.get(territoryToMoveTransport).getAllDefenders();
defenders.add(transport);
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(territoryToMoveTransport, attackers, defenders);
if (strengthDifference < minStrengthDifference) {
minTerritory = territoryToMoveTransport;
minStrengthDifference = strengthDifference;
}
}
}
if (minTerritory != null) {
// Add amphib defense
moveMap.get(t).getTransportTerritoryMap().put(transport, minTerritory);
moveMap.get(t).addTempUnits(amphibUnitsToAdd);
moveMap.get(t).putTempAmphibAttackMap(transport, amphibUnitsToAdd);
moveMap.get(t).setBattleResult(null);
for (final Unit unit : amphibUnitsToAdd) {
sortedUnitMoveOptions.remove(unit);
}
ProLogger.trace("Adding amphibious defense to: " + t + ", units=" + amphibUnitsToAdd + ", unloadTerritory=" + minTerritory);
addedAmphibUnits = true;
break;
}
}
}
if (addedAmphibUnits) {
break;
}
}
}
}
// Determine if all defenses are successful
boolean areSuccessful = true;
boolean containsCapital = false;
ProLogger.debug("Current number of territories: " + numToDefend);
for (final ProTerritory patd : territoriesToTryToDefend) {
final Territory t = patd.getTerritory();
// Find defense result and hold value based on used defenders TUV
final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
moveMap.get(t).setBattleResult(calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
final ProBattleResult result = patd.getBattleResult();
int isFactory = 0;
if (ProMatches.territoryHasInfraFactoryAndIsLand().test(t)) {
isFactory = 1;
}
int isMyCapital = 0;
if (t.equals(ProData.myCapital)) {
isMyCapital = 1;
containsCapital = true;
}
final double extraUnitValue = TuvUtils.getTuv(moveMap.get(t).getTempUnits(), ProData.unitValueMap);
final List<Unit> unsafeTransports = new ArrayList<>();
for (final Unit transport : moveMap.get(t).getTransportTerritoryMap().keySet()) {
final Territory transportTerritory = moveMap.get(t).getTransportTerritoryMap().get(transport);
if (!moveMap.get(transportTerritory).isCanHold()) {
unsafeTransports.add(transport);
}
}
final int unsafeTransportValue = TuvUtils.getTuv(unsafeTransports, ProData.unitValueMap);
final double holdValue = extraUnitValue / 8 * (1 + 0.5 * isFactory) * (1 + 2 * isMyCapital) - unsafeTransportValue;
// Find strategic value
boolean hasHigherStrategicValue = true;
if (!t.isWater() && !t.equals(ProData.myCapital) && !ProMatches.territoryHasInfraFactoryAndIsLand().test(t)) {
double totalValue = 0.0;
final List<Unit> nonAirDefenders = CollectionUtils.getMatches(moveMap.get(t).getTempUnits(), Matches.unitIsNotAir());
for (final Unit u : nonAirDefenders) {
totalValue += territoryValueMap.get(unitTerritoryMap.get(u));
}
final double averageValue = totalValue / nonAirDefenders.size();
if (territoryValueMap.get(t) < averageValue) {
hasHigherStrategicValue = false;
ProLogger.trace(t + " has lower value then move from with value=" + territoryValueMap.get(t) + ", averageMoveFromValue=" + averageValue);
}
}
// Check if its worth defending
if ((result.getTuvSwing() - holdValue) > patd.getMinBattleResult().getTuvSwing() || (!hasHigherStrategicValue && (result.getTuvSwing() + extraUnitValue / 2) >= patd.getMinBattleResult().getTuvSwing())) {
areSuccessful = false;
}
ProLogger.debug(patd.getResultString() + ", holdValue=" + holdValue + ", minTUVSwing=" + patd.getMinBattleResult().getTuvSwing() + ", hasHighStrategicValue=" + hasHigherStrategicValue + ", defenders=" + defendingUnits + ", attackers=" + moveMap.get(t).getMaxEnemyUnits());
}
final Territory currentTerritory = prioritizedTerritories.get(numToDefend - 1).getTerritory();
if (ProData.myCapital != null) {
// Check capital defense
if (containsCapital && !currentTerritory.equals(ProData.myCapital) && moveMap.get(ProData.myCapital).getBattleResult().getWinPercentage() > (100 - ProData.winPercentage)) {
if (!Collections.disjoint(moveMap.get(currentTerritory).getAllDefenders(), moveMap.get(ProData.myCapital).getMaxDefenders())) {
areSuccessful = false;
ProLogger.debug("Capital isn't safe after defense moves with winPercentage=" + moveMap.get(ProData.myCapital).getBattleResult().getWinPercentage());
}
}
// Check capital local superiority
if (!currentTerritory.isWater() && enemyDistance >= 2 && enemyDistance <= 3) {
final int distance = data.getMap().getDistance(ProData.myCapital, currentTerritory, ProMatches.territoryCanMoveLandUnits(player, data, true));
if (distance > 0 && (enemyDistance == distance || enemyDistance == (distance - 1)) && !ProBattleUtils.territoryHasLocalLandSuperiorityAfterMoves(ProData.myCapital, enemyDistance, player, moveMap)) {
areSuccessful = false;
ProLogger.debug("Capital doesn't have local land superiority after defense moves with enemyDistance=" + enemyDistance);
}
}
}
// Determine whether to try more territories, remove a territory, or end
if (areSuccessful) {
numToDefend++;
for (final ProTerritory patd : territoriesToTryToDefend) {
patd.setCanAttack(true);
}
// Can defend all territories in list so end
if (numToDefend > prioritizedTerritories.size()) {
break;
}
} else {
// Remove territory last territory in prioritized list since we can't hold them all
ProLogger.debug("Removing territory: " + currentTerritory);
prioritizedTerritories.get(numToDefend - 1).setCanHold(false);
prioritizedTerritories.remove(numToDefend - 1);
if (numToDefend > prioritizedTerritories.size()) {
numToDefend--;
}
}
}
// Add temp units to move lists
for (final ProTerritory t : moveMap.values()) {
// Handle allied units such as fighters on carriers
final List<Unit> alliedUnits = CollectionUtils.getMatches(t.getTempUnits(), Matches.unitIsOwnedBy(player).negate());
for (final Unit alliedUnit : alliedUnits) {
t.addCantMoveUnit(alliedUnit);
t.getTempUnits().remove(alliedUnit);
}
t.addUnits(t.getTempUnits());
t.putAllAmphibAttackMap(t.getTempAmphibAttackMap());
for (final Unit u : t.getTempUnits()) {
if (Matches.unitIsTransport().test(u)) {
transportMoveMap.remove(u);
transportMapList.removeIf(proTransport -> proTransport.getTransport().equals(u));
} else {
unitMoveMap.remove(u);
}
}
for (final Unit u : t.getTempAmphibAttackMap().keySet()) {
transportMoveMap.remove(u);
transportMapList.removeIf(proTransport -> proTransport.getTransport().equals(u));
}
t.getTempUnits().clear();
t.getTempAmphibAttackMap().clear();
}
ProLogger.debug("Final number of territories: " + (numToDefend - 1));
}
use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProNonCombatMoveAi method moveUnitsToBestTerritories.
private void moveUnitsToBestTerritories() {
final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
final Map<Unit, Set<Territory>> unitMoveMap = territoryManager.getDefendOptions().getUnitMoveMap();
final Map<Unit, Set<Territory>> transportMoveMap = territoryManager.getDefendOptions().getTransportMoveMap();
final List<ProTransport> transportMapList = territoryManager.getDefendOptions().getTransportList();
while (true) {
ProLogger.info("Move units to best value territories");
final Set<Territory> territoriesToDefend = new HashSet<>();
final Map<Unit, Set<Territory>> currentUnitMoveMap = new HashMap<>(unitMoveMap);
final Map<Unit, Set<Territory>> currentTransportMoveMap = new HashMap<>(transportMoveMap);
final List<ProTransport> currentTransportMapList = new ArrayList<>(transportMapList);
// Reset lists
for (final ProTerritory t : moveMap.values()) {
t.getTempUnits().clear();
for (final Unit transport : t.getTempAmphibAttackMap().keySet()) {
t.getTransportTerritoryMap().remove(transport);
}
t.getTempAmphibAttackMap().clear();
t.setBattleResult(null);
}
ProLogger.debug("Move amphib units");
// Transport amphib units to best territory
for (final Iterator<ProTransport> it = currentTransportMapList.iterator(); it.hasNext(); ) {
final ProTransport amphibData = it.next();
final Unit transport = amphibData.getTransport();
// Get all units that have already moved
final List<Unit> alreadyMovedUnits = new ArrayList<>();
for (final ProTerritory t : moveMap.values()) {
alreadyMovedUnits.addAll(t.getUnits());
alreadyMovedUnits.addAll(t.getTempUnits());
}
// Transport amphib units to best land territory
Territory maxValueTerritory = null;
List<Unit> maxAmphibUnitsToAdd = null;
double maxValue = Double.MIN_VALUE;
double maxSeaValue = 0;
Territory maxUnloadFromTerritory = null;
for (final Territory t : amphibData.getTransportMap().keySet()) {
if (moveMap.get(t).getValue() >= maxValue) {
// Find units to load
final Set<Territory> territoriesCanLoadFrom = amphibData.getTransportMap().get(t);
final List<Unit> amphibUnitsToAdd = ProTransportUtils.getUnitsToTransportThatCantMoveToHigherValue(player, transport, territoriesCanLoadFrom, alreadyMovedUnits, moveMap, currentUnitMoveMap, moveMap.get(t).getValue());
if (amphibUnitsToAdd.isEmpty()) {
continue;
}
// Find best territory to move transport
final Set<Territory> loadFromTerritories = new HashSet<>();
for (final Unit u : amphibUnitsToAdd) {
loadFromTerritories.add(unitTerritoryMap.get(u));
}
final Set<Territory> territoriesToMoveTransport = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, false));
for (final Territory territoryToMoveTransport : territoriesToMoveTransport) {
if (amphibData.getSeaTransportMap().containsKey(territoryToMoveTransport) && amphibData.getSeaTransportMap().get(territoryToMoveTransport).containsAll(loadFromTerritories) && moveMap.get(territoryToMoveTransport) != null && moveMap.get(territoryToMoveTransport).isCanHold() && (moveMap.get(t).getValue() > maxValue || moveMap.get(territoryToMoveTransport).getValue() > maxSeaValue)) {
maxValueTerritory = t;
maxAmphibUnitsToAdd = amphibUnitsToAdd;
maxValue = moveMap.get(t).getValue();
maxSeaValue = moveMap.get(territoryToMoveTransport).getValue();
maxUnloadFromTerritory = territoryToMoveTransport;
}
}
}
}
if (maxValueTerritory != null) {
ProLogger.trace(transport + " moved to " + maxUnloadFromTerritory + " and unloading to best land at " + maxValueTerritory + " with " + maxAmphibUnitsToAdd + ", value=" + maxValue);
moveMap.get(maxValueTerritory).addTempUnits(maxAmphibUnitsToAdd);
moveMap.get(maxValueTerritory).putTempAmphibAttackMap(transport, maxAmphibUnitsToAdd);
moveMap.get(maxValueTerritory).getTransportTerritoryMap().put(transport, maxUnloadFromTerritory);
currentTransportMoveMap.remove(transport);
for (final Unit unit : maxAmphibUnitsToAdd) {
currentUnitMoveMap.remove(unit);
}
territoriesToDefend.add(maxUnloadFromTerritory);
it.remove();
continue;
}
// Transport amphib units to best sea territory
for (final Territory t : amphibData.getSeaTransportMap().keySet()) {
if (moveMap.get(t) != null && moveMap.get(t).getValue() > maxValue) {
// Find units to load
final Set<Territory> territoriesCanLoadFrom = amphibData.getSeaTransportMap().get(t);
// Don't transport adjacent units
territoriesCanLoadFrom.removeAll(data.getMap().getNeighbors(t));
final List<Unit> amphibUnitsToAdd = ProTransportUtils.getUnitsToTransportThatCantMoveToHigherValue(player, transport, territoriesCanLoadFrom, alreadyMovedUnits, moveMap, currentUnitMoveMap, 0.1);
if (!amphibUnitsToAdd.isEmpty()) {
maxValueTerritory = t;
maxAmphibUnitsToAdd = amphibUnitsToAdd;
maxValue = moveMap.get(t).getValue();
}
}
}
if (maxValueTerritory != null) {
final Set<Territory> possibleUnloadTerritories = data.getMap().getNeighbors(maxValueTerritory, ProMatches.territoryCanMoveLandUnitsAndIsAllied(player, data));
Territory unloadToTerritory = null;
int maxNumSeaNeighbors = 0;
for (final Territory t : possibleUnloadTerritories) {
final int numSeaNeighbors = data.getMap().getNeighbors(t, Matches.territoryIsWater()).size();
final boolean isAdjacentToEnemy = ProMatches.territoryIsOrAdjacentToEnemyNotNeutralLand(player, data).test(t);
if (moveMap.get(t) != null && (moveMap.get(t).isCanHold() || !isAdjacentToEnemy) && numSeaNeighbors > maxNumSeaNeighbors) {
unloadToTerritory = t;
maxNumSeaNeighbors = numSeaNeighbors;
}
}
if (unloadToTerritory != null) {
moveMap.get(unloadToTerritory).addTempUnits(maxAmphibUnitsToAdd);
moveMap.get(unloadToTerritory).putTempAmphibAttackMap(transport, maxAmphibUnitsToAdd);
moveMap.get(unloadToTerritory).getTransportTerritoryMap().put(transport, maxValueTerritory);
ProLogger.trace(transport + " moved to best sea at " + maxValueTerritory + " and unloading to " + unloadToTerritory + " with " + maxAmphibUnitsToAdd + ", value=" + maxValue);
} else {
moveMap.get(maxValueTerritory).addTempUnits(maxAmphibUnitsToAdd);
moveMap.get(maxValueTerritory).putTempAmphibAttackMap(transport, maxAmphibUnitsToAdd);
moveMap.get(maxValueTerritory).getTransportTerritoryMap().put(transport, maxValueTerritory);
ProLogger.trace(transport + " moved to best sea at " + maxValueTerritory + " with " + maxAmphibUnitsToAdd + ", value=" + maxValue);
}
currentTransportMoveMap.remove(transport);
for (final Unit unit : maxAmphibUnitsToAdd) {
currentUnitMoveMap.remove(unit);
}
territoriesToDefend.add(maxValueTerritory);
it.remove();
}
}
ProLogger.debug("Move empty transports to best loading territory");
// TODO: consider which territory is 'safest'
for (final Iterator<Unit> it = currentTransportMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit transport = it.next();
final Territory currentTerritory = unitTerritoryMap.get(transport);
final int moves = TripleAUnit.get(transport).getMovementLeft();
if (TransportTracker.isTransporting(transport) || moves <= 0) {
continue;
}
final List<ProTerritory> priorizitedLoadTerritories = new ArrayList<>();
for (final Territory t : moveMap.keySet()) {
// Check if land with adjacent sea that can be reached and that I'm not already adjacent to
final boolean territoryHasTransportableUnits = Matches.territoryHasUnitsThatMatch(ProMatches.unitIsOwnedTransportableUnitAndCanBeLoaded(player, transport, false)).test(t);
final int distance = data.getMap().getDistance_IgnoreEndForCondition(currentTerritory, t, ProMatches.territoryCanMoveSeaUnits(player, data, true));
final boolean hasSeaNeighbor = Matches.territoryHasNeighborMatching(data, Matches.territoryIsWater()).test(t);
final boolean hasFactory = ProMatches.territoryHasInfraFactoryAndIsOwnedLand(player).test(t);
if (!t.isWater() && hasSeaNeighbor && distance > 0 && !(distance == 1 && territoryHasTransportableUnits && !hasFactory)) {
// TODO: add calculation of transports vs units
final double territoryValue = moveMap.get(t).getValue();
final int numUnitsToLoad = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsOwnedTransportableUnit(player)).size();
final boolean hasUnconqueredFactory = ProMatches.territoryHasInfraFactoryAndIsOwnedLand(player).test(t) && !AbstractMoveDelegate.getBattleTracker(data).wasConquered(t);
int factoryProduction = 0;
if (hasUnconqueredFactory) {
factoryProduction = TerritoryAttachment.getProduction(t);
}
int numTurnsAway = (distance - 1) / moves;
if (distance <= moves) {
numTurnsAway = 0;
}
final double value = territoryValue + 0.5 * numTurnsAway - 0.1 * numUnitsToLoad - 0.1 * factoryProduction;
moveMap.get(t).setLoadValue(value);
priorizitedLoadTerritories.add(moveMap.get(t));
}
}
// Sort prioritized territories
priorizitedLoadTerritories.sort(Comparator.comparingDouble(ProTerritory::getLoadValue));
// Move towards best loading territory if route is safe
for (final ProTerritory patd : priorizitedLoadTerritories) {
boolean movedTransport = false;
final Set<Territory> cantHoldTerritories = new HashSet<>();
while (true) {
final Predicate<Territory> match = ProMatches.territoryCanMoveSeaUnitsThrough(player, data, false).and(Matches.territoryIsInList(cantHoldTerritories).negate());
final Route route = data.getMap().getRoute_IgnoreEnd(currentTerritory, patd.getTerritory(), match);
if (route == null || MoveValidator.validateCanal(route, Collections.singletonList(transport), player, data) != null) {
break;
}
final List<Territory> territories = route.getAllTerritories();
territories.remove(territories.size() - 1);
final Territory moveToTerritory = territories.get(Math.min(territories.size() - 1, moves));
final ProTerritory patd2 = moveMap.get(moveToTerritory);
if (patd2 != null && patd2.isCanHold()) {
ProLogger.trace(transport + " moved towards best loading territory " + patd.getTerritory() + " and moved to " + moveToTerritory);
patd2.addTempUnit(transport);
territoriesToDefend.add(moveToTerritory);
it.remove();
movedTransport = true;
break;
}
if (!cantHoldTerritories.add(moveToTerritory)) {
break;
}
}
if (movedTransport) {
break;
}
}
}
ProLogger.debug("Move remaining transports to safest territory");
// Move remaining transports to safest territory
for (final Iterator<Unit> it = currentTransportMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit transport = it.next();
// Get all units that have already moved
final List<Unit> alreadyMovedUnits = new ArrayList<>();
for (final ProTerritory t : moveMap.values()) {
alreadyMovedUnits.addAll(t.getUnits());
}
// Find safest territory
double minStrengthDifference = Double.POSITIVE_INFINITY;
Territory minTerritory = null;
for (final Territory t : currentTransportMoveMap.get(transport)) {
final List<Unit> attackers = moveMap.get(t).getMaxEnemyUnits();
final List<Unit> defenders = moveMap.get(t).getMaxDefenders();
defenders.removeAll(alreadyMovedUnits);
defenders.addAll(moveMap.get(t).getUnits());
defenders.removeAll(ProTransportUtils.getAirThatCantLandOnCarrier(player, t, defenders));
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, attackers, defenders);
// TODO: add logic to move towards closest factory
ProLogger.trace(transport + " at " + t + ", strengthDifference=" + strengthDifference + ", attackers=" + attackers + ", defenders=" + defenders);
if (strengthDifference < minStrengthDifference) {
minStrengthDifference = strengthDifference;
minTerritory = t;
}
}
if (minTerritory != null) {
// TODO: consider which is 'safest'
if (TransportTracker.isTransporting(transport)) {
final List<Unit> amphibUnits = (List<Unit>) TransportTracker.transporting(transport);
final Set<Territory> possibleUnloadTerritories = data.getMap().getNeighbors(minTerritory, ProMatches.territoryCanMoveLandUnitsAndIsAllied(player, data));
if (!possibleUnloadTerritories.isEmpty()) {
// Find best unload territory
Territory unloadToTerritory = possibleUnloadTerritories.iterator().next();
for (final Territory t : possibleUnloadTerritories) {
if (moveMap.get(t) != null && moveMap.get(t).isCanHold()) {
unloadToTerritory = t;
}
}
ProLogger.trace(transport + " moved to safest territory at " + minTerritory + " and unloading to " + unloadToTerritory + " with " + amphibUnits + ", strengthDifference=" + minStrengthDifference);
moveMap.get(unloadToTerritory).addTempUnits(amphibUnits);
moveMap.get(unloadToTerritory).putTempAmphibAttackMap(transport, amphibUnits);
moveMap.get(unloadToTerritory).getTransportTerritoryMap().put(transport, minTerritory);
for (final Unit unit : amphibUnits) {
currentUnitMoveMap.remove(unit);
}
it.remove();
} else {
// Move transport with units since no unload options
ProLogger.trace(transport + " moved to safest territory at " + minTerritory + " with " + amphibUnits + ", strengthDifference=" + minStrengthDifference);
moveMap.get(minTerritory).addTempUnits(amphibUnits);
moveMap.get(minTerritory).putTempAmphibAttackMap(transport, amphibUnits);
moveMap.get(minTerritory).getTransportTerritoryMap().put(transport, minTerritory);
for (final Unit unit : amphibUnits) {
currentUnitMoveMap.remove(unit);
}
it.remove();
}
} else {
// If not transporting units
ProLogger.trace(transport + " moved to safest territory at " + minTerritory + ", strengthDifference=" + minStrengthDifference);
moveMap.get(minTerritory).addTempUnit(transport);
it.remove();
}
}
}
// Get all transport final territories
ProMoveUtils.calculateAmphibRoutes(player, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), moveMap, false);
for (final ProTerritory t : moveMap.values()) {
for (final Map.Entry<Unit, Territory> entry : t.getTransportTerritoryMap().entrySet()) {
final ProTerritory territory = moveMap.get(entry.getValue());
if (territory != null) {
territory.addTempUnit(entry.getKey());
}
}
}
ProLogger.debug("Move sea units");
// Move sea units to defend transports
for (final Iterator<Unit> it = currentUnitMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (Matches.unitIsSea().test(u)) {
for (final Territory t : currentUnitMoveMap.get(u)) {
if (moveMap.get(t).isCanHold() && !moveMap.get(t).getAllDefenders().isEmpty() && moveMap.get(t).getAllDefenders().stream().anyMatch(ProMatches.unitIsOwnedTransport(player))) {
final List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), Matches.unitIsNotLand());
if (moveMap.get(t).getBattleResult() == null) {
moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
}
final ProBattleResult result = moveMap.get(t).getBattleResult();
ProLogger.trace(t.getName() + " TUVSwing=" + result.getTuvSwing() + ", Win%=" + result.getWinPercentage() + ", enemyAttackers=" + moveMap.get(t).getMaxEnemyUnits().size() + ", defenders=" + defendingUnits.size());
if (result.getWinPercentage() > (100 - ProData.winPercentage) || result.getTuvSwing() > 0) {
ProLogger.trace(u + " added sea to defend transport at " + t);
moveMap.get(t).addTempUnit(u);
moveMap.get(t).setBattleResult(null);
territoriesToDefend.add(t);
it.remove();
// If carrier has dependent allied fighters then move them too
if (Matches.unitIsCarrier().test(u)) {
final Territory unitTerritory = unitTerritoryMap.get(u);
final Map<Unit, Collection<Unit>> carrierMustMoveWith = MoveValidator.carrierMustMoveWith(unitTerritory.getUnits().getUnits(), unitTerritory, data, player);
if (carrierMustMoveWith.containsKey(u)) {
moveMap.get(t).getTempUnits().addAll(carrierMustMoveWith.get(u));
}
}
break;
}
}
}
}
}
// Move air units to defend transports
for (final Iterator<Unit> it = currentUnitMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (Matches.unitCanLandOnCarrier().test(u)) {
for (final Territory t : currentUnitMoveMap.get(u)) {
if (t.isWater() && moveMap.get(t).isCanHold() && !moveMap.get(t).getAllDefenders().isEmpty() && moveMap.get(t).getAllDefenders().stream().anyMatch(ProMatches.unitIsOwnedTransport(player))) {
if (!ProTransportUtils.validateCarrierCapacity(player, t, moveMap.get(t).getAllDefendersForCarrierCalcs(data, player), u)) {
continue;
}
final List<Unit> defendingUnits = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), Matches.unitIsNotLand());
if (moveMap.get(t).getBattleResult() == null) {
moveMap.get(t).setBattleResult(calc.estimateDefendBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
}
final ProBattleResult result = moveMap.get(t).getBattleResult();
ProLogger.trace(t.getName() + " TUVSwing=" + result.getTuvSwing() + ", Win%=" + result.getWinPercentage() + ", enemyAttackers=" + moveMap.get(t).getMaxEnemyUnits().size() + ", defenders=" + defendingUnits.size());
if (result.getWinPercentage() > (100 - ProData.winPercentage) || result.getTuvSwing() > 0) {
ProLogger.trace(u + " added air to defend transport at " + t);
moveMap.get(t).addTempUnit(u);
moveMap.get(t).setBattleResult(null);
territoriesToDefend.add(t);
it.remove();
break;
}
}
}
}
}
// Move sea units to best location or safest location
for (final Iterator<Unit> it = currentUnitMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (Matches.unitIsSea().test(u)) {
Territory maxValueTerritory = null;
double maxValue = 0;
for (final Territory t : currentUnitMoveMap.get(u)) {
if (moveMap.get(t).isCanHold()) {
final int transports = CollectionUtils.countMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsOwnedTransport(player));
final double value = (1 + transports) * moveMap.get(t).getSeaValue() + (1 + transports * 100) * moveMap.get(t).getValue() / 10000;
ProLogger.trace(t + ", value=" + value + ", seaValue=" + moveMap.get(t).getSeaValue() + ", tValue=" + moveMap.get(t).getValue() + ", transports=" + transports);
if (value > maxValue) {
maxValue = value;
maxValueTerritory = t;
}
}
}
if (maxValueTerritory != null) {
ProLogger.trace(u + " added to best territory " + maxValueTerritory + ", value=" + maxValue);
moveMap.get(maxValueTerritory).addTempUnit(u);
moveMap.get(maxValueTerritory).setBattleResult(null);
territoriesToDefend.add(maxValueTerritory);
it.remove();
// If carrier has dependent allied fighters then move them too
if (Matches.unitIsCarrier().test(u)) {
final Territory unitTerritory = unitTerritoryMap.get(u);
final Map<Unit, Collection<Unit>> carrierMustMoveWith = MoveValidator.carrierMustMoveWith(unitTerritory.getUnits().getUnits(), unitTerritory, data, player);
if (carrierMustMoveWith.containsKey(u)) {
moveMap.get(maxValueTerritory).getTempUnits().addAll(carrierMustMoveWith.get(u));
}
}
} else {
// Get all units that have already moved
final List<Unit> alreadyMovedUnits = new ArrayList<>();
for (final ProTerritory t : moveMap.values()) {
alreadyMovedUnits.addAll(t.getUnits());
}
// Find safest territory
double minStrengthDifference = Double.POSITIVE_INFINITY;
Territory minTerritory = null;
for (final Territory t : currentUnitMoveMap.get(u)) {
final List<Unit> attackers = moveMap.get(t).getMaxEnemyUnits();
final List<Unit> defenders = moveMap.get(t).getMaxDefenders();
defenders.removeAll(alreadyMovedUnits);
defenders.addAll(moveMap.get(t).getUnits());
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, attackers, defenders);
if (strengthDifference < minStrengthDifference) {
minStrengthDifference = strengthDifference;
minTerritory = t;
}
}
if (minTerritory != null) {
ProLogger.trace(u + " moved to safest territory at " + minTerritory + ", strengthDifference=" + minStrengthDifference);
moveMap.get(minTerritory).addTempUnit(u);
moveMap.get(minTerritory).setBattleResult(null);
it.remove();
// If carrier has dependent allied fighters then move them too
if (Matches.unitIsCarrier().test(u)) {
final Territory unitTerritory = unitTerritoryMap.get(u);
final Map<Unit, Collection<Unit>> carrierMustMoveWith = MoveValidator.carrierMustMoveWith(unitTerritory.getUnits().getUnits(), unitTerritory, data, player);
if (carrierMustMoveWith.containsKey(u)) {
moveMap.get(minTerritory).getTempUnits().addAll(carrierMustMoveWith.get(u));
}
}
} else {
final Territory currentTerritory = unitTerritoryMap.get(u);
ProLogger.trace(u + " added to current territory since no better options at " + currentTerritory);
moveMap.get(currentTerritory).addTempUnit(u);
moveMap.get(currentTerritory).setBattleResult(null);
it.remove();
}
}
}
}
// Determine if all defenses are successful
ProLogger.debug("Checking if all sea moves are safe for " + territoriesToDefend);
boolean areSuccessful = true;
for (final Territory t : territoriesToDefend) {
// Find result with temp units
final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
moveMap.get(t).setBattleResult(calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
final ProBattleResult result = moveMap.get(t).getBattleResult();
int isWater = 0;
if (t.isWater()) {
isWater = 1;
}
final double extraUnitValue = TuvUtils.getTuv(moveMap.get(t).getTempUnits(), ProData.unitValueMap);
final double holdValue = result.getTuvSwing() - (extraUnitValue / 8 * (1 + isWater));
// Find min result without temp units
final List<Unit> minDefendingUnits = new ArrayList<>(defendingUnits);
minDefendingUnits.removeAll(moveMap.get(t).getTempUnits());
final ProBattleResult minResult = calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), minDefendingUnits, moveMap.get(t).getMaxEnemyBombardUnits());
// Check if territory is worth defending with temp units
if (holdValue > minResult.getTuvSwing()) {
areSuccessful = false;
moveMap.get(t).setCanHold(false);
moveMap.get(t).setValue(0);
moveMap.get(t).setSeaValue(0);
ProLogger.trace(t + " unable to defend so removing with holdValue=" + holdValue + ", minTUVSwing=" + minResult.getTuvSwing() + ", defenders=" + defendingUnits + ", enemyAttackers=" + moveMap.get(t).getMaxEnemyUnits());
}
ProLogger.trace(moveMap.get(t).getResultString() + ", holdValue=" + holdValue + ", minTUVSwing=" + minResult.getTuvSwing());
}
// Determine whether to try more territories, remove a territory, or end
if (areSuccessful) {
break;
}
}
// Add temp units to move lists
for (final ProTerritory t : moveMap.values()) {
// Handle allied units such as fighters on carriers
final List<Unit> alliedUnits = CollectionUtils.getMatches(t.getTempUnits(), Matches.unitIsOwnedBy(player).negate());
for (final Unit alliedUnit : alliedUnits) {
t.addCantMoveUnit(alliedUnit);
t.getTempUnits().remove(alliedUnit);
}
t.addUnits(t.getTempUnits());
t.putAllAmphibAttackMap(t.getTempAmphibAttackMap());
for (final Unit u : t.getTempUnits()) {
if (Matches.unitIsTransport().test(u)) {
transportMoveMap.remove(u);
transportMapList.removeIf(proTransport -> proTransport.getTransport().equals(u));
} else {
unitMoveMap.remove(u);
}
}
for (final Unit u : t.getTempAmphibAttackMap().keySet()) {
transportMoveMap.remove(u);
transportMapList.removeIf(proTransport -> proTransport.getTransport().equals(u));
}
t.getTempUnits().clear();
t.getTempAmphibAttackMap().clear();
}
ProLogger.info("Move land units");
// TODO: consider if territory ends up being safe
for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (Matches.unitIsLand().test(u)) {
Territory maxValueTerritory = null;
double maxValue = 0;
int maxNeedAmphibUnitValue = Integer.MIN_VALUE;
for (final Territory t : unitMoveMap.get(u)) {
if (moveMap.get(t).isCanHold() && moveMap.get(t).getValue() >= maxValue) {
// Find transport capacity of neighboring (distance 1) transports
final List<Unit> transports1 = new ArrayList<>();
final Set<Territory> seaNeighbors = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, true));
for (final Territory neighborTerritory : seaNeighbors) {
if (moveMap.containsKey(neighborTerritory)) {
transports1.addAll(CollectionUtils.getMatches(moveMap.get(neighborTerritory).getAllDefenders(), ProMatches.unitIsOwnedTransport(player)));
}
}
int transportCapacity1 = 0;
for (final Unit transport : transports1) {
transportCapacity1 += UnitAttachment.get(transport.getType()).getTransportCapacity();
}
// Find transport capacity of nearby (distance 2) transports
final List<Unit> transports2 = new ArrayList<>();
final Set<Territory> nearbySeaTerritories = data.getMap().getNeighbors(t, 2, ProMatches.territoryCanMoveSeaUnits(player, data, true));
nearbySeaTerritories.removeAll(seaNeighbors);
for (final Territory neighborTerritory : nearbySeaTerritories) {
if (moveMap.containsKey(neighborTerritory)) {
transports2.addAll(CollectionUtils.getMatches(moveMap.get(neighborTerritory).getAllDefenders(), ProMatches.unitIsOwnedTransport(player)));
}
}
int transportCapacity2 = 0;
for (final Unit transport : transports2) {
transportCapacity2 += UnitAttachment.get(transport.getType()).getTransportCapacity();
}
final List<Unit> unitsToTransport = CollectionUtils.getMatches(moveMap.get(t).getAllDefenders(), ProMatches.unitIsOwnedTransportableUnit(player));
// Find transport cost of potential amphib units
int transportCost = 0;
for (final Unit unit : unitsToTransport) {
transportCost += UnitAttachment.get(unit.getType()).getTransportCost();
}
// Find territory that needs amphib units that most
int hasFactory = 0;
if (ProMatches.territoryHasInfraFactoryAndIsOwnedLandAdjacentToSea(player, data).test(t)) {
hasFactory = 1;
}
final int neededNeighborTransportValue = Math.max(0, transportCapacity1 - transportCost);
final int neededNearbyTransportValue = Math.max(0, transportCapacity1 + transportCapacity2 - transportCost);
final int needAmphibUnitValue = 1000 * neededNeighborTransportValue + 100 * neededNearbyTransportValue + (1 + 10 * hasFactory) * data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, true)).size();
if (moveMap.get(t).getValue() > maxValue || needAmphibUnitValue > maxNeedAmphibUnitValue) {
maxValue = moveMap.get(t).getValue();
maxNeedAmphibUnitValue = needAmphibUnitValue;
maxValueTerritory = t;
}
}
}
if (maxValueTerritory != null) {
ProLogger.trace(u + " moved to " + maxValueTerritory + " with value=" + maxValue + ", numNeededTransportUnits=" + maxNeedAmphibUnitValue);
moveMap.get(maxValueTerritory).addUnit(u);
it.remove();
}
}
}
// Move land units towards nearest factory that is adjacent to the sea
final Set<Territory> myFactoriesAdjacentToSea = new HashSet<>(CollectionUtils.getMatches(data.getMap().getTerritories(), ProMatches.territoryHasInfraFactoryAndIsOwnedLandAdjacentToSea(player, data)));
for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (Matches.unitIsLand().test(u)) {
int minDistance = Integer.MAX_VALUE;
Territory minTerritory = null;
for (final Territory t : unitMoveMap.get(u)) {
if (moveMap.get(t).isCanHold()) {
for (final Territory factory : myFactoriesAdjacentToSea) {
int distance = data.getMap().getDistance(t, factory, ProMatches.territoryCanMoveLandUnits(player, data, true));
if (distance < 0) {
distance = 10 * data.getMap().getDistance(t, factory);
}
if (distance >= 0 && distance < minDistance) {
minDistance = distance;
minTerritory = t;
}
}
}
}
if (minTerritory != null) {
ProLogger.trace(u.getType().getName() + " moved towards closest factory adjacent to sea at " + minTerritory.getName());
moveMap.get(minTerritory).addUnit(u);
it.remove();
}
}
}
ProLogger.info("Move land units to safest territory");
// Move any remaining land units to safest territory (this is rarely used)
for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (Matches.unitIsLand().test(u)) {
// Get all units that have already moved
final List<Unit> alreadyMovedUnits = moveMap.values().stream().map(ProTerritory::getUnits).flatMap(Collection::stream).collect(Collectors.toList());
// Find safest territory
double minStrengthDifference = Double.POSITIVE_INFINITY;
Territory minTerritory = null;
for (final Territory t : unitMoveMap.get(u)) {
final List<Unit> attackers = moveMap.get(t).getMaxEnemyUnits();
final List<Unit> defenders = moveMap.get(t).getMaxDefenders();
defenders.removeAll(alreadyMovedUnits);
defenders.addAll(moveMap.get(t).getUnits());
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, attackers, defenders);
if (strengthDifference < minStrengthDifference) {
minStrengthDifference = strengthDifference;
minTerritory = t;
}
}
if (minTerritory != null) {
ProLogger.debug(u.getType().getName() + " moved to safest territory at " + minTerritory.getName() + " with strengthDifference=" + minStrengthDifference);
moveMap.get(minTerritory).addUnit(u);
it.remove();
}
}
}
ProLogger.info("Move air units");
// Get list of territories that can't be held
final List<Territory> territoriesThatCantBeHeld = moveMap.entrySet().stream().filter(e -> !e.getValue().isCanHold()).map(Map.Entry::getKey).collect(Collectors.toList());
// Move air units to safe territory with most attack options
for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (Matches.unitIsNotAir().test(u)) {
continue;
}
double maxAirValue = 0;
Territory maxTerritory = null;
for (final Territory t : unitMoveMap.get(u)) {
if (!moveMap.get(t).isCanHold()) {
continue;
}
if (t.isWater() && !ProTransportUtils.validateCarrierCapacity(player, t, moveMap.get(t).getAllDefendersForCarrierCalcs(data, player), u)) {
ProLogger.trace(t + " already at MAX carrier capacity");
continue;
}
// Check to see if the territory is safe
final List<Unit> defendingUnits = moveMap.get(t).getAllDefenders();
defendingUnits.add(u);
if (moveMap.get(t).getBattleResult() == null) {
moveMap.get(t).setBattleResult(calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), defendingUnits, moveMap.get(t).getMaxEnemyBombardUnits()));
}
final ProBattleResult result = moveMap.get(t).getBattleResult();
ProLogger.trace(t + ", TUVSwing=" + result.getTuvSwing() + ", win%=" + result.getWinPercentage() + ", defendingUnits=" + defendingUnits + ", enemyAttackers=" + moveMap.get(t).getMaxEnemyUnits());
if (result.getWinPercentage() >= ProData.minWinPercentage || result.getTuvSwing() > 0) {
moveMap.get(t).setCanHold(false);
continue;
}
// Determine if territory can be held with owned units
final List<Unit> myDefenders = CollectionUtils.getMatches(defendingUnits, Matches.unitIsOwnedBy(player));
final ProBattleResult result2 = calc.calculateBattleResults(t, moveMap.get(t).getMaxEnemyUnits(), myDefenders, moveMap.get(t).getMaxEnemyBombardUnits());
int cantHoldWithoutAllies = 0;
if (result2.getWinPercentage() >= ProData.minWinPercentage || result2.getTuvSwing() > 0) {
cantHoldWithoutAllies = 1;
}
// Find number of potential attack options next turn
final int range = TripleAUnit.get(u).getMaxMovementAllowed();
final Set<Territory> possibleAttackTerritories = data.getMap().getNeighbors(t, range / 2, ProMatches.territoryCanMoveAirUnits(player, data, true));
final int numEnemyAttackTerritories = CollectionUtils.countMatches(possibleAttackTerritories, ProMatches.territoryIsEnemyNotNeutralLand(player, data));
final int numLandAttackTerritories = CollectionUtils.countMatches(possibleAttackTerritories, ProMatches.territoryIsEnemyOrCantBeHeldAndIsAdjacentToMyLandUnits(player, data, territoriesThatCantBeHeld));
final int numSeaAttackTerritories = CollectionUtils.countMatches(possibleAttackTerritories, Matches.territoryHasEnemySeaUnits(player, data).and(Matches.territoryHasUnitsThatMatch(Matches.unitIsNotSub())));
final Set<Territory> possibleMoveTerritories = data.getMap().getNeighbors(t, range, ProMatches.territoryCanMoveAirUnits(player, data, true));
final int numNearbyEnemyTerritories = CollectionUtils.countMatches(possibleMoveTerritories, ProMatches.territoryIsEnemyNotNeutralLand(player, data));
// Check if number of attack territories and value are max
final int isntFactory = ProMatches.territoryHasInfraFactoryAndIsLand().test(t) ? 0 : 1;
final int hasOwnedCarrier = moveMap.get(t).getAllDefenders().stream().anyMatch(ProMatches.unitIsOwnedCarrier(player)) ? 1 : 0;
final double airValue = (200.0 * numSeaAttackTerritories + 100 * numLandAttackTerritories + 10 * numEnemyAttackTerritories + numNearbyEnemyTerritories) / (1 + cantHoldWithoutAllies) / (1 + cantHoldWithoutAllies * isntFactory) * (1 + hasOwnedCarrier);
if (airValue > maxAirValue) {
maxAirValue = airValue;
maxTerritory = t;
}
ProLogger.trace("Safe territory: " + t + ", airValue=" + airValue + ", numLandAttackOptions=" + numLandAttackTerritories + ", numSeaAttackTerritories=" + numSeaAttackTerritories + ", numEnemyAttackTerritories=" + numEnemyAttackTerritories);
}
if (maxTerritory != null) {
ProLogger.debug(u.getType().getName() + " added to safe territory with most attack options " + maxTerritory + ", maxAirValue=" + maxAirValue);
moveMap.get(maxTerritory).addUnit(u);
moveMap.get(maxTerritory).setBattleResult(null);
it.remove();
}
}
// Move air units to safest territory
for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (Matches.unitIsNotAir().test(u)) {
continue;
}
double minStrengthDifference = Double.POSITIVE_INFINITY;
Territory minTerritory = null;
for (final Territory t : unitMoveMap.get(u)) {
if (t.isWater() && !ProTransportUtils.validateCarrierCapacity(player, t, moveMap.get(t).getAllDefendersForCarrierCalcs(data, player), u)) {
ProLogger.trace(t + " already at MAX carrier capacity");
continue;
}
final List<Unit> attackers = moveMap.get(t).getMaxEnemyUnits();
final List<Unit> defenders = moveMap.get(t).getAllDefenders();
defenders.add(u);
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(t, attackers, defenders);
ProLogger.trace("Unsafe territory: " + t + " with strengthDifference=" + strengthDifference);
if (strengthDifference < minStrengthDifference) {
minStrengthDifference = strengthDifference;
minTerritory = t;
}
}
if (minTerritory != null) {
ProLogger.debug(u.getType().getName() + " added to safest territory at " + minTerritory + " with strengthDifference=" + minStrengthDifference);
moveMap.get(minTerritory).addUnit(u);
it.remove();
}
}
}
use of games.strategy.triplea.ai.pro.data.ProTerritory in project triplea by triplea-game.
the class ProNonCombatMoveAi method determineIfMoveTerritoriesCanBeHeld.
private void determineIfMoveTerritoriesCanBeHeld() {
ProLogger.info("Find max enemy attackers and if territories can be held");
final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
final ProOtherMoveOptions enemyAttackOptions = territoryManager.getEnemyAttackOptions();
// Determine which territories can possibly be held
for (final Territory t : moveMap.keySet()) {
final ProTerritory patd = moveMap.get(t);
// Check if no enemy attackers
if (enemyAttackOptions.getMax(t) == null) {
ProLogger.debug("Territory=" + t.getName() + ", CanHold=true since has no enemy attackers");
continue;
}
// Check if min defenders can hold it (not considering AA)
final Set<Unit> enemyAttackingUnits = new HashSet<>(enemyAttackOptions.getMax(t).getMaxUnits());
enemyAttackingUnits.addAll(enemyAttackOptions.getMax(t).getMaxAmphibUnits());
patd.setMaxEnemyUnits(new ArrayList<>(enemyAttackingUnits));
patd.setMaxEnemyBombardUnits(enemyAttackOptions.getMax(t).getMaxBombardUnits());
final List<Unit> minDefendingUnitsAndNotAa = CollectionUtils.getMatches(patd.getCantMoveUnits(), Matches.unitIsAaForAnything().negate());
final ProBattleResult minResult = calc.calculateBattleResults(t, new ArrayList<>(enemyAttackingUnits), minDefendingUnitsAndNotAa, enemyAttackOptions.getMax(t).getMaxBombardUnits());
patd.setMinBattleResult(minResult);
if (minResult.getTuvSwing() <= 0 && !minDefendingUnitsAndNotAa.isEmpty()) {
ProLogger.debug("Territory=" + t.getName() + ", CanHold=true" + ", MinDefenders=" + minDefendingUnitsAndNotAa.size() + ", EnemyAttackers=" + enemyAttackingUnits.size() + ", win%=" + minResult.getWinPercentage() + ", EnemyTUVSwing=" + minResult.getTuvSwing() + ", hasLandUnitRemaining=" + minResult.isHasLandUnitRemaining());
continue;
}
// Check if max defenders can hold it (not considering AA)
final Set<Unit> defendingUnits = new HashSet<>(patd.getMaxUnits());
defendingUnits.addAll(patd.getMaxAmphibUnits());
defendingUnits.addAll(patd.getCantMoveUnits());
final List<Unit> defendingUnitsAndNotAa = CollectionUtils.getMatches(defendingUnits, Matches.unitIsAaForAnything().negate());
final ProBattleResult result = calc.calculateBattleResults(t, new ArrayList<>(enemyAttackingUnits), defendingUnitsAndNotAa, enemyAttackOptions.getMax(t).getMaxBombardUnits());
int isFactory = 0;
if (ProMatches.territoryHasInfraFactoryAndIsLand().test(t)) {
isFactory = 1;
}
int isMyCapital = 0;
if (t.equals(ProData.myCapital)) {
isMyCapital = 1;
}
final List<Unit> extraUnits = new ArrayList<>(defendingUnitsAndNotAa);
extraUnits.removeAll(minDefendingUnitsAndNotAa);
final double extraUnitValue = TuvUtils.getTuv(extraUnits, ProData.unitValueMap);
final double holdValue = extraUnitValue / 8 * (1 + 0.5 * isFactory) * (1 + 2 * isMyCapital);
if (minDefendingUnitsAndNotAa.size() != defendingUnitsAndNotAa.size() && (result.getTuvSwing() - holdValue) < minResult.getTuvSwing()) {
ProLogger.debug("Territory=" + t.getName() + ", CanHold=true" + ", MaxDefenders=" + defendingUnitsAndNotAa.size() + ", EnemyAttackers=" + enemyAttackingUnits.size() + ", minTUVSwing=" + minResult.getTuvSwing() + ", win%=" + result.getWinPercentage() + ", EnemyTUVSwing=" + result.getTuvSwing() + ", hasLandUnitRemaining=" + result.isHasLandUnitRemaining() + ", holdValue=" + holdValue);
continue;
}
// Can't hold territory
patd.setCanHold(false);
ProLogger.debug("Can't hold Territory=" + t.getName() + ", MaxDefenders=" + defendingUnitsAndNotAa.size() + ", EnemyAttackers=" + enemyAttackingUnits.size() + ", minTUVSwing=" + minResult.getTuvSwing() + ", win%=" + result.getWinPercentage() + ", EnemyTUVSwing=" + result.getTuvSwing() + ", hasLandUnitRemaining=" + result.isHasLandUnitRemaining() + ", holdValue=" + holdValue);
}
}
Aggregations