use of games.strategy.engine.data.Route in project triplea by triplea-game.
the class ProTechAi method determineEnemyBlitzStrength.
/**
* Determine the enemy potential for blitzing a territory - all enemies are combined.
*
* @param blitzHere
* - Territory expecting to be blitzed
* @return actual strength of enemy units (armor)
*/
private static float determineEnemyBlitzStrength(final Territory blitzHere, final List<Route> blitzTerrRoutes, final GameData data, final PlayerID enemyPlayer) {
final HashSet<Integer> ignore = new HashSet<>();
ignore.add(1);
final Predicate<Unit> blitzUnit = Matches.unitIsOwnedBy(enemyPlayer).and(Matches.unitCanBlitz()).and(Matches.unitCanMove());
final Predicate<Territory> validBlitzRoute = Matches.territoryHasNoEnemyUnits(enemyPlayer, data).and(Matches.territoryIsNotImpassableToLandUnits(enemyPlayer, data));
final List<Route> routes = new ArrayList<>();
final List<Unit> blitzUnits = findAttackers(blitzHere, 2, ignore, enemyPlayer, data, blitzUnit, validBlitzRoute, routes, false);
for (final Route r : routes) {
if (r.numberOfSteps() == 2) {
blitzTerrRoutes.add(r);
}
}
return strength(blitzUnits, true, false, true);
}
use of games.strategy.engine.data.Route in project triplea by triplea-game.
the class ProTechAi method getStrengthOfPotentialAttackers.
/**
* Returns the strength of all attackers to a territory.
* Differentiates between sea and land attack
* Determines all transports within range of territory
* Determines all air units within range of territory (using 2 for fighters and 3 for bombers)
* Does not check for extended range fighters or bombers
*/
private static float getStrengthOfPotentialAttackers(final Territory location, final GameData data, final PlayerID player) {
final boolean transportsFirst = false;
PlayerID enemyPlayer = null;
final List<PlayerID> enemyPlayers = getEnemyPlayers(data, player);
final HashMap<PlayerID, Float> enemyPlayerAttackMap = new HashMap<>();
final Iterator<PlayerID> playerIter = enemyPlayers.iterator();
if (location == null) {
return -1000.0F;
}
boolean nonTransportsInAttack = false;
final boolean onWater = location.isWater();
if (!onWater) {
nonTransportsInAttack = true;
}
final Set<Territory> waterTerr = data.getMap().getNeighbors(location, Matches.territoryIsWater());
while (playerIter.hasNext()) {
float seaStrength = 0.0F;
float firstStrength = 0.0F;
float secondStrength = 0.0F;
float blitzStrength = 0.0F;
float strength;
enemyPlayer = playerIter.next();
final Predicate<Unit> enemyPlane = Matches.unitIsAir().and(Matches.unitIsOwnedBy(enemyPlayer)).and(Matches.unitCanMove());
final Predicate<Unit> enemyTransport = Matches.unitIsOwnedBy(enemyPlayer).and(Matches.unitIsSea()).and(Matches.unitIsTransport()).and(Matches.unitCanMove());
final Predicate<Unit> enemyShip = Matches.unitIsOwnedBy(enemyPlayer).and(Matches.unitIsSea()).and(Matches.unitCanMove());
final Predicate<Unit> enemyTransportable = Matches.unitIsOwnedBy(enemyPlayer).and(Matches.unitCanBeTransported()).and(Matches.unitIsNotAa()).and(Matches.unitCanMove());
final Predicate<Unit> transport = Matches.unitIsSea().and(Matches.unitIsTransport()).and(Matches.unitCanMove());
final List<Territory> enemyFighterTerritories = findUnitTerr(data, enemyPlane);
int maxFighterDistance = 0;
// and likely player will have at least 1 max move plane.
for (final Territory enemyFighterTerritory : enemyFighterTerritories) {
final List<Unit> enemyFighterUnits = enemyFighterTerritory.getUnits().getMatches(enemyPlane);
maxFighterDistance = Math.max(maxFighterDistance, MoveValidator.getMaxMovement(enemyFighterUnits));
}
// must be able to land...we will miss fighters who have a Carrier that can reach same sea zone...C'est la vie
maxFighterDistance--;
if (maxFighterDistance < 0) {
maxFighterDistance = 0;
}
final List<Territory> enemyTransportTerritories = findUnitTerr(data, transport);
int maxTransportDistance = 0;
for (final Territory enemyTransportTerritory : enemyTransportTerritories) {
final List<Unit> enemyTransportUnits = enemyTransportTerritory.getUnits().getMatches(transport);
maxTransportDistance = Math.max(maxTransportDistance, MoveValidator.getMaxMovement(enemyTransportUnits));
}
final List<Unit> alreadyLoaded = new ArrayList<>();
final List<Route> blitzTerrRoutes = new ArrayList<>();
final List<Territory> checked = new ArrayList<>();
final List<Unit> enemyWaterUnits = new ArrayList<>();
for (final Territory t : data.getMap().getNeighbors(location, onWater ? Matches.territoryIsWater() : Matches.territoryIsLand())) {
final List<Unit> enemies = t.getUnits().getMatches(Matches.unitIsOwnedBy(enemyPlayer));
enemyWaterUnits.addAll(enemies);
firstStrength += strength(enemies, true, onWater, transportsFirst);
checked.add(t);
}
if (Matches.territoryIsLand().test(location)) {
blitzStrength = determineEnemyBlitzStrength(location, blitzTerrRoutes, data, enemyPlayer);
} else {
// get ships attack strength
// old assumed fleets won't split up, new lets them. no biggie.
// assumes max ship movement is 3.
// note, both old and new implementations
// allow units to be calculated that are in
// territories we have already assaulted
// this can be easily changed
final HashSet<Integer> ignore = new HashSet<>();
ignore.add(1);
final List<Route> r = new ArrayList<>();
final List<Unit> ships = findAttackers(location, 3, ignore, enemyPlayer, data, enemyShip, Matches.territoryIsBlockedSea(enemyPlayer, data), r, true);
secondStrength = strength(ships, true, true, transportsFirst);
enemyWaterUnits.addAll(ships);
}
final List<Unit> attackPlanes = findPlaneAttackersThatCanLand(location, maxFighterDistance, enemyPlayer, data, checked);
final float airStrength = allAirStrength(attackPlanes);
if (Matches.territoryHasWaterNeighbor(data).test(location) && Matches.territoryIsLand().test(location)) {
for (final Territory t4 : data.getMap().getNeighbors(location, maxTransportDistance)) {
if (!t4.isWater()) {
continue;
}
for (final Territory waterCheck : waterTerr) {
if (enemyPlayer == null) {
continue;
}
final List<Unit> transports = t4.getUnits().getMatches(enemyTransport);
if (transports.isEmpty()) {
continue;
}
if (!t4.equals(waterCheck)) {
final Route seaRoute = getMaxSeaRoute(data, t4, waterCheck, enemyPlayer, maxTransportDistance);
if (seaRoute == null || seaRoute.getEnd() == null || seaRoute.getEnd() != waterCheck) {
continue;
}
}
final List<Unit> loadedUnits = new ArrayList<>();
int availInf = 0;
int availOther = 0;
for (final Unit candidateTransport : transports) {
final Collection<Unit> thisTransUnits = TransportTracker.transporting(candidateTransport);
if (thisTransUnits == null) {
availInf += 2;
availOther += 1;
continue;
}
int inf = 2;
int other = 1;
for (final Unit checkUnit : thisTransUnits) {
if (Matches.unitIsLandTransportable().test(checkUnit)) {
inf--;
}
if (Matches.unitIsNotLandTransportable().test(checkUnit)) {
inf--;
other--;
}
loadedUnits.add(checkUnit);
}
availInf += inf;
availOther += other;
}
final Set<Territory> transNeighbors = data.getMap().getNeighbors(t4, Matches.isTerritoryAllied(enemyPlayer, data));
for (final Territory transNeighbor : transNeighbors) {
final List<Unit> transUnits = transNeighbor.getUnits().getMatches(enemyTransportable);
transUnits.removeAll(alreadyLoaded);
final List<Unit> availTransUnits = sortTransportUnits(transUnits);
for (final Unit transUnit : availTransUnits) {
if (availInf > 0 && Matches.unitIsLandTransportable().test(transUnit)) {
availInf--;
loadedUnits.add(transUnit);
alreadyLoaded.add(transUnit);
}
if (availInf > 0 && availOther > 0 && Matches.unitIsNotLandTransportable().test(transUnit)) {
availInf--;
availOther--;
loadedUnits.add(transUnit);
alreadyLoaded.add(transUnit);
}
}
}
seaStrength += strength(loadedUnits, true, false, transportsFirst);
break;
}
}
}
strength = seaStrength + blitzStrength + firstStrength + secondStrength;
if (strength > 0.0F) {
strength += airStrength;
}
if (onWater) {
final Iterator<Unit> enemyWaterUnitsIter = enemyWaterUnits.iterator();
while (enemyWaterUnitsIter.hasNext() && !nonTransportsInAttack) {
if (Matches.unitIsNotTransport().test(enemyWaterUnitsIter.next())) {
nonTransportsInAttack = true;
}
}
}
if (!nonTransportsInAttack) {
strength = 0.0F;
}
enemyPlayerAttackMap.put(enemyPlayer, strength);
}
float maxStrength = 0.0F;
for (final PlayerID enemyPlayerCandidate : enemyPlayers) {
if (enemyPlayerAttackMap.get(enemyPlayerCandidate) > maxStrength) {
enemyPlayer = enemyPlayerCandidate;
maxStrength = enemyPlayerAttackMap.get(enemyPlayerCandidate);
}
}
for (final PlayerID enemyPlayerCandidate : enemyPlayers) {
if (enemyPlayer != enemyPlayerCandidate) {
// give 40% of other players...this is will affect a lot of decisions by AI
maxStrength += enemyPlayerAttackMap.get(enemyPlayerCandidate) * 0.40F;
}
}
return maxStrength;
}
use of games.strategy.engine.data.Route 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.engine.data.Route in project triplea by triplea-game.
the class ProMoveUtils method doMove.
public static void doMove(final List<Collection<Unit>> moveUnits, final List<Route> moveRoutes, final List<Collection<Unit>> transportsToLoad, final IMoveDelegate moveDel) {
final GameData data = ProData.getData();
// Group non-amphib units of the same type moving on the same route
if (transportsToLoad == null) {
for (int i = 0; i < moveRoutes.size(); i++) {
final Route r = moveRoutes.get(i);
for (int j = i + 1; j < moveRoutes.size(); j++) {
final Route r2 = moveRoutes.get(j);
if (r.equals(r2)) {
moveUnits.get(j).addAll(moveUnits.get(i));
moveUnits.remove(i);
moveRoutes.remove(i);
i--;
break;
}
}
}
}
// Move units
for (int i = 0; i < moveRoutes.size(); i++) {
if (!ProData.isSimulation) {
ProUtils.pause();
}
if (moveRoutes.get(i) == null || moveRoutes.get(i).getEnd() == null || moveRoutes.get(i).getStart() == null) {
ProLogger.warn(data.getSequence().getRound() + "-" + data.getSequence().getStep().getName() + ": route not valid " + moveRoutes.get(i) + " units: " + moveUnits.get(i));
continue;
}
final String result;
if (transportsToLoad == null || transportsToLoad.get(i) == null) {
result = moveDel.move(moveUnits.get(i), moveRoutes.get(i));
} else {
result = moveDel.move(moveUnits.get(i), moveRoutes.get(i), transportsToLoad.get(i));
}
if (result != null) {
ProLogger.warn(data.getSequence().getRound() + "-" + data.getSequence().getStep().getName() + ": could not move " + moveUnits.get(i) + " over " + moveRoutes.get(i) + " because: " + result);
}
}
}
use of games.strategy.engine.data.Route in project triplea by triplea-game.
the class ProMoveUtils method calculateMoveRoutes.
public static void calculateMoveRoutes(final PlayerID player, final List<Collection<Unit>> moveUnits, final List<Route> moveRoutes, final Map<Territory, ProTerritory> attackMap, final boolean isCombatMove) {
final GameData data = ProData.getData();
// Find all amphib units
final Set<Unit> amphibUnits = attackMap.values().stream().map(ProTerritory::getAmphibAttackMap).map(Map::entrySet).flatMap(Collection::stream).flatMap(e -> Stream.concat(Stream.of(e.getKey()), e.getValue().stream())).collect(Collectors.toSet());
// Loop through all territories to attack
for (final Territory t : attackMap.keySet()) {
// Loop through each unit that is attacking the current territory
for (final Unit u : attackMap.get(t).getUnits()) {
// Skip amphib units
if (amphibUnits.contains(u)) {
continue;
}
// Skip if unit is already in move to territory
final Territory startTerritory = ProData.unitTerritoryMap.get(u);
if (startTerritory == null || startTerritory.equals(t)) {
continue;
}
// Add unit to move list
final List<Unit> unitList = new ArrayList<>();
unitList.add(u);
moveUnits.add(unitList);
// If carrier has dependent allied fighters then move them too
if (Matches.unitIsCarrier().test(u)) {
final Map<Unit, Collection<Unit>> carrierMustMoveWith = MoveValidator.carrierMustMoveWith(startTerritory.getUnits().getUnits(), startTerritory, data, player);
if (carrierMustMoveWith.containsKey(u)) {
unitList.addAll(carrierMustMoveWith.get(u));
}
}
// Determine route and add to move list
Route route = null;
if (unitList.stream().anyMatch(Matches.unitIsSea())) {
// Sea unit (including carriers with planes)
route = data.getMap().getRoute_IgnoreEnd(startTerritory, t, ProMatches.territoryCanMoveSeaUnitsThrough(player, data, isCombatMove));
} else if (!unitList.isEmpty() && unitList.stream().allMatch(Matches.unitIsLand())) {
// Land unit
route = data.getMap().getRoute_IgnoreEnd(startTerritory, t, ProMatches.territoryCanMoveLandUnitsThrough(player, data, u, startTerritory, isCombatMove, new ArrayList<>()));
} else if (!unitList.isEmpty() && unitList.stream().allMatch(Matches.unitIsAir())) {
// Air unit
route = data.getMap().getRoute_IgnoreEnd(startTerritory, t, ProMatches.territoryCanMoveAirUnitsAndNoAa(player, data, isCombatMove));
}
if (route == null) {
ProLogger.warn(data.getSequence().getRound() + "-" + data.getSequence().getStep().getName() + ": route is null " + startTerritory + " to " + t + ", units=" + unitList);
}
moveRoutes.add(route);
}
}
}
Aggregations