Search in sources :

Example 41 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.

the class ProTerritoryManager method findScrambleOptions.

private static void findScrambleOptions(final PlayerID player, final Map<Territory, ProTerritory> moveMap) {
    final GameData data = ProData.getData();
    if (!Properties.getScrambleRulesInEffect(data)) {
        return;
    }
    // Find scramble properties
    final boolean fromIslandOnly = Properties.getScrambleFromIslandOnly(data);
    final boolean toSeaOnly = Properties.getScrambleToSeaOnly(data);
    final int maxScrambleDistance = StreamSupport.stream(data.getUnitTypeList().spliterator(), false).map(UnitAttachment::get).filter(UnitAttachment::getCanScramble).mapToInt(UnitAttachment::getMaxScrambleDistance).max().orElse(0);
    final Predicate<Unit> airbasesCanScramble = Matches.unitIsEnemyOf(data, player).and(Matches.unitIsAirBase()).and(Matches.unitIsNotDisabled()).and(Matches.unitIsBeingTransported().negate());
    final Predicate<Territory> canScramble = PredicateBuilder.of(Matches.territoryIsWater().or(Matches.isTerritoryEnemy(player, data))).and(Matches.territoryHasUnitsThatMatch(Matches.unitCanScramble().and(Matches.unitIsEnemyOf(data, player)).and(Matches.unitIsNotDisabled()))).and(Matches.territoryHasUnitsThatMatch(airbasesCanScramble)).andIf(fromIslandOnly, Matches.territoryIsIsland()).build();
    // Find potential territories to scramble from
    final HashMap<Territory, HashSet<Territory>> scrambleTerrs = new HashMap<>();
    for (final Territory t : moveMap.keySet()) {
        if (t.isWater() || !toSeaOnly) {
            final HashSet<Territory> canScrambleFrom = new HashSet<>(CollectionUtils.getMatches(data.getMap().getNeighbors(t, maxScrambleDistance), canScramble));
            if (!canScrambleFrom.isEmpty()) {
                scrambleTerrs.put(t, canScrambleFrom);
            }
        }
    }
    if (scrambleTerrs.isEmpty()) {
        return;
    }
    // Find potential max units that can be scrambled to each territory
    for (final Territory to : scrambleTerrs.keySet()) {
        for (final Territory from : scrambleTerrs.get(to)) {
            // Find potential scramble units from territory
            final Collection<Unit> airbases = from.getUnits().getMatches(airbasesCanScramble);
            final int maxCanScramble = getMaxScrambleCount(airbases);
            final Route toBattleRoute = data.getMap().getRoute_IgnoreEnd(from, to, Matches.territoryIsNotImpassable());
            List<Unit> canScrambleAir = from.getUnits().getMatches(Matches.unitIsEnemyOf(data, player).and(Matches.unitCanScramble()).and(Matches.unitIsNotDisabled()).and(Matches.unitWasScrambled().negate()).and(Matches.unitCanScrambleOnRouteDistance(toBattleRoute)));
            // Add max scramble units
            if (maxCanScramble > 0 && !canScrambleAir.isEmpty()) {
                if (maxCanScramble < canScrambleAir.size()) {
                    canScrambleAir.sort(Comparator.comparingDouble(o -> ProBattleUtils.estimateStrength(to, Collections.singletonList(o), new ArrayList<>(), false)));
                    canScrambleAir = canScrambleAir.subList(0, maxCanScramble);
                }
                moveMap.get(to).getMaxScrambleUnits().addAll(canScrambleAir);
            }
        }
    }
}
Also used : ProUtils(games.strategy.triplea.ai.pro.util.ProUtils) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) HashMap(java.util.HashMap) ProBattleUtils(games.strategy.triplea.ai.pro.util.ProBattleUtils) PredicateBuilder(games.strategy.util.PredicateBuilder) Properties(games.strategy.triplea.Properties) ProTransportUtils(games.strategy.triplea.ai.pro.util.ProTransportUtils) ArrayList(java.util.ArrayList) ProLogger(games.strategy.triplea.ai.pro.logging.ProLogger) HashSet(java.util.HashSet) Route(games.strategy.engine.data.Route) TransportTracker(games.strategy.triplea.delegate.TransportTracker) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) MoveValidator(games.strategy.triplea.delegate.MoveValidator) Map(java.util.Map) StreamSupport(java.util.stream.StreamSupport) TripleAUnit(games.strategy.triplea.TripleAUnit) CollectionUtils(games.strategy.util.CollectionUtils) Unit(games.strategy.engine.data.Unit) Predicate(java.util.function.Predicate) Collection(java.util.Collection) TerritoryEffectHelper(games.strategy.triplea.delegate.TerritoryEffectHelper) Set(java.util.Set) Territory(games.strategy.engine.data.Territory) ProData(games.strategy.triplea.ai.pro.ProData) GameData(games.strategy.engine.data.GameData) List(java.util.List) PlayerID(games.strategy.engine.data.PlayerID) ProMatches(games.strategy.triplea.ai.pro.util.ProMatches) Matches(games.strategy.triplea.delegate.Matches) ProOddsCalculator(games.strategy.triplea.ai.pro.util.ProOddsCalculator) Comparator(java.util.Comparator) Collections(java.util.Collections) Territory(games.strategy.engine.data.Territory) GameData(games.strategy.engine.data.GameData) HashMap(java.util.HashMap) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) Route(games.strategy.engine.data.Route) HashSet(java.util.HashSet)

