use of games.strategy.triplea.attachments.PlayerAttachment 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.triplea.attachments.PlayerAttachment in project triplea by triplea-game.
the class TripleAPlayer method selectKamikazeSuicideAttacks.
@Override
public HashMap<Territory, HashMap<Unit, IntegerMap<Resource>>> selectKamikazeSuicideAttacks(final HashMap<Territory, Collection<Unit>> possibleUnitsToAttack) {
final PlayerID id = getPlayerId();
final PlayerAttachment pa = PlayerAttachment.get(id);
if (pa == null) {
return null;
}
final IntegerMap<Resource> resourcesAndAttackValues = pa.getSuicideAttackResources();
if (resourcesAndAttackValues.size() <= 0) {
return null;
}
final IntegerMap<Resource> playerResourceCollection = id.getResources().getResourcesCopy();
final IntegerMap<Resource> attackTokens = new IntegerMap<>();
for (final Resource possible : resourcesAndAttackValues.keySet()) {
final int amount = playerResourceCollection.getInt(possible);
if (amount > 0) {
attackTokens.put(possible, amount);
}
}
if (attackTokens.size() <= 0) {
return null;
}
final HashMap<Territory, HashMap<Unit, IntegerMap<Resource>>> kamikazeSuicideAttacks = new HashMap<>();
for (final Entry<Resource, Integer> entry : attackTokens.entrySet()) {
final Resource resource = entry.getKey();
final int max = entry.getValue();
final Map<Territory, IntegerMap<Unit>> selection = ui.selectKamikazeSuicideAttacks(possibleUnitsToAttack, resource, max);
for (final Entry<Territory, IntegerMap<Unit>> selectionEntry : selection.entrySet()) {
final Territory territory = selectionEntry.getKey();
final HashMap<Unit, IntegerMap<Resource>> currentTerr = kamikazeSuicideAttacks.getOrDefault(territory, new HashMap<>());
for (final Entry<Unit, Integer> unitEntry : selectionEntry.getValue().entrySet()) {
final Unit unit = unitEntry.getKey();
final IntegerMap<Resource> currentUnit = currentTerr.getOrDefault(unit, new IntegerMap<>());
currentUnit.add(resource, unitEntry.getValue());
currentTerr.put(unit, currentUnit);
}
kamikazeSuicideAttacks.put(territory, currentTerr);
}
}
return kamikazeSuicideAttacks;
}
use of games.strategy.triplea.attachments.PlayerAttachment in project triplea by triplea-game.
the class AbstractAi method selectKamikazeSuicideAttacks.
@Override
public HashMap<Territory, HashMap<Unit, IntegerMap<Resource>>> selectKamikazeSuicideAttacks(final HashMap<Territory, Collection<Unit>> possibleUnitsToAttack) {
final PlayerID id = getPlayerId();
// we are going to just assign random attacks to each unit randomly, til we run out of tokens to attack with.
final PlayerAttachment pa = PlayerAttachment.get(id);
if (pa == null) {
return null;
}
final IntegerMap<Resource> resourcesAndAttackValues = pa.getSuicideAttackResources();
if (resourcesAndAttackValues.size() <= 0) {
return null;
}
final IntegerMap<Resource> playerResourceCollection = id.getResources().getResourcesCopy();
final IntegerMap<Resource> attackTokens = new IntegerMap<>();
for (final Resource possible : resourcesAndAttackValues.keySet()) {
final int amount = playerResourceCollection.getInt(possible);
if (amount > 0) {
attackTokens.put(possible, amount);
}
}
if (attackTokens.size() <= 0) {
return null;
}
final HashMap<Territory, HashMap<Unit, IntegerMap<Resource>>> kamikazeSuicideAttacks = new HashMap<>();
for (final Entry<Territory, Collection<Unit>> entry : possibleUnitsToAttack.entrySet()) {
if (attackTokens.size() <= 0) {
continue;
}
final Territory t = entry.getKey();
final List<Unit> targets = new ArrayList<>(entry.getValue());
Collections.shuffle(targets);
for (final Unit u : targets) {
if (attackTokens.size() <= 0) {
continue;
}
final IntegerMap<Resource> resourceMap = new IntegerMap<>();
final Resource resource = attackTokens.keySet().iterator().next();
final int num = Math.min(attackTokens.getInt(resource), (UnitAttachment.get(u.getType()).getHitPoints() * (Math.random() < .3 ? 1 : (Math.random() < .5 ? 2 : 3))));
resourceMap.put(resource, num);
final HashMap<Unit, IntegerMap<Resource>> attMap = kamikazeSuicideAttacks.getOrDefault(t, new HashMap<>());
attMap.put(u, resourceMap);
kamikazeSuicideAttacks.put(t, attMap);
attackTokens.add(resource, -num);
if (attackTokens.getInt(resource) <= 0) {
attackTokens.removeKey(resource);
}
}
}
return kamikazeSuicideAttacks;
}
Aggregations