package games.strategy.triplea.ai.proAI.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import games.strategy.debug.ClientLogger;
import games.strategy.engine.data.GameData;
import games.strategy.engine.data.GameSequence;
import games.strategy.engine.data.GameStep;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.RelationshipTracker;
import games.strategy.engine.data.RelationshipType;
import games.strategy.engine.data.Territory;
import games.strategy.engine.data.Unit;
import games.strategy.triplea.Properties;
import games.strategy.triplea.ai.proAI.ProData;
import games.strategy.triplea.attachments.TerritoryAttachment;
import games.strategy.triplea.delegate.Matches;
import games.strategy.triplea.ui.AbstractUIContext;
import games.strategy.util.Match;
import games.strategy.util.ThreadUtil;
/**
* Pro AI utilities (these are very general and maybe should be moved into delegate or engine).
*/
public class ProUtils {
public static Map<Unit, Territory> createUnitTerritoryMap() {
final Map<Unit, Territory> unitTerritoryMap = new HashMap<>();
for (final Territory t : ProData.getData().getMap().getTerritories()) {
for (final Unit u : t.getUnits().getUnits()) {
unitTerritoryMap.put(u, t);
}
}
return unitTerritoryMap;
}
public static List<PlayerID> getOtherPlayersInTurnOrder(final PlayerID player) {
final GameData data = ProData.getData();
final List<PlayerID> players = new ArrayList<>();
final GameSequence sequence = data.getSequence();
final int startIndex = sequence.getStepIndex();
for (int i = 0; i < sequence.size(); i++) {
int currentIndex = startIndex + i;
if (currentIndex >= sequence.size()) {
currentIndex -= sequence.size();
}
final GameStep step = sequence.getStep(currentIndex);
final PlayerID stepPlayer = step.getPlayerID();
if (step.getName().endsWith("CombatMove") && stepPlayer != null && !stepPlayer.equals(player)
&& !players.contains(stepPlayer)) {
players.add(step.getPlayerID());
}
}
return players;
}
public static List<PlayerID> getAlliedPlayersInTurnOrder(final PlayerID player) {
final GameData data = ProData.getData();
final List<PlayerID> players = getOtherPlayersInTurnOrder(player);
for (final Iterator<PlayerID> it = players.iterator(); it.hasNext();) {
final PlayerID currentPlayer = it.next();
if (!data.getRelationshipTracker().isAllied(player, currentPlayer)) {
it.remove();
}
}
return players;
}
public static List<PlayerID> getEnemyPlayersInTurnOrder(final PlayerID player) {
final GameData data = ProData.getData();
final List<PlayerID> players = getOtherPlayersInTurnOrder(player);
for (final Iterator<PlayerID> it = players.iterator(); it.hasNext();) {
final PlayerID currentPlayer = it.next();
if (data.getRelationshipTracker().isAllied(player, currentPlayer)) {
it.remove();
}
}
return players;
}
public static boolean isPlayersTurnFirst(final List<PlayerID> playersInOrder, final PlayerID player1,
final PlayerID player2) {
for (final PlayerID p : playersInOrder) {
if (p.equals(player1)) {
return true;
} else if (p.equals(player2)) {
return false;
}
}
return true;
}
public static List<PlayerID> getEnemyPlayers(final PlayerID player) {
final GameData data = ProData.getData();
final List<PlayerID> enemyPlayers = new ArrayList<>();
for (final PlayerID players : data.getPlayerList().getPlayers()) {
if (!data.getRelationshipTracker().isAllied(player, players)) {
enemyPlayers.add(players);
}
}
return enemyPlayers;
}
public static List<PlayerID> getAlliedPlayers(final PlayerID player) {
final GameData data = ProData.getData();
final List<PlayerID> alliedPlayers = new ArrayList<>();
for (final PlayerID players : data.getPlayerList().getPlayers()) {
if (data.getRelationshipTracker().isAllied(player, players)) {
alliedPlayers.add(players);
}
}
return alliedPlayers;
}
public static List<PlayerID> getPotentialEnemyPlayers(final PlayerID player) {
final GameData data = ProData.getData();
final List<PlayerID> otherPlayers = data.getPlayerList().getPlayers();
for (final Iterator<PlayerID> it = otherPlayers.iterator(); it.hasNext();) {
final PlayerID otherPlayer = it.next();
final RelationshipType relation = data.getRelationshipTracker().getRelationshipType(player, otherPlayer);
if (Matches.RelationshipTypeIsAllied.match(relation) || isNeutralPlayer(otherPlayer)) {
it.remove();
}
}
return otherPlayers;
}
public static double getPlayerProduction(final PlayerID player, final GameData data) {
int rVal = 0;
for (final Territory place : data.getMap().getTerritories()) {
// Match will Check if terr is a Land Convoy Route and check ownership of neighboring Sea Zone, or if contested
if (place.getOwner().equals(player) && Matches.territoryCanCollectIncomeFrom(player, data).match(place)) {
rVal += TerritoryAttachment.getProduction(place);
}
}
rVal *= Properties.getPU_Multiplier(data);
return rVal;
}
public static List<Territory> getLiveEnemyCapitals(final GameData data, final PlayerID player) {
final List<Territory> enemyCapitals = new ArrayList<>();
final List<PlayerID> ePlayers = getEnemyPlayers(player);
for (final PlayerID otherPlayer : ePlayers) {
enemyCapitals.addAll(TerritoryAttachment.getAllCurrentlyOwnedCapitals(otherPlayer, data));
}
enemyCapitals.retainAll(Match.getMatches(enemyCapitals, Matches.TerritoryIsNotImpassableToLandUnits(player, data)));
enemyCapitals
.retainAll(Match.getMatches(enemyCapitals, Matches.isTerritoryOwnedBy(getPotentialEnemyPlayers(player))));
return enemyCapitals;
}
public static List<Territory> getLiveAlliedCapitals(final GameData data, final PlayerID player) {
final List<Territory> capitals = new ArrayList<>();
final List<PlayerID> players = getAlliedPlayers(player);
for (final PlayerID alliedPlayer : players) {
capitals.addAll(TerritoryAttachment.getAllCurrentlyOwnedCapitals(alliedPlayer, data));
}
capitals.retainAll(Match.getMatches(capitals, Matches.TerritoryIsNotImpassableToLandUnits(player, data)));
capitals.retainAll(Match.getMatches(capitals, Matches.isTerritoryAllied(player, data)));
return capitals;
}
public static int getClosestEnemyLandTerritoryDistance(final GameData data, final PlayerID player,
final Territory t) {
final Set<Territory> landTerritories =
data.getMap().getNeighbors(t, 9, ProMatches.territoryCanPotentiallyMoveLandUnits(player, data, true));
final List<Territory> enemyLandTerritories =
Match.getMatches(landTerritories, Matches.isTerritoryOwnedBy(getPotentialEnemyPlayers(player)));
int minDistance = 10;
for (final Territory enemyLandTerritory : enemyLandTerritories) {
final int distance = data.getMap().getDistance(t, enemyLandTerritory,
ProMatches.territoryCanPotentiallyMoveLandUnits(player, data, true));
if (distance < minDistance) {
minDistance = distance;
}
}
if (minDistance < 10) {
return minDistance;
} else {
return -1;
}
}
public static int getClosestEnemyOrNeutralLandTerritoryDistance(final GameData data, final PlayerID player,
final Territory t, final Map<Territory, Double> territoryValueMap) {
final Set<Territory> landTerritories =
data.getMap().getNeighbors(t, 9, ProMatches.territoryCanPotentiallyMoveLandUnits(player, data, true));
final List<Territory> enemyLandTerritories =
Match.getMatches(landTerritories, Matches.isTerritoryOwnedBy(getEnemyPlayers(player)));
int minDistance = 10;
for (final Territory enemyLandTerritory : enemyLandTerritories) {
if (territoryValueMap.get(enemyLandTerritory) <= 0) {
continue;
}
int distance = data.getMap().getDistance(t, enemyLandTerritory,
ProMatches.territoryCanPotentiallyMoveLandUnits(player, data, true));
if (enemyLandTerritory.getOwner().isNull()) {
distance++;
}
if (distance < minDistance) {
minDistance = distance;
}
}
if (minDistance < 10) {
return minDistance;
} else {
return -1;
}
}
public static int getClosestEnemyLandTerritoryDistanceOverWater(final GameData data, final PlayerID player,
final Territory t) {
final Set<Territory> neighborTerritories = data.getMap().getNeighbors(t, 9);
final List<Territory> enemyOrAdjacentLandTerritories =
Match.getMatches(neighborTerritories, ProMatches.territoryIsOrAdjacentToEnemyNotNeutralLand(player, data));
int minDistance = 10;
for (final Territory enemyLandTerritory : enemyOrAdjacentLandTerritories) {
final int distance =
data.getMap().getDistance_IgnoreEndForCondition(t, enemyLandTerritory, Matches.TerritoryIsWater);
if (distance > 0 && distance < minDistance) {
minDistance = distance;
}
}
if (minDistance < 10) {
return minDistance;
} else {
return -1;
}
}
/**
* Returns whether the game is a FFA based on whether any of the player's enemies
* are enemies of each other.
*/
public static boolean isFFA(final GameData data, final PlayerID player) {
final RelationshipTracker relationshipTracker = data.getRelationshipTracker();
final Set<PlayerID> enemies = relationshipTracker.getEnemies(player);
for (final PlayerID enemy : enemies) {
if (relationshipTracker.isAtWarWithAnyOfThesePlayers(enemy, enemies)) {
return true;
}
}
return false;
}
public static boolean isNeutralPlayer(final PlayerID player) {
final GameData data = ProData.getData();
for (final GameStep gameStep : data.getSequence()) {
if (player.equals(gameStep.getPlayerID())) {
return false;
}
}
return true;
}
/**
* Pause the game to allow the human player to see what is going on.
*/
public static void pause() {
try {
ThreadUtil.sleep(AbstractUIContext.getAIPauseDuration());
} catch (final Exception e) {
ClientLogger.logQuietly(e);
}
}
}