Example 42 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.

the class ProTerritoryManager method getMaxScrambleCount.

private static int getMaxScrambleCount(final Collection<Unit> airbases) {
    if (airbases.isEmpty() || !airbases.stream().allMatch(Matches.unitIsAirBase().and(Matches.unitIsNotDisabled()))) {
        throw new IllegalStateException("All units must be viable airbases");
    }
    // find how many is the max this territory can scramble
    int maxScrambled = 0;
    for (final Unit base : airbases) {
        final UnitAttachment ua = UnitAttachment.get(base.getType());
        final int baseMax = ua.getMaxScrambleCount();
        if (baseMax == -1) {
            return Integer.MAX_VALUE;
        }
        maxScrambled += baseMax;
    }
    return maxScrambled;
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Example 43 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.

the class DiceRoll method rollDiceNormal.

/**
 * Roll dice for units per normal rules.
 */
private static DiceRoll rollDiceNormal(final List<Unit> unitsList, final boolean defending, final PlayerID player, final IDelegateBridge bridge, final IBattle battle, final String annotation, final Collection<TerritoryEffect> territoryEffects, final List<Unit> allEnemyUnitsAliveOrWaitingToDie) {
    final List<Unit> units = new ArrayList<>(unitsList);
    {
        final Set<Unit> duplicatesCheckSet = new HashSet<>(unitsList);
        if (units.size() != duplicatesCheckSet.size()) {
            throw new IllegalStateException("Duplicate Units Detected: Original List:" + units + "  HashSet:" + duplicatesCheckSet);
        }
    }
    final GameData data = bridge.getData();
    sortByStrength(units, defending);
    final Territory location = battle.getTerritory();
    final boolean isAmphibiousBattle = battle.isAmphibious();
    final Collection<Unit> amphibiousLandAttackers = battle.getAmphibiousLandAttackers();
    final Map<Unit, Tuple<Integer, Integer>> unitPowerAndRollsMap = DiceRoll.getUnitPowerAndRollsForNormalBattles(units, allEnemyUnitsAliveOrWaitingToDie, defending, false, data, location, territoryEffects, isAmphibiousBattle, amphibiousLandAttackers);
    final Tuple<Integer, Integer> totalPowerAndRolls = getTotalPowerAndRolls(unitPowerAndRollsMap, data);
    final int totalPower = totalPowerAndRolls.getFirst();
    final int rollCount = totalPowerAndRolls.getSecond();
    if (rollCount == 0) {
        return new DiceRoll(new ArrayList<>(), 0, 0);
    }
    final int[] random = bridge.getRandom(data.getDiceSides(), rollCount, player, DiceType.COMBAT, annotation);
    final boolean lhtrBombers = Properties.getLhtrHeavyBombers(data);
    final List<Die> dice = new ArrayList<>();
    int hitCount = 0;
    int diceIndex = 0;
    for (final Unit current : units) {
        final UnitAttachment ua = UnitAttachment.get(current.getType());
        final Tuple<Integer, Integer> powerAndRolls = unitPowerAndRollsMap.get(current);
        final int strength = powerAndRolls.getFirst();
        final int rolls = powerAndRolls.getSecond();
        // lhtr heavy bombers take best of n dice for both attack and defense
        if (rolls <= 0 || strength <= 0) {
            continue;
        }
        if (rolls > 1 && (lhtrBombers || ua.getChooseBestRoll())) {
            int smallestDieIndex = 0;
            int smallestDie = data.getDiceSides();
            for (int i = 0; i < rolls; i++) {
                if (random[diceIndex + i] < smallestDie) {
                    smallestDie = random[diceIndex + i];
                    smallestDieIndex = i;
                }
            }
            // zero based
            final boolean hit = strength > random[diceIndex + smallestDieIndex];
            dice.add(new Die(random[diceIndex + smallestDieIndex], strength, hit ? DieType.HIT : DieType.MISS));
            for (int i = 0; i < rolls; i++) {
                if (i != smallestDieIndex) {
                    dice.add(new Die(random[diceIndex + i], strength, DieType.IGNORED));
                }
            }
            if (hit) {
                hitCount++;
            }
            diceIndex += rolls;
        } else {
            for (int i = 0; i < rolls; i++) {
                // zero based
                final boolean hit = strength > random[diceIndex];
                dice.add(new Die(random[diceIndex], strength, hit ? DieType.HIT : DieType.MISS));
                if (hit) {
                    hitCount++;
                }
                diceIndex++;
            }
        }
    }
    final double expectedHits = ((double) totalPower) / data.getDiceSides();
    final DiceRoll diceRoll = new DiceRoll(dice, hitCount, expectedHits);
    bridge.getHistoryWriter().addChildToEvent(annotation + " : " + MyFormatter.asDice(random), diceRoll);
    return diceRoll;
}
Also used : Territory(games.strategy.engine.data.Territory) HashSet(java.util.HashSet) Set(java.util.Set) GameData(games.strategy.engine.data.GameData) ArrayList(java.util.ArrayList) Unit(games.strategy.engine.data.Unit) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) Tuple(games.strategy.util.Tuple)

