use of games.strategy.util.IntegerMap in project triplea by triplea-game.
the class DiceRoll method getUnitPowerAndRollsForNormalBattles.
/**
* @param unitsGettingPowerFor
* should be sorted from weakest to strongest, before the method is called, for the actual battle.
*/
protected static Map<Unit, Tuple<Integer, Integer>> getUnitPowerAndRollsForNormalBattles(final List<Unit> unitsGettingPowerFor, final List<Unit> allEnemyUnitsAliveOrWaitingToDie, final boolean defending, final boolean bombing, final GameData data, final Territory location, final Collection<TerritoryEffect> territoryEffects, final boolean isAmphibiousBattle, final Collection<Unit> amphibiousLandAttackers, final Map<Unit, IntegerMap<Unit>> unitSupportPowerMap, final Map<Unit, IntegerMap<Unit>> unitSupportRollsMap) {
final Map<Unit, Tuple<Integer, Integer>> unitPowerAndRolls = new HashMap<>();
if (unitsGettingPowerFor == null || unitsGettingPowerFor.isEmpty()) {
return unitPowerAndRolls;
}
// get all supports, friendly and enemy
final Set<List<UnitSupportAttachment>> supportRulesFriendly = new HashSet<>();
final IntegerMap<UnitSupportAttachment> supportLeftFriendly = new IntegerMap<>();
final Map<UnitSupportAttachment, LinkedIntegerMap<Unit>> supportUnitsLeftFriendly = new HashMap<>();
getSupport(unitsGettingPowerFor, supportRulesFriendly, supportLeftFriendly, supportUnitsLeftFriendly, data, defending, true);
final Set<List<UnitSupportAttachment>> supportRulesEnemy = new HashSet<>();
final IntegerMap<UnitSupportAttachment> supportLeftEnemy = new IntegerMap<>();
final Map<UnitSupportAttachment, LinkedIntegerMap<Unit>> supportUnitsLeftEnemy = new HashMap<>();
getSupport(allEnemyUnitsAliveOrWaitingToDie, supportRulesEnemy, supportLeftEnemy, supportUnitsLeftEnemy, data, !defending, false);
// copy for rolls
final IntegerMap<UnitSupportAttachment> supportLeftFriendlyRolls = new IntegerMap<>(supportLeftFriendly);
final IntegerMap<UnitSupportAttachment> supportLeftEnemyRolls = new IntegerMap<>(supportLeftEnemy);
final Map<UnitSupportAttachment, LinkedIntegerMap<Unit>> supportUnitsLeftFriendlyRolls = new HashMap<>();
for (final UnitSupportAttachment usa : supportUnitsLeftFriendly.keySet()) {
supportUnitsLeftFriendlyRolls.put(usa, new LinkedIntegerMap<>(supportUnitsLeftFriendly.get(usa)));
}
final Map<UnitSupportAttachment, LinkedIntegerMap<Unit>> supportUnitsLeftEnemyRolls = new HashMap<>();
for (final UnitSupportAttachment usa : supportUnitsLeftEnemy.keySet()) {
supportUnitsLeftEnemyRolls.put(usa, new LinkedIntegerMap<>(supportUnitsLeftEnemy.get(usa)));
}
final int diceSides = data.getDiceSides();
for (final Unit current : unitsGettingPowerFor) {
// find our initial strength
int strength;
final UnitAttachment ua = UnitAttachment.get(current.getType());
if (defending) {
strength = ua.getDefense(current.getOwner());
if (isFirstTurnLimitedRoll(current.getOwner(), data)) {
strength = Math.min(1, strength);
} else {
strength += getSupport(current, supportRulesFriendly, supportLeftFriendly, supportUnitsLeftFriendly, unitSupportPowerMap, true, false);
}
strength += getSupport(current, supportRulesEnemy, supportLeftEnemy, supportUnitsLeftEnemy, unitSupportPowerMap, true, false);
} else {
strength = ua.getAttack(current.getOwner());
if (ua.getIsMarine() != 0 && isAmphibiousBattle) {
if (amphibiousLandAttackers.contains(current)) {
strength += ua.getIsMarine();
}
}
if (ua.getIsSea() && isAmphibiousBattle && Matches.territoryIsLand().test(location)) {
// change the strength to be bombard, not attack/defense, because this is a
strength = ua.getBombard();
// bombarding naval unit
}
strength += getSupport(current, supportRulesFriendly, supportLeftFriendly, supportUnitsLeftFriendly, unitSupportPowerMap, true, false);
strength += getSupport(current, supportRulesEnemy, supportLeftEnemy, supportUnitsLeftEnemy, unitSupportPowerMap, true, false);
}
strength += TerritoryEffectHelper.getTerritoryCombatBonus(current.getType(), territoryEffects, defending);
strength = Math.min(Math.max(strength, 0), diceSides);
// now determine our rolls
int rolls;
if (!bombing && strength == 0) {
rolls = 0;
} else {
if (defending) {
rolls = ua.getDefenseRolls(current.getOwner());
} else {
rolls = ua.getAttackRolls(current.getOwner());
}
rolls += getSupport(current, supportRulesFriendly, supportLeftFriendlyRolls, supportUnitsLeftFriendlyRolls, unitSupportRollsMap, false, true);
rolls += getSupport(current, supportRulesEnemy, supportLeftEnemyRolls, supportUnitsLeftEnemyRolls, unitSupportRollsMap, false, true);
rolls = Math.max(0, rolls);
if (rolls == 0) {
strength = 0;
}
}
unitPowerAndRolls.put(current, Tuple.of(strength, rolls));
}
return unitPowerAndRolls;
}
use of games.strategy.util.IntegerMap in project triplea by triplea-game.
the class RulesAttachment method checkUnitExclusions.
/**
* Checks for the collection of territories to see if they have units owned by the exclType alliance.
* It doesn't yet threshold the data
*/
private boolean checkUnitExclusions(final Collection<Territory> territories, final String exclType, final int numberNeeded, final List<PlayerID> players, final GameData data) {
boolean useSpecific = false;
if (getUnitPresence() != null && !getUnitPresence().keySet().isEmpty()) {
useSpecific = true;
}
// Go through the owned territories and see if there are any units owned by allied/enemy based on exclType
boolean satisfied = false;
int numberMet = 0;
for (final Territory terr : territories) {
// get all the units in the territory
final Collection<Unit> allUnits = new ArrayList<>(terr.getUnits().getUnits());
if (exclType.equals("allied")) {
// any allied units in the territory. (does not include owned units)
allUnits.removeAll(CollectionUtils.getMatches(allUnits, Matches.unitIsOwnedByOfAnyOfThesePlayers(players)));
allUnits.retainAll(CollectionUtils.getMatches(allUnits, Matches.alliedUnitOfAnyOfThesePlayers(players, data)));
} else if (exclType.equals("direct")) {
allUnits.removeAll(CollectionUtils.getMatches(allUnits, Matches.unitIsOwnedByOfAnyOfThesePlayers(players).negate()));
} else if (exclType.equals("enemy")) {
// any enemy units in the territory
allUnits.retainAll(CollectionUtils.getMatches(allUnits, Matches.enemyUnitOfAnyOfThesePlayers(players, data)));
} else if (exclType.equals("enemy_surface")) {
// any enemy units (not trn/sub) in the territory
allUnits.retainAll(CollectionUtils.getMatches(allUnits, Matches.enemyUnitOfAnyOfThesePlayers(players, data).and(Matches.unitIsNotSub()).and(Matches.unitIsNotTransportButCouldBeCombatTransport())));
} else {
return false;
}
if (allUnits.size() == 0) {
numberMet += 1;
if (numberMet >= numberNeeded) {
satisfied = true;
if (!getCountEach()) {
break;
}
}
} else if (useSpecific) {
final IntegerMap<String> unitComboMap = getUnitPresence();
final Set<String> unitCombos = unitComboMap.keySet();
boolean hasLess = false;
for (final String uc : unitCombos) {
final int unitsMax = unitComboMap.getInt(uc);
if (uc == null || uc.equals("ANY") || uc.equals("any")) {
hasLess = allUnits.size() <= unitsMax;
} else {
final Set<UnitType> typesAllowed = data.getUnitTypeList().getUnitTypes(uc.split(":"));
hasLess = CollectionUtils.getMatches(allUnits, Matches.unitIsOfTypes(typesAllowed)).size() <= unitsMax;
}
if (!hasLess) {
break;
}
}
if (hasLess) {
numberMet += 1;
if (numberMet >= numberNeeded) {
satisfied = true;
if (!getCountEach()) {
break;
}
}
}
}
}
if (getCountEach()) {
m_eachMultiple = numberMet;
}
return satisfied;
}
use of games.strategy.util.IntegerMap in project triplea by triplea-game.
the class AbstractBattle method findPlayerWithMostUnits.
static PlayerID findPlayerWithMostUnits(final Collection<Unit> units) {
final IntegerMap<PlayerID> playerUnitCount = new IntegerMap<>();
for (final Unit unit : units) {
playerUnitCount.add(unit.getOwner(), 1);
}
int max = -1;
PlayerID player = null;
for (final PlayerID current : playerUnitCount.keySet()) {
final int count = playerUnitCount.getInt(current);
if (count > max) {
max = count;
player = current;
}
}
return player;
}
use of games.strategy.util.IntegerMap 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.IntegerMap in project triplea by triplea-game.
the class PacificTest method testCanMoveNavalBase.
@Test
public void testCanMoveNavalBase() {
bridge.setStepName("americanNonCombatMove");
final Route route = new Route();
route.setStart(sz5);
route.add(sz7);
route.add(sz8);
route.add(sz20);
final IntegerMap<UnitType> map = new IntegerMap<>();
map.put(fighter, 1);
final String results = delegate.move(GameDataTestUtil.getUnits(map, route.getStart()), route);
assertValid(results);
}
Aggregations