use of games.strategy.util.Tuple in project triplea by triplea-game.
the class AbstractEndTurnDelegate method changeUnitOwnership.
private static void changeUnitOwnership(final IDelegateBridge bridge) {
final PlayerID player = bridge.getPlayerId();
final PlayerAttachment pa = PlayerAttachment.get(player);
final Collection<PlayerID> possibleNewOwners = pa.getGiveUnitControl();
final Collection<Territory> territories = bridge.getData().getMap().getTerritories();
final CompositeChange change = new CompositeChange();
final Collection<Tuple<Territory, Collection<Unit>>> changeList = new ArrayList<>();
for (final Territory currTerritory : territories) {
final TerritoryAttachment ta = TerritoryAttachment.get(currTerritory);
// if ownership should change in this territory
if (ta != null && ta.getChangeUnitOwners() != null && !ta.getChangeUnitOwners().isEmpty()) {
final Collection<PlayerID> terrNewOwners = ta.getChangeUnitOwners();
for (final PlayerID terrNewOwner : terrNewOwners) {
if (possibleNewOwners.contains(terrNewOwner)) {
// PlayerOwnerChange
final Collection<Unit> units = currTerritory.getUnits().getMatches(Matches.unitOwnedBy(player).and(Matches.unitCanBeGivenByTerritoryTo(terrNewOwner)));
if (!units.isEmpty()) {
change.add(ChangeFactory.changeOwner(units, terrNewOwner, currTerritory));
changeList.add(Tuple.of(currTerritory, units));
}
}
}
}
}
if (!change.isEmpty() && !changeList.isEmpty()) {
if (changeList.size() == 1) {
final Tuple<Territory, Collection<Unit>> tuple = changeList.iterator().next();
bridge.getHistoryWriter().startEvent("Some Units in " + tuple.getFirst().getName() + " change ownership: " + MyFormatter.unitsToTextNoOwner(tuple.getSecond()), tuple.getSecond());
} else {
bridge.getHistoryWriter().startEvent("Units Change Ownership");
for (final Tuple<Territory, Collection<Unit>> tuple : changeList) {
bridge.getHistoryWriter().addChildToEvent("Some Units in " + tuple.getFirst().getName() + " change ownership: " + MyFormatter.unitsToTextNoOwner(tuple.getSecond()), tuple.getSecond());
}
}
bridge.addChange(change);
}
}
use of games.strategy.util.Tuple in project triplea by triplea-game.
the class AbstractEndTurnDelegate method getBlockadeProductionLoss.
// finds losses due to blockades, positive value returned.
private int getBlockadeProductionLoss(final PlayerID player, final GameData data, final IDelegateBridge bridge, final StringBuilder endTurnReport) {
final PlayerAttachment playerRules = PlayerAttachment.get(player);
if (playerRules != null && playerRules.getImmuneToBlockade()) {
return 0;
}
final GameMap map = data.getMap();
final Collection<Territory> blockable = CollectionUtils.getMatches(map.getTerritories(), Matches.territoryIsBlockadeZone());
if (blockable.isEmpty()) {
return 0;
}
final Predicate<Unit> enemyUnits = Matches.enemyUnit(player, data);
int totalLoss = 0;
final boolean rollDiceForBlockadeDamage = Properties.getConvoyBlockadesRollDiceForCost(data);
final Collection<String> transcripts = new ArrayList<>();
final HashMap<Territory, Tuple<Integer, List<Territory>>> damagePerBlockadeZone = new HashMap<>();
boolean rolledDice = false;
for (final Territory b : blockable) {
// match will check for land, convoy zones, and also contested territories
final List<Territory> viableNeighbors = CollectionUtils.getMatches(map.getNeighbors(b), Matches.isTerritoryOwnedBy(player).and(Matches.territoryCanCollectIncomeFrom(player, data)));
final int maxLoss = getProduction(viableNeighbors);
if (maxLoss <= 0) {
continue;
}
final Collection<Unit> enemies = CollectionUtils.getMatches(b.getUnits().getUnits(), enemyUnits);
if (enemies.isEmpty()) {
continue;
}
int loss = 0;
if (rollDiceForBlockadeDamage) {
int numberOfDice = 0;
for (final Unit u : enemies) {
numberOfDice += UnitAttachment.get(u.getType()).getBlockade();
}
if (numberOfDice > 0) {
// there is an issue with maps that have lots of rolls without any pause between them: they are causing the
// cypted random source
// (ie: live and pbem games) to lock up or error out
// so we need to slow them down a bit, until we come up with a better solution (like aggregating all the
// chances together, then
// getting a ton of random numbers at once instead of one at a time)
Interruptibles.sleep(100);
final String transcript = "Rolling for Convoy Blockade Damage in " + b.getName();
final int[] dice = bridge.getRandom(CONVOY_BLOCKADE_DICE_SIDES, numberOfDice, enemies.iterator().next().getOwner(), DiceType.BOMBING, transcript);
transcripts.add(transcript + ". Rolls: " + MyFormatter.asDice(dice));
rolledDice = true;
for (final int d : dice) {
// we are zero based
final int roll = d + 1;
loss += (roll <= 3 ? roll : 0);
}
}
} else {
for (final Unit u : enemies) {
loss += UnitAttachment.get(u.getType()).getBlockade();
}
}
if (loss <= 0) {
continue;
}
final int lossForBlockade = Math.min(maxLoss, loss);
damagePerBlockadeZone.put(b, Tuple.of(lossForBlockade, viableNeighbors));
totalLoss += lossForBlockade;
}
if (totalLoss <= 0 && !rolledDice) {
return 0;
}
// now we need to make sure that we didn't deal more damage than the territories are worth, in the case of having
// multiple sea zones
// touching the same land zone.
final List<Territory> blockadeZonesSorted = new ArrayList<>(damagePerBlockadeZone.keySet());
blockadeZonesSorted.sort(getSingleBlockadeThenHighestToLowestBlockadeDamage(damagePerBlockadeZone));
// we want to match highest damage to largest producer first, that is why we sort twice
final IntegerMap<Territory> totalDamageTracker = new IntegerMap<>();
for (final Territory b : blockadeZonesSorted) {
final Tuple<Integer, List<Territory>> tuple = damagePerBlockadeZone.get(b);
int damageForZone = tuple.getFirst();
final List<Territory> terrsLosingIncome = new ArrayList<>(tuple.getSecond());
terrsLosingIncome.sort(getSingleNeighborBlockadesThenHighestToLowestProduction(blockadeZonesSorted, map));
final Iterator<Territory> iter = terrsLosingIncome.iterator();
while (damageForZone > 0 && iter.hasNext()) {
final Territory t = iter.next();
final int maxProductionLessPreviousDamage = TerritoryAttachment.getProduction(t) - totalDamageTracker.getInt(t);
final int damageToTerr = Math.min(damageForZone, maxProductionLessPreviousDamage);
damageForZone -= damageToTerr;
totalDamageTracker.put(t, damageToTerr + totalDamageTracker.getInt(t));
}
}
final int realTotalLoss = Math.max(0, totalDamageTracker.totalValues());
if (rollDiceForBlockadeDamage && (realTotalLoss > 0 || (rolledDice && !transcripts.isEmpty()))) {
final String mainline = "Total Cost from Convoy Blockades: " + realTotalLoss;
bridge.getHistoryWriter().startEvent(mainline);
endTurnReport.append(mainline).append("<br />");
for (final String t : transcripts) {
bridge.getHistoryWriter().addChildToEvent(t);
endTurnReport.append("* ").append(t).append("<br />");
}
endTurnReport.append("<br />");
}
return realTotalLoss;
}
use of games.strategy.util.Tuple in project triplea by triplea-game.
the class ProScrambleAi method scrambleUnitsQuery.
HashMap<Territory, Collection<Unit>> scrambleUnitsQuery(final Territory scrambleTo, final Map<Territory, Tuple<Collection<Unit>, Collection<Unit>>> possibleScramblers) {
// Get battle data
final GameData data = ProData.getData();
final PlayerID player = ProData.getPlayer();
final BattleDelegate delegate = DelegateFinder.battleDelegate(data);
final IBattle battle = delegate.getBattleTracker().getPendingBattle(scrambleTo, false, BattleType.NORMAL);
// Check if defense already wins
final List<Unit> attackers = (List<Unit>) battle.getAttackingUnits();
final List<Unit> defenders = (List<Unit>) battle.getDefendingUnits();
final Set<Unit> bombardingUnits = new HashSet<>(battle.getBombardingUnits());
final ProBattleResult minResult = calc.calculateBattleResults(scrambleTo, attackers, defenders, bombardingUnits);
ProLogger.debug(scrambleTo + ", minTUVSwing=" + minResult.getTuvSwing() + ", minWin%=" + minResult.getWinPercentage());
if (minResult.getTuvSwing() <= 0 && minResult.getWinPercentage() < (100 - ProData.minWinPercentage)) {
return null;
}
// Check if max defense is worse
final Set<Unit> allScramblers = new HashSet<>();
final Map<Territory, List<Unit>> possibleMaxScramblerMap = new HashMap<>();
for (final Territory t : possibleScramblers.keySet()) {
final int maxCanScramble = BattleDelegate.getMaxScrambleCount(possibleScramblers.get(t).getFirst());
List<Unit> canScrambleAir = new ArrayList<>(possibleScramblers.get(t).getSecond());
if (maxCanScramble < canScrambleAir.size()) {
canScrambleAir.sort(Comparator.comparingDouble(o -> ProBattleUtils.estimateStrength(scrambleTo, Collections.singletonList(o), new ArrayList<>(), false)));
canScrambleAir = canScrambleAir.subList(0, maxCanScramble);
}
allScramblers.addAll(canScrambleAir);
possibleMaxScramblerMap.put(t, canScrambleAir);
}
defenders.addAll(allScramblers);
final ProBattleResult maxResult = calc.calculateBattleResults(scrambleTo, attackers, defenders, bombardingUnits);
ProLogger.debug(scrambleTo + ", maxTUVSwing=" + maxResult.getTuvSwing() + ", maxWin%=" + maxResult.getWinPercentage());
if (maxResult.getTuvSwing() >= minResult.getTuvSwing()) {
return null;
}
// Loop through all units and determine attack options
final Map<Unit, Set<Territory>> unitDefendOptions = new HashMap<>();
for (final Territory t : possibleMaxScramblerMap.keySet()) {
final Set<Territory> possibleTerritories = data.getMap().getNeighbors(t, ProMatches.territoryCanMoveSeaUnits(player, data, true));
possibleTerritories.add(t);
final Set<Territory> battleTerritories = new HashSet<>();
for (final Territory possibleTerritory : possibleTerritories) {
final IBattle possibleBattle = delegate.getBattleTracker().getPendingBattle(possibleTerritory, false, BattleType.NORMAL);
if (possibleBattle != null) {
battleTerritories.add(possibleTerritory);
}
}
for (final Unit u : possibleMaxScramblerMap.get(t)) {
unitDefendOptions.put(u, battleTerritories);
}
}
// Sort units by number of defend options and cost
final Map<Unit, Set<Territory>> sortedUnitDefendOptions = ProSortMoveOptionsUtils.sortUnitMoveOptions(unitDefendOptions);
// Add one scramble unit at a time and check if final result is better than min result
final List<Unit> unitsToScramble = new ArrayList<>();
ProBattleResult result = minResult;
for (final Unit u : sortedUnitDefendOptions.keySet()) {
unitsToScramble.add(u);
final List<Unit> currentDefenders = (List<Unit>) battle.getDefendingUnits();
currentDefenders.addAll(unitsToScramble);
result = calc.calculateBattleResults(scrambleTo, attackers, currentDefenders, bombardingUnits);
ProLogger.debug(scrambleTo + ", TUVSwing=" + result.getTuvSwing() + ", Win%=" + result.getWinPercentage() + ", addedUnit=" + u);
if (result.getTuvSwing() <= 0 && result.getWinPercentage() < (100 - ProData.minWinPercentage)) {
break;
}
}
if (result.getTuvSwing() >= minResult.getTuvSwing()) {
return null;
}
// Return units to scramble
final HashMap<Territory, Collection<Unit>> scrambleMap = new HashMap<>();
for (final Territory t : possibleScramblers.keySet()) {
for (final Unit u : possibleScramblers.get(t).getSecond()) {
if (unitsToScramble.contains(u)) {
if (scrambleMap.containsKey(t)) {
scrambleMap.get(t).add(u);
} else {
final Collection<Unit> units = new ArrayList<>();
units.add(u);
scrambleMap.put(t, units);
}
}
}
}
return scrambleMap;
}
use of games.strategy.util.Tuple in project triplea by triplea-game.
the class GameParser method setValues.
private ArrayList<Tuple<String, String>> setValues(final IAttachment attachment, final List<Element> values) throws GameParseException {
final ArrayList<Tuple<String, String>> options = new ArrayList<>();
for (final Element current : values) {
// decapitalize the property name for backwards compatibility
final String name = decapitalize(current.getAttribute("name"));
if (name.isEmpty()) {
throw newGameParseException("Option name with zero length");
}
final String value = current.getAttribute("value");
final String count = current.getAttribute("count");
final String itemValues = (count.length() > 0 ? count + ":" : "") + value;
try {
attachment.getProperty(name).orElseThrow(() -> newGameParseException(String.format("Missing property definition for option '%s' in attachment '%s'", name, attachment.getName()))).setValue(itemValues);
} catch (final GameParseException e) {
throw e;
} catch (final Exception e) {
throw newGameParseException("Unexpected Exception while setting values for attachment" + attachment, e);
}
options.add(Tuple.of(name, itemValues));
}
return options;
}
use of games.strategy.util.Tuple in project triplea by triplea-game.
the class TabbedProductionPanel method getDefaultRuleLists.
private List<Tuple<String, List<Rule>>> getDefaultRuleLists() {
final List<Tuple<String, List<Rule>>> ruleLists = new ArrayList<>();
final ArrayList<Rule> allRules = new ArrayList<>();
final ArrayList<Rule> landRules = new ArrayList<>();
final ArrayList<Rule> airRules = new ArrayList<>();
final ArrayList<Rule> seaRules = new ArrayList<>();
final ArrayList<Rule> constructRules = new ArrayList<>();
final ArrayList<Rule> upgradeConsumesRules = new ArrayList<>();
final ArrayList<Rule> resourceRules = new ArrayList<>();
for (final Rule rule : rules) {
allRules.add(rule);
final NamedAttachable resourceOrUnit = rule.getProductionRule().getResults().keySet().iterator().next();
if (resourceOrUnit instanceof UnitType) {
final UnitType type = (UnitType) resourceOrUnit;
final UnitAttachment attach = UnitAttachment.get(type);
if (attach.getConsumesUnits() != null && attach.getConsumesUnits().totalValues() >= 1) {
upgradeConsumesRules.add(rule);
}
// anywhere (placed without needing a factory).
if (attach.getIsConstruction()) {
constructRules.add(rule);
} else if (attach.getIsSea()) {
seaRules.add(rule);
} else if (attach.getIsAir()) {
airRules.add(rule);
} else {
landRules.add(rule);
}
} else if (resourceOrUnit instanceof Resource) {
resourceRules.add(rule);
}
}
ruleLists.add(Tuple.of("All", allRules));
ruleLists.add(Tuple.of("Land", landRules));
ruleLists.add(Tuple.of("Air", airRules));
ruleLists.add(Tuple.of("Sea", seaRules));
ruleLists.add(Tuple.of("Construction", constructRules));
ruleLists.add(Tuple.of("Upgrades/Consumes", upgradeConsumesRules));
ruleLists.add(Tuple.of("Resources", resourceRules));
return ruleLists;
}
Aggregations