use of games.strategy.engine.data.PlayerID in project triplea by triplea-game.
the class ProUtils method getLiveEnemyCapitals.
public static List<Territory> getLiveEnemyCapitals(final GameData data, final PlayerID player) {
final List<Territory> enemyCapitals = new ArrayList<>();
final List<PlayerID> enemyPlayers = getEnemyPlayers(player);
for (final PlayerID otherPlayer : enemyPlayers) {
enemyCapitals.addAll(TerritoryAttachment.getAllCurrentlyOwnedCapitals(otherPlayer, data));
}
enemyCapitals.retainAll(CollectionUtils.getMatches(enemyCapitals, Matches.territoryIsNotImpassableToLandUnits(player, data)));
enemyCapitals.retainAll(CollectionUtils.getMatches(enemyCapitals, Matches.isTerritoryOwnedBy(getPotentialEnemyPlayers(player))));
return enemyCapitals;
}
use of games.strategy.engine.data.PlayerID in project triplea by triplea-game.
the class WeakAi method populateCombatMove.
private static void populateCombatMove(final GameData data, final List<Collection<Unit>> moveUnits, final List<Route> moveRoutes, final PlayerID player) {
populateBomberCombat(data, moveUnits, moveRoutes, player);
final Collection<Unit> unitsAlreadyMoved = new HashSet<>();
// find the territories we can just walk into
final Predicate<Territory> walkInto = Matches.isTerritoryEnemyAndNotUnownedWaterOrImpassableOrRestricted(player, data).or(Matches.isTerritoryFreeNeutral(data));
final List<Territory> enemyOwned = CollectionUtils.getMatches(data.getMap().getTerritories(), walkInto);
Collections.shuffle(enemyOwned);
enemyOwned.sort((o1, o2) -> {
// -1 means o1 goes first. 1 means o2 goes first. zero means they are equal.
if (Objects.equals(o1, o2)) {
return 0;
}
if (o1 == null) {
return 1;
}
if (o2 == null) {
return -1;
}
final TerritoryAttachment ta1 = TerritoryAttachment.get(o1);
final TerritoryAttachment ta2 = TerritoryAttachment.get(o2);
if (ta1 == null && ta2 == null) {
return 0;
}
if (ta1 == null) {
return 1;
}
if (ta2 == null) {
return -1;
}
// take capitols first if we can
if (ta1.isCapital() && !ta2.isCapital()) {
return -1;
}
if (!ta1.isCapital() && ta2.isCapital()) {
return 1;
}
final boolean factoryInT1 = o1.getUnits().anyMatch(Matches.unitCanProduceUnits());
final boolean factoryInT2 = o2.getUnits().anyMatch(Matches.unitCanProduceUnits());
// next take territories which can produce
if (factoryInT1 && !factoryInT2) {
return -1;
}
if (!factoryInT1 && factoryInT2) {
return 1;
}
final boolean infrastructureInT1 = o1.getUnits().anyMatch(Matches.unitIsInfrastructure());
final boolean infrastructureInT2 = o2.getUnits().anyMatch(Matches.unitIsInfrastructure());
// next take territories with infrastructure
if (infrastructureInT1 && !infrastructureInT2) {
return -1;
}
if (!infrastructureInT1 && infrastructureInT2) {
return 1;
}
// next take territories with largest PU value
return ta2.getProduction() - ta1.getProduction();
});
final List<Territory> isWaterTerr = Utils.onlyWaterTerr(enemyOwned);
enemyOwned.removeAll(isWaterTerr);
// first find the territories we can just walk into
for (final Territory enemy : enemyOwned) {
if (AiUtils.strength(enemy.getUnits().getUnits(), false, false) == 0) {
// only take it with 1 unit
boolean taken = false;
for (final Territory attackFrom : data.getMap().getNeighbors(enemy, Matches.territoryHasLandUnitsOwnedBy(player))) {
if (taken) {
break;
}
// get the cheapest unit to move in
final List<Unit> unitsSortedByCost = new ArrayList<>(attackFrom.getUnits().getUnits());
unitsSortedByCost.sort(AiUtils.getCostComparator());
for (final Unit unit : unitsSortedByCost) {
final Predicate<Unit> match = Matches.unitIsOwnedBy(player).and(Matches.unitIsLand()).and(Matches.unitIsNotInfrastructure()).and(Matches.unitCanMove()).and(Matches.unitIsNotAa()).and(Matches.unitCanNotMoveDuringCombatMove().negate());
if (!unitsAlreadyMoved.contains(unit) && match.test(unit)) {
moveRoutes.add(data.getMap().getRoute(attackFrom, enemy));
// number of units, to leave units free to move elsewhere
if (attackFrom.isWater()) {
final List<Unit> units = attackFrom.getUnits().getMatches(Matches.unitIsLandAndOwnedBy(player));
moveUnits.add(CollectionUtils.difference(units, unitsAlreadyMoved));
unitsAlreadyMoved.addAll(units);
} else {
moveUnits.add(Collections.singleton(unit));
}
unitsAlreadyMoved.add(unit);
taken = true;
break;
}
}
}
}
}
// find the territories we can reasonably expect to take
for (final Territory enemy : enemyOwned) {
final float enemyStrength = AiUtils.strength(enemy.getUnits().getUnits(), false, false);
if (enemyStrength > 0) {
final Predicate<Unit> attackable = Matches.unitIsOwnedBy(player).and(Matches.unitIsStrategicBomber().negate()).and(o -> !unitsAlreadyMoved.contains(o)).and(Matches.unitIsNotAa()).and(Matches.unitCanMove()).and(Matches.unitIsNotInfrastructure()).and(Matches.unitCanNotMoveDuringCombatMove().negate()).and(Matches.unitIsNotSea());
final Set<Territory> dontMoveFrom = new HashSet<>();
// find our strength that we can attack with
float ourStrength = 0;
final Collection<Territory> attackFrom = data.getMap().getNeighbors(enemy, Matches.territoryHasLandUnitsOwnedBy(player));
for (final Territory owned : attackFrom) {
if (TerritoryAttachment.get(owned) != null && TerritoryAttachment.get(owned).isCapital() && (Utils.getStrengthOfPotentialAttackers(owned, data) > AiUtils.strength(owned.getUnits().getUnits(), false, false))) {
dontMoveFrom.add(owned);
continue;
}
ourStrength += AiUtils.strength(owned.getUnits().getMatches(attackable), true, false);
}
// prevents 2 infantry from attacking 1 infantry
if (ourStrength > 1.37 * enemyStrength) {
// this is all we need to take it, dont go overboard, since we may be able to use the units to attack
// somewhere else
double remainingStrengthNeeded = (2.5 * enemyStrength) + 4;
for (final Territory owned : attackFrom) {
if (dontMoveFrom.contains(owned)) {
continue;
}
List<Unit> units = owned.getUnits().getMatches(attackable);
// 2) we can potentially attack another territory
if (!owned.isWater() && data.getMap().getNeighbors(owned, Matches.territoryHasEnemyLandUnits(player, data)).size() > 1) {
units = Utils.getUnitsUpToStrength(remainingStrengthNeeded, units, false);
}
remainingStrengthNeeded -= AiUtils.strength(units, true, false);
if (units.size() > 0) {
unitsAlreadyMoved.addAll(units);
moveUnits.add(units);
moveRoutes.add(data.getMap().getRoute(owned, enemy));
}
}
}
}
}
}
use of games.strategy.engine.data.PlayerID in project triplea by triplea-game.
the class WeakAi method getAmphibRoute.
private static Route getAmphibRoute(final PlayerID player, final GameData data) {
if (!isAmphibAttack(player, data)) {
return null;
}
final Territory ourCapitol = TerritoryAttachment.getFirstOwnedCapitalOrFirstUnownedCapital(player, data);
final Predicate<Territory> endMatch = o -> {
final boolean impassable = TerritoryAttachment.get(o) != null && TerritoryAttachment.get(o).getIsImpassable();
return !impassable && !o.isWater() && Utils.hasLandRouteToEnemyOwnedCapitol(o, player, data);
};
final Predicate<Territory> routeCond = Matches.territoryIsWater().and(Matches.territoryHasNoEnemyUnits(player, data));
final Route withNoEnemy = Utils.findNearest(ourCapitol, endMatch, routeCond, data);
if (withNoEnemy != null && withNoEnemy.numberOfSteps() > 0) {
return withNoEnemy;
}
// this will fail if our capitol is not next to water, c'est la vie.
final Route route = Utils.findNearest(ourCapitol, endMatch, Matches.territoryIsWater(), data);
if (route != null && route.numberOfSteps() == 0) {
return null;
}
return route;
}
use of games.strategy.engine.data.PlayerID 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.PlayerID in project triplea by triplea-game.
the class ProAi method retreatQuery.
@Override
public Territory retreatQuery(final GUID battleId, final boolean submerge, final Territory battleTerritory, final Collection<Territory> possibleTerritories, final String message) {
initializeData();
// Get battle data
final GameData data = getGameData();
final PlayerID player = getPlayerId();
final BattleDelegate delegate = DelegateFinder.battleDelegate(data);
final IBattle battle = delegate.getBattleTracker().getPendingBattle(battleId);
// If battle is null or amphibious then don't retreat
if (battle == null || battleTerritory == null || battle.isAmphibious()) {
return null;
}
// If attacker with more unit strength or strafing and isn't land battle with only air left then don't retreat
final boolean isAttacker = player.equals(battle.getAttacker());
final List<Unit> attackers = (List<Unit>) battle.getAttackingUnits();
final List<Unit> defenders = (List<Unit>) battle.getDefendingUnits();
final double strengthDifference = ProBattleUtils.estimateStrengthDifference(battleTerritory, attackers, defenders);
final boolean isStrafing = isAttacker && storedStrafingTerritories.contains(battleTerritory);
ProLogger.info(player.getName() + " checking retreat from territory " + battleTerritory + ", attackers=" + attackers.size() + ", defenders=" + defenders.size() + ", submerge=" + submerge + ", attacker=" + isAttacker + ", isStrafing=" + isStrafing);
if ((isStrafing || (isAttacker && strengthDifference > 50)) && (battleTerritory.isWater() || attackers.stream().anyMatch(Matches.unitIsLand()))) {
return null;
}
calc.setData(getGameData());
return retreatAi.retreatQuery(battleId, battleTerritory, possibleTerritories);
}
Aggregations