Example 44 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment in project triplea by triplea-game.

the class DiceRoll method getAAattackAndMaxDiceSides.

/**
 * Returns a Tuple with 2 values, the first is the max attack, the second is the max dice sides for the AA unit with
 * that attack value.
 */
public static Tuple<Integer, Integer> getAAattackAndMaxDiceSides(final Collection<Unit> defendingEnemyAa, final GameData data, final boolean defending) {
    int highestAttack = 0;
    final int diceSize = data.getDiceSides();
    int chosenDiceSize = diceSize;
    for (final Unit u : defendingEnemyAa) {
        final UnitAttachment ua = UnitAttachment.get(u.getType());
        int uaDiceSides = defending ? ua.getAttackAaMaxDieSides() : ua.getOffensiveAttackAaMaxDieSides();
        if (uaDiceSides < 1) {
            uaDiceSides = diceSize;
        }
        int attack = defending ? ua.getAttackAa(u.getOwner()) : ua.getOffensiveAttackAa(u.getOwner());
        if (attack > uaDiceSides) {
            attack = uaDiceSides;
        }
        if ((((float) attack) / ((float) uaDiceSides)) > (((float) highestAttack) / ((float) chosenDiceSize))) {
            highestAttack = attack;
            chosenDiceSize = uaDiceSides;
        }
    }
    if (highestAttack > chosenDiceSize / 2 && chosenDiceSize > 1) {
        // TODO: sadly the whole low luck section falls apart if AA are hitting at greater than half the
        // value of dice, and I don't feel like rewriting it
        highestAttack = chosenDiceSize / 2;
    }
    return Tuple.of(highestAttack, chosenDiceSize);
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) Unit(games.strategy.engine.data.Unit)

Example 45 with UnitAttachment

use of games.strategy.triplea.attachments.UnitAttachment 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;
}
Also used : LinkedIntegerMap(games.strategy.util.LinkedIntegerMap) IntegerMap(games.strategy.util.IntegerMap) HashMap(java.util.HashMap) UnitSupportAttachment(games.strategy.triplea.attachments.UnitSupportAttachment) Unit(games.strategy.engine.data.Unit) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) LinkedIntegerMap(games.strategy.util.LinkedIntegerMap) ArrayList(java.util.ArrayList) List(java.util.List) Tuple(games.strategy.util.Tuple) HashSet(java.util.HashSet)

Aggregations

UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)60 Unit (games.strategy.engine.data.Unit)45 ArrayList (java.util.ArrayList)25 TripleAUnit (games.strategy.triplea.TripleAUnit)23 UnitType (games.strategy.engine.data.UnitType)20 GameData (games.strategy.engine.data.GameData)19 Territory (games.strategy.engine.data.Territory)19 PlayerID (games.strategy.engine.data.PlayerID)12 CompositeChange (games.strategy.engine.data.CompositeChange)8 TerritoryAttachment (games.strategy.triplea.attachments.TerritoryAttachment)7 IntegerMap (games.strategy.util.IntegerMap)6 Collection (java.util.Collection)6 Set (java.util.Set)6 Change (games.strategy.engine.data.Change)5 Resource (games.strategy.engine.data.Resource)5 Tuple (games.strategy.util.Tuple)5 HashSet (java.util.HashSet)5 ITestDelegateBridge (games.strategy.engine.data.ITestDelegateBridge)4 Route (games.strategy.engine.data.Route)4 List (java.util.List)4