use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseAi method purchaseLandUnits.
private void purchaseLandUnits(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final List<ProPlaceTerritory> prioritizedLandTerritories, final ProPurchaseOptionMap purchaseOptions, final Map<Territory, Double> territoryValueMap) {
final List<Unit> unplacedUnits = player.getUnits().getMatches(Matches.unitIsNotSea());
if (resourceTracker.isEmpty() && unplacedUnits.isEmpty()) {
return;
}
ProLogger.info("Purchase land units with resources: " + resourceTracker);
if (!unplacedUnits.isEmpty()) {
ProLogger.info("Purchase land units with unplaced units=" + unplacedUnits);
}
// Loop through prioritized territories and purchase land units
for (final ProPlaceTerritory placeTerritory : prioritizedLandTerritories) {
final Territory t = placeTerritory.getTerritory();
ProLogger.debug("Checking land place for " + t.getName());
// Check remaining production
int remainingUnitProduction = purchaseTerritories.get(t).getRemainingUnitProduction();
ProLogger.debug(t + ", remainingUnitProduction=" + remainingUnitProduction);
if (remainingUnitProduction <= 0) {
continue;
}
// Determine most cost efficient units that can be produced in this territory
final List<ProPurchaseOption> landFodderOptions = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getLandFodderOptions(), t, isBid);
final List<ProPurchaseOption> landAttackOptions = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getLandAttackOptions(), t, isBid);
final List<ProPurchaseOption> landDefenseOptions = ProPurchaseUtils.findPurchaseOptionsForTerritory(player, purchaseOptions.getLandDefenseOptions(), t, isBid);
// Determine enemy distance and locally owned units
int enemyDistance = ProUtils.getClosestEnemyOrNeutralLandTerritoryDistance(data, player, t, territoryValueMap);
if (enemyDistance <= 0) {
enemyDistance = 10;
}
final int fodderPercent = 80 - enemyDistance * 5;
ProLogger.debug(t + ", enemyDistance=" + enemyDistance + ", fodderPercent=" + fodderPercent);
final Set<Territory> neighbors = data.getMap().getNeighbors(t, 2, ProMatches.territoryCanMoveLandUnits(player, data, false));
neighbors.add(t);
final List<Unit> ownedLocalUnits = new ArrayList<>();
for (final Territory neighbor : neighbors) {
ownedLocalUnits.addAll(neighbor.getUnits().getMatches(Matches.unitIsOwnedBy(player)));
}
// Check for unplaced units
final List<Unit> unitsToPlace = new ArrayList<>();
for (final Iterator<Unit> it = unplacedUnits.iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (remainingUnitProduction > 0 && ProPurchaseUtils.canUnitsBePlaced(Collections.singletonList(u), player, t, isBid)) {
remainingUnitProduction--;
unitsToPlace.add(u);
it.remove();
ProLogger.trace("Selected unplaced unit=" + u);
}
}
// Purchase as many units as possible
int addedFodderUnits = 0;
double attackAndDefenseDifference = 0;
boolean selectFodderUnit = true;
while (true) {
// Remove options that cost too much PUs or production
ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, landFodderOptions, resourceTracker, remainingUnitProduction, unitsToPlace, purchaseTerritories);
ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, landAttackOptions, resourceTracker, remainingUnitProduction, unitsToPlace, purchaseTerritories);
ProPurchaseUtils.removeInvalidPurchaseOptions(player, startOfTurnData, landDefenseOptions, resourceTracker, remainingUnitProduction, unitsToPlace, purchaseTerritories);
// Select purchase option
Optional<ProPurchaseOption> optionalSelectedOption = Optional.empty();
if (!selectFodderUnit && attackAndDefenseDifference > 0 && !landDefenseOptions.isEmpty()) {
final Map<ProPurchaseOption, Double> defenseEfficiencies = new HashMap<>();
for (final ProPurchaseOption ppo : landDefenseOptions) {
defenseEfficiencies.put(ppo, ppo.getDefenseEfficiency2(enemyDistance, data, ownedLocalUnits, unitsToPlace));
}
optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(defenseEfficiencies, "Land Defense");
} else if (!selectFodderUnit && !landAttackOptions.isEmpty()) {
final Map<ProPurchaseOption, Double> attackEfficiencies = new HashMap<>();
for (final ProPurchaseOption ppo : landAttackOptions) {
attackEfficiencies.put(ppo, ppo.getAttackEfficiency2(enemyDistance, data, ownedLocalUnits, unitsToPlace));
}
optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(attackEfficiencies, "Land Attack");
} else if (!landFodderOptions.isEmpty()) {
final Map<ProPurchaseOption, Double> fodderEfficiencies = new HashMap<>();
for (final ProPurchaseOption ppo : landFodderOptions) {
fodderEfficiencies.put(ppo, ppo.getFodderEfficiency(enemyDistance, data, ownedLocalUnits, unitsToPlace));
}
optionalSelectedOption = ProPurchaseUtils.randomizePurchaseOption(fodderEfficiencies, "Land Fodder");
if (optionalSelectedOption.isPresent()) {
addedFodderUnits += optionalSelectedOption.get().getQuantity();
}
}
if (!optionalSelectedOption.isPresent()) {
break;
}
final ProPurchaseOption selectedOption = optionalSelectedOption.get();
// Create new temp units
resourceTracker.purchase(selectedOption);
remainingUnitProduction -= selectedOption.getQuantity();
unitsToPlace.addAll(selectedOption.getUnitType().create(selectedOption.getQuantity(), player, true));
attackAndDefenseDifference += (selectedOption.getAttack() - selectedOption.getDefense());
selectFodderUnit = ((double) addedFodderUnits / unitsToPlace.size() * 100) <= fodderPercent;
ProLogger.trace("Selected unit=" + selectedOption.getUnitType().getName());
}
// Add units to place territory
placeTerritory.getPlaceUnits().addAll(unitsToPlace);
ProLogger.debug(t + ", placedUnits=" + unitsToPlace);
}
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProNonCombatMoveAi method findUnitsThatCantMove.
private void findUnitsThatCantMove(final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final List<ProPurchaseOption> landPurchaseOptions) {
ProLogger.info("Find units that can't move");
final Map<Territory, ProTerritory> moveMap = territoryManager.getDefendOptions().getTerritoryMap();
final Map<Unit, Set<Territory>> unitMoveMap = territoryManager.getDefendOptions().getUnitMoveMap();
final List<ProTransport> transportMapList = territoryManager.getDefendOptions().getTransportList();
// Add all units that can't move (allied units, 0 move units, etc)
for (final Territory t : moveMap.keySet()) {
moveMap.get(t).getCantMoveUnits().addAll(t.getUnits().getMatches(ProMatches.unitCantBeMovedAndIsAlliedDefender(player, data, t)));
}
// Add all units that only have 1 move option and can't be transported
for (final Iterator<Unit> it = unitMoveMap.keySet().iterator(); it.hasNext(); ) {
final Unit u = it.next();
if (unitMoveMap.get(u).size() == 1) {
final Territory onlyTerritory = unitMoveMap.get(u).iterator().next();
if (onlyTerritory.equals(unitTerritoryMap.get(u))) {
boolean canBeTransported = false;
for (final ProTransport pad : transportMapList) {
for (final Territory t : pad.getTransportMap().keySet()) {
if (pad.getTransportMap().get(t).contains(onlyTerritory)) {
canBeTransported = true;
}
}
for (final Territory t : pad.getSeaTransportMap().keySet()) {
if (pad.getSeaTransportMap().get(t).contains(onlyTerritory)) {
canBeTransported = true;
}
}
}
if (!canBeTransported) {
moveMap.get(onlyTerritory).getCantMoveUnits().add(u);
it.remove();
}
}
}
}
// Check if purchase units are known yet
if (purchaseTerritories != null) {
// Add all units that will be purchased
for (final ProPurchaseTerritory ppt : purchaseTerritories.values()) {
for (final ProPlaceTerritory placeTerritory : ppt.getCanPlaceTerritories()) {
final Territory t = placeTerritory.getTerritory();
if (moveMap.get(t) != null) {
moveMap.get(t).getCantMoveUnits().addAll(placeTerritory.getPlaceUnits());
}
}
}
} else {
// Add max defenders that can be purchased to each territory
for (final Territory t : moveMap.keySet()) {
if (ProMatches.territoryHasNonMobileInfraFactoryAndIsNotConqueredOwnedLand(player, data).test(t)) {
moveMap.get(t).getCantMoveUnits().addAll(ProPurchaseUtils.findMaxPurchaseDefenders(player, t, landPurchaseOptions));
}
}
}
// Log can't move units per territory
for (final Territory t : moveMap.keySet()) {
if (!moveMap.get(t).getCantMoveUnits().isEmpty()) {
ProLogger.trace(t + " has units that can't move: " + moveMap.get(t).getCantMoveUnits());
}
}
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProNonCombatMoveAi method doNonCombatMove.
Map<Territory, ProTerritory> doNonCombatMove(Map<Territory, ProTerritory> factoryMoveMap, final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final IMoveDelegate moveDel) {
ProLogger.info("Starting non-combat move phase");
// Current data at the start of non-combat move
data = ProData.getData();
player = ProData.getPlayer();
unitTerritoryMap = ProData.unitTerritoryMap;
territoryManager = new ProTerritoryManager(calc);
// Find the max number of units that can move to each allied territory
territoryManager.populateDefenseOptions(new ArrayList<>());
// Find number of units in each move territory that can't move and all infra units
findUnitsThatCantMove(purchaseTerritories, ProData.purchaseOptions.getLandOptions());
final Map<Unit, Set<Territory>> infraUnitMoveMap = findInfraUnitsThatCanMove();
// Try to have one land unit in each territory that is bordering an enemy territory
final List<Territory> movedOneDefenderToTerritories = moveOneDefenderToLandTerritoriesBorderingEnemy();
// Determine max enemy attack units and if territories can be held
territoryManager.populateEnemyAttackOptions(movedOneDefenderToTerritories, territoryManager.getDefendTerritories());
determineIfMoveTerritoriesCanBeHeld();
// Get list of territories that can't be held and find move value for each territory
final List<Territory> territoriesThatCantBeHeld = territoryManager.getCantHoldTerritories();
final Map<Territory, Double> territoryValueMap = ProTerritoryValueUtils.findTerritoryValues(player, territoriesThatCantBeHeld, new ArrayList<>());
final Map<Territory, Double> seaTerritoryValueMap = ProTerritoryValueUtils.findSeaTerritoryValues(player, territoriesThatCantBeHeld);
// Prioritize territories to defend
final List<ProTerritory> prioritizedTerritories = prioritizeDefendOptions(factoryMoveMap, territoryValueMap);
// Determine which territories to defend and how many units each one needs
final int enemyDistance = ProUtils.getClosestEnemyLandTerritoryDistance(data, player, ProData.myCapital);
moveUnitsToDefendTerritories(prioritizedTerritories, enemyDistance, territoryValueMap);
// Copy data in case capital defense needs increased
final ProTerritoryManager territoryManagerCopy = new ProTerritoryManager(calc, territoryManager);
// Use loop to ensure capital is protected after moves
if (ProData.myCapital != null) {
int defenseRange = -1;
while (true) {
// Add value to territories near capital if necessary
for (final Territory t : territoryManager.getDefendTerritories()) {
double value = territoryValueMap.get(t);
final int distance = data.getMap().getDistance(ProData.myCapital, t, ProMatches.territoryCanMoveLandUnits(player, data, false));
if (distance >= 0 && distance <= defenseRange) {
value *= 10;
}
territoryManager.getDefendOptions().getTerritoryMap().get(t).setValue(value);
if (t.isWater()) {
territoryManager.getDefendOptions().getTerritoryMap().get(t).setSeaValue(seaTerritoryValueMap.get(t));
}
}
moveUnitsToBestTerritories();
// Check if capital has local land superiority
ProLogger.info("Checking if capital has local land superiority with enemyDistance=" + enemyDistance);
if (enemyDistance >= 2 && enemyDistance <= 3 && defenseRange == -1 && !ProBattleUtils.territoryHasLocalLandSuperiorityAfterMoves(ProData.myCapital, enemyDistance, player, territoryManager.getDefendOptions().getTerritoryMap())) {
defenseRange = enemyDistance - 1;
territoryManager = territoryManagerCopy;
ProLogger.debug("Capital doesn't have local land superiority so setting defensive stance");
} else {
break;
}
}
} else {
moveUnitsToBestTerritories();
}
// Determine where to move infra units
factoryMoveMap = moveInfraUnits(factoryMoveMap, infraUnitMoveMap);
// Log a warning if any units not assigned to a territory (skip infrastructure for now)
for (final Unit u : territoryManager.getDefendOptions().getUnitMoveMap().keySet()) {
if (Matches.unitIsInfrastructure().negate().test(u)) {
ProLogger.warn(player + ": " + unitTerritoryMap.get(u) + " has unmoved unit: " + u + " with options: " + territoryManager.getDefendOptions().getUnitMoveMap().get(u));
}
}
// Calculate move routes and perform moves
doMove(territoryManager.getDefendOptions().getTerritoryMap(), moveDel, data, player);
// Log results
ProLogger.info("Logging results");
logAttackMoves(prioritizedTerritories);
return factoryMoveMap;
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProBattleUtils method territoryHasLocalNavalSuperiority.
public static boolean territoryHasLocalNavalSuperiority(final Territory t, final PlayerID player, final Map<Territory, ProPurchaseTerritory> purchaseTerritories, final List<Unit> unitsToPlace) {
final GameData data = ProData.getData();
int landDistance = ProUtils.getClosestEnemyLandTerritoryDistanceOverWater(data, player, t);
if (landDistance <= 0) {
landDistance = 10;
}
final int enemyDistance = Math.max(3, (landDistance + 1));
final Set<Territory> nearbyTerritories = data.getMap().getNeighbors(t, enemyDistance);
final List<Territory> nearbyLandTerritories = CollectionUtils.getMatches(nearbyTerritories, Matches.territoryIsLand());
final Set<Territory> nearbyEnemySeaTerritories = data.getMap().getNeighbors(t, enemyDistance, Matches.territoryIsWater());
nearbyEnemySeaTerritories.add(t);
final int alliedDistance = (enemyDistance + 1) / 2;
final Set<Territory> nearbyAlliedSeaTerritories = data.getMap().getNeighbors(t, alliedDistance, Matches.territoryIsWater());
nearbyAlliedSeaTerritories.add(t);
final List<Unit> enemyUnitsInLandTerritories = new ArrayList<>();
for (final Territory nearbyLandTerritory : nearbyLandTerritories) {
enemyUnitsInLandTerritories.addAll(nearbyLandTerritory.getUnits().getMatches(ProMatches.unitIsEnemyAir(player, data)));
}
final List<Unit> enemyUnitsInSeaTerritories = new ArrayList<>();
for (final Territory nearbySeaTerritory : nearbyEnemySeaTerritories) {
final List<Unit> enemySeaUnits = nearbySeaTerritory.getUnits().getMatches(ProMatches.unitIsEnemyNotLand(player, data));
if (enemySeaUnits.isEmpty()) {
continue;
}
final Route route = data.getMap().getRoute_IgnoreEnd(t, nearbySeaTerritory, Matches.territoryIsWater());
if (route == null) {
continue;
}
if (MoveValidator.validateCanal(route, enemySeaUnits, enemySeaUnits.get(0).getOwner(), data) != null) {
continue;
}
final int routeLength = route.numberOfSteps();
if (routeLength <= enemyDistance) {
enemyUnitsInSeaTerritories.addAll(enemySeaUnits);
}
}
final List<Unit> alliedUnitsInSeaTerritories = new ArrayList<>();
final List<Unit> myUnitsInSeaTerritories = new ArrayList<>();
for (final Territory nearbySeaTerritory : nearbyAlliedSeaTerritories) {
myUnitsInSeaTerritories.addAll(nearbySeaTerritory.getUnits().getMatches(ProMatches.unitIsOwnedNotLand(player)));
myUnitsInSeaTerritories.addAll(ProPurchaseUtils.getPlaceUnits(nearbySeaTerritory, purchaseTerritories));
alliedUnitsInSeaTerritories.addAll(nearbySeaTerritory.getUnits().getMatches(ProMatches.unitIsAlliedNotOwned(player, data)));
}
ProLogger.trace(t + ", enemyDistance=" + enemyDistance + ", alliedDistance=" + alliedDistance + ", enemyAirUnits=" + enemyUnitsInLandTerritories + ", enemySeaUnits=" + enemyUnitsInSeaTerritories + ", mySeaUnits=" + myUnitsInSeaTerritories);
// Find current naval defense strength
final List<Unit> myUnits = new ArrayList<>(myUnitsInSeaTerritories);
myUnits.addAll(unitsToPlace);
myUnits.addAll(alliedUnitsInSeaTerritories);
final List<Unit> enemyAttackers = new ArrayList<>(enemyUnitsInSeaTerritories);
enemyAttackers.addAll(enemyUnitsInLandTerritories);
final double defenseStrengthDifference = estimateStrengthDifference(t, enemyAttackers, myUnits);
ProLogger.trace(t + ", current enemy naval attack strengthDifference=" + defenseStrengthDifference + ", enemySize=" + enemyAttackers.size() + ", alliedSize=" + myUnits.size());
// Find current naval attack strength
double attackStrengthDifference = estimateStrengthDifference(t, myUnits, enemyUnitsInSeaTerritories);
attackStrengthDifference += 0.5 * estimateStrengthDifference(t, alliedUnitsInSeaTerritories, enemyUnitsInSeaTerritories);
ProLogger.trace(t + ", current allied naval attack strengthDifference=" + attackStrengthDifference + ", alliedSize=" + myUnits.size() + ", enemySize=" + enemyUnitsInSeaTerritories.size());
// If I have naval attack/defense superiority then break
return (defenseStrengthDifference < 50 && attackStrengthDifference > 50);
}
use of games.strategy.triplea.ai.pro.data.ProPurchaseTerritory in project triplea by triplea-game.
the class ProPurchaseUtils method findBidTerritories.
/**
* Find all territories that bid units can be placed in and initialize data holders for them.
*
* @param player - current AI player
* @return - map of all available purchase and place territories
*/
public static Map<Territory, ProPurchaseTerritory> findBidTerritories(final PlayerID player) {
ProLogger.info("Find all bid territories");
final GameData data = ProData.getData();
// Find all territories that I can place units on
final Set<Territory> ownedOrHasUnitTerritories = new HashSet<>(data.getMap().getTerritoriesOwnedBy(player));
ownedOrHasUnitTerritories.addAll(ProData.myUnitTerritories);
final List<Territory> potentialTerritories = CollectionUtils.getMatches(ownedOrHasUnitTerritories, Matches.territoryIsPassableAndNotRestrictedAndOkByRelationships(player, data, false, false, false, false, false));
// Create purchase territory holder for each factory territory
final Map<Territory, ProPurchaseTerritory> purchaseTerritories = new HashMap<>();
for (final Territory t : potentialTerritories) {
final ProPurchaseTerritory ppt = new ProPurchaseTerritory(t, data, player, 1, true);
purchaseTerritories.put(t, ppt);
ProLogger.debug(ppt.toString());
}
return purchaseTerritories;
}
Aggregations