Search in sources :

Example 1 with CasualtyList

use of games.strategy.triplea.delegate.dataObjects.CasualtyList in project triplea by triplea-game.

the class BattleCalculator method selectCasualties.

/**
 * @param battleId
 *        may be null if we are not in a battle (eg, if this is an aa fire due to moving).
 */
public static CasualtyDetails selectCasualties(final String step, final PlayerID player, final Collection<Unit> targetsToPickFrom, final Collection<Unit> friendlyUnits, final PlayerID enemyPlayer, final Collection<Unit> enemyUnits, final boolean amphibious, final Collection<Unit> amphibiousLandAttackers, final Territory battlesite, final Collection<TerritoryEffect> territoryEffects, final IDelegateBridge bridge, final String text, final DiceRoll dice, final boolean defending, final GUID battleId, final boolean headLess, final int extraHits, final boolean allowMultipleHitsPerUnit) {
    if (targetsToPickFrom.isEmpty()) {
        return new CasualtyDetails();
    }
    if (!friendlyUnits.containsAll(targetsToPickFrom)) {
        throw new IllegalStateException("friendlyUnits should but does not contain all units from targetsToPickFrom");
    }
    final GameData data = bridge.getData();
    final boolean isEditMode = BaseEditDelegate.getEditMode(data);
    final ITripleAPlayer tripleaPlayer = player.isNull() ? new WeakAi(player.getName(), TripleA.WEAK_COMPUTER_PLAYER_TYPE) : (ITripleAPlayer) bridge.getRemotePlayer(player);
    final Map<Unit, Collection<Unit>> dependents = headLess ? Collections.emptyMap() : getDependents(targetsToPickFrom);
    if (isEditMode && !headLess) {
        final CasualtyDetails editSelection = tripleaPlayer.selectCasualties(targetsToPickFrom, dependents, 0, text, dice, player, friendlyUnits, enemyPlayer, enemyUnits, amphibious, amphibiousLandAttackers, new CasualtyList(), battleId, battlesite, allowMultipleHitsPerUnit);
        final List<Unit> killed = editSelection.getKilled();
        // if partial retreat is possible, kill amphibious units first
        if (isPartialAmphibiousRetreat(data)) {
            killAmphibiousFirst(killed, targetsToPickFrom);
        }
        return editSelection;
    }
    if (dice.getHits() == 0) {
        return new CasualtyDetails(Collections.emptyList(), Collections.emptyList(), true);
    }
    int hitsRemaining = dice.getHits();
    if (isTransportCasualtiesRestricted(data)) {
        hitsRemaining = extraHits;
    }
    if (!isEditMode && allTargetsOneTypeOneHitPoint(targetsToPickFrom, dependents)) {
        final List<Unit> killed = new ArrayList<>();
        final Iterator<Unit> iter = targetsToPickFrom.iterator();
        for (int i = 0; i < hitsRemaining; i++) {
            if (i >= targetsToPickFrom.size()) {
                break;
            }
            killed.add(iter.next());
        }
        return new CasualtyDetails(killed, Collections.emptyList(), true);
    }
    // Create production cost map, Maybe should do this elsewhere, but in case prices change, we do it here.
    final IntegerMap<UnitType> costs = TuvUtils.getCostsForTuv(player, data);
    final Tuple<CasualtyList, List<Unit>> defaultCasualtiesAndSortedTargets = getDefaultCasualties(targetsToPickFrom, hitsRemaining, defending, player, enemyUnits, amphibious, amphibiousLandAttackers, battlesite, costs, territoryEffects, data, allowMultipleHitsPerUnit, true);
    final CasualtyList defaultCasualties = defaultCasualtiesAndSortedTargets.getFirst();
    final List<Unit> sortedTargetsToPickFrom = defaultCasualtiesAndSortedTargets.getSecond();
    if (sortedTargetsToPickFrom.size() != targetsToPickFrom.size() || !targetsToPickFrom.containsAll(sortedTargetsToPickFrom) || !sortedTargetsToPickFrom.containsAll(targetsToPickFrom)) {
        throw new IllegalStateException("sortedTargetsToPickFrom must contain the same units as targetsToPickFrom list");
    }
    final int totalHitpoints = (allowMultipleHitsPerUnit ? getTotalHitpointsLeft(sortedTargetsToPickFrom) : sortedTargetsToPickFrom.size());
    final CasualtyDetails casualtySelection;
    if (hitsRemaining >= totalHitpoints) {
        casualtySelection = new CasualtyDetails(defaultCasualties, true);
    } else {
        casualtySelection = tripleaPlayer.selectCasualties(sortedTargetsToPickFrom, dependents, hitsRemaining, text, dice, player, friendlyUnits, enemyPlayer, enemyUnits, amphibious, amphibiousLandAttackers, defaultCasualties, battleId, battlesite, allowMultipleHitsPerUnit);
    }
    List<Unit> killed = casualtySelection.getKilled();
    // if partial retreat is possible, kill amphibious units first
    if (isPartialAmphibiousRetreat(data)) {
        killed = killAmphibiousFirst(killed, sortedTargetsToPickFrom);
    }
    final List<Unit> damaged = casualtySelection.getDamaged();
    int numhits = killed.size();
    if (!allowMultipleHitsPerUnit) {
        damaged.clear();
    } else {
        for (final Unit unit : killed) {
            final UnitAttachment ua = UnitAttachment.get(unit.getType());
            final int damageToUnit = Collections.frequency(damaged, unit);
            // allowed damage
            numhits += Math.max(0, Math.min(damageToUnit, (ua.getHitPoints() - (1 + unit.getHits()))));
            // remove from damaged list, since they will die
            damaged.removeIf(unit::equals);
        }
    }
    // check right number
    if (!isEditMode && !(numhits + damaged.size() == (hitsRemaining > totalHitpoints ? totalHitpoints : hitsRemaining))) {
        tripleaPlayer.reportError("Wrong number of casualties selected");
        if (headLess) {
            System.err.println("Possible Infinite Loop: Wrong number of casualties selected: number of hits on units " + (numhits + damaged.size()) + " != number of hits to take " + (hitsRemaining > totalHitpoints ? totalHitpoints : hitsRemaining) + ", for " + casualtySelection.toString());
        }
        return selectCasualties(step, player, sortedTargetsToPickFrom, friendlyUnits, enemyPlayer, enemyUnits, amphibious, amphibiousLandAttackers, battlesite, territoryEffects, bridge, text, dice, defending, battleId, headLess, extraHits, allowMultipleHitsPerUnit);
    }
    // check we have enough of each type
    if (!sortedTargetsToPickFrom.containsAll(killed) || !sortedTargetsToPickFrom.containsAll(damaged)) {
        tripleaPlayer.reportError("Cannot remove enough units of those types");
        if (headLess) {
            System.err.println("Possible Infinite Loop: Cannot remove enough units of those types: targets " + MyFormatter.unitsToTextNoOwner(sortedTargetsToPickFrom) + ", for " + casualtySelection.toString());
        }
        return selectCasualties(step, player, sortedTargetsToPickFrom, friendlyUnits, enemyPlayer, enemyUnits, amphibious, amphibiousLandAttackers, battlesite, territoryEffects, bridge, text, dice, defending, battleId, headLess, extraHits, allowMultipleHitsPerUnit);
    }
    return casualtySelection;
}
Also used : GameData(games.strategy.engine.data.GameData) ArrayList(java.util.ArrayList) Unit(games.strategy.engine.data.Unit) ITripleAPlayer(games.strategy.triplea.player.ITripleAPlayer) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) WeakAi(games.strategy.triplea.ai.weak.WeakAi) CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList) UnitType(games.strategy.engine.data.UnitType) Collection(java.util.Collection) CasualtyDetails(games.strategy.triplea.delegate.dataObjects.CasualtyDetails) ArrayList(java.util.ArrayList) CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList) List(java.util.List)

Example 2 with CasualtyList

use of games.strategy.triplea.delegate.dataObjects.CasualtyList in project triplea by triplea-game.

the class BattleCalculator method getDefaultCasualties.

/**
 * A unit with two hitpoints will be listed twice if they will die. The first time they are listed it is as damaged.
 * The second time they
 * are listed, it is dead.
 */
private static Tuple<CasualtyList, List<Unit>> getDefaultCasualties(final Collection<Unit> targetsToPickFrom, final int hits, final boolean defending, final PlayerID player, final Collection<Unit> enemyUnits, final boolean amphibious, final Collection<Unit> amphibiousLandAttackers, final Territory battlesite, final IntegerMap<UnitType> costs, final Collection<TerritoryEffect> territoryEffects, final GameData data, final boolean allowMultipleHitsPerUnit, final boolean bonus) {
    final CasualtyList defaultCasualtySelection = new CasualtyList();
    // Sort units by power and cost in ascending order
    final List<Unit> sorted = sortUnitsForCasualtiesWithSupport(targetsToPickFrom, defending, player, enemyUnits, amphibious, amphibiousLandAttackers, battlesite, costs, territoryEffects, data, bonus);
    // Remove two hit bb's selecting them first for default casualties
    int numSelectedCasualties = 0;
    if (allowMultipleHitsPerUnit) {
        for (final Unit unit : sorted) {
            // Stop if we have already selected as many hits as there are targets
            if (numSelectedCasualties >= hits) {
                return Tuple.of(defaultCasualtySelection, sorted);
            }
            final UnitAttachment ua = UnitAttachment.get(unit.getType());
            final int extraHitPoints = Math.min((hits - numSelectedCasualties), (ua.getHitPoints() - (1 + unit.getHits())));
            for (int i = 0; i < extraHitPoints; i++) {
                numSelectedCasualties++;
                defaultCasualtySelection.addToDamaged(unit);
            }
        }
    }
    // Select units
    for (final Unit unit : sorted) {
        // Stop if we have already selected as many hits as there are targets
        if (numSelectedCasualties >= hits) {
            return Tuple.of(defaultCasualtySelection, sorted);
        }
        defaultCasualtySelection.addToKilled(unit);
        numSelectedCasualties++;
    }
    return Tuple.of(defaultCasualtySelection, sorted);
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList) Unit(games.strategy.engine.data.Unit)

Example 3 with CasualtyList

use of games.strategy.triplea.delegate.dataObjects.CasualtyList in project triplea by triplea-game.

the class ProAi method selectCasualties.

@Override
public CasualtyDetails selectCasualties(final Collection<Unit> selectFrom, final Map<Unit, Collection<Unit>> dependents, final int count, final String message, final DiceRoll dice, final PlayerID hit, final Collection<Unit> friendlyUnits, final PlayerID enemyPlayer, final Collection<Unit> enemyUnits, final boolean amphibious, final Collection<Unit> amphibiousLandAttackers, final CasualtyList defaultCasualties, final GUID battleId, final Territory battlesite, final boolean allowMultipleHitsPerUnit) {
    initializeData();
    if (defaultCasualties.size() != count) {
        throw new IllegalStateException("Select Casualties showing different numbers for number of hits to take vs total " + "size of default casualty selections");
    }
    if (defaultCasualties.getKilled().size() <= 0) {
        return new CasualtyDetails(defaultCasualties, false);
    }
    // Consider unit cost
    final CasualtyDetails myCasualties = new CasualtyDetails(false);
    myCasualties.addToDamaged(defaultCasualties.getDamaged());
    final List<Unit> selectFromSorted = new ArrayList<>(selectFrom);
    if (enemyUnits.isEmpty()) {
        selectFromSorted.sort(ProPurchaseUtils.getCostComparator());
    } else {
        // Get battle data
        final GameData data = getGameData();
        final PlayerID player = getPlayerId();
        final BattleDelegate delegate = DelegateFinder.battleDelegate(data);
        final IBattle battle = delegate.getBattleTracker().getPendingBattle(battleId);
        // If defender and could lose battle then don't consider unit cost as just trying to survive
        boolean needToCheck = true;
        final boolean isAttacker = player.equals(battle.getAttacker());
        if (!isAttacker) {
            final List<Unit> attackers = (List<Unit>) battle.getAttackingUnits();
            final List<Unit> defenders = (List<Unit>) battle.getDefendingUnits();
            defenders.removeAll(defaultCasualties.getKilled());
            final double strengthDifference = ProBattleUtils.estimateStrengthDifference(battlesite, attackers, defenders);
            int minStrengthDifference = 60;
            if (!Properties.getLowLuck(data)) {
                minStrengthDifference = 55;
            }
            if (strengthDifference > minStrengthDifference) {
                needToCheck = false;
            }
        }
        // Use bubble sort to save expensive units
        while (needToCheck) {
            needToCheck = false;
            for (int i = 0; i < selectFromSorted.size() - 1; i++) {
                final Unit unit1 = selectFromSorted.get(i);
                final Unit unit2 = selectFromSorted.get(i + 1);
                final double unitCost1 = ProPurchaseUtils.getCost(unit1);
                final double unitCost2 = ProPurchaseUtils.getCost(unit2);
                if (unitCost1 > 1.5 * unitCost2) {
                    selectFromSorted.set(i, unit2);
                    selectFromSorted.set(i + 1, unit1);
                    needToCheck = true;
                }
            }
        }
    }
    // Interleave carriers and planes
    final List<Unit> interleavedTargetList = new ArrayList<>(ProTransportUtils.interleaveUnitsCarriersAndPlanes(selectFromSorted, 0));
    for (int i = 0; i < defaultCasualties.getKilled().size(); ++i) {
        myCasualties.addToKilled(interleavedTargetList.get(i));
    }
    if (count != myCasualties.size()) {
        throw new IllegalStateException("AI chose wrong number of casualties");
    }
    return myCasualties;
}
Also used : PlayerID(games.strategy.engine.data.PlayerID) BattleDelegate(games.strategy.triplea.delegate.BattleDelegate) GameData(games.strategy.engine.data.GameData) ArrayList(java.util.ArrayList) Unit(games.strategy.engine.data.Unit) IBattle(games.strategy.triplea.delegate.IBattle) CasualtyDetails(games.strategy.triplea.delegate.dataObjects.CasualtyDetails) List(java.util.List) ArrayList(java.util.ArrayList) CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList)

Example 4 with CasualtyList

use of games.strategy.triplea.delegate.dataObjects.CasualtyList in project triplea by triplea-game.

the class RevisedTest method setUp.

/**
 * Sets up a GameData object for testing..
 */
@BeforeEach
public void setUp() throws Exception {
    when(dummyPlayer.selectCasualties(any(), any(), anyInt(), any(), any(), any(), any(), any(), any(), anyBoolean(), any(), any(), any(), any(), anyBoolean())).thenAnswer(new Answer<CasualtyDetails>() {

        @Override
        public CasualtyDetails answer(final InvocationOnMock invocation) {
            final CasualtyList defaultCasualties = invocation.getArgument(11);
            if (defaultCasualties != null) {
                return new CasualtyDetails(defaultCasualties.getKilled(), defaultCasualties.getDamaged(), true);
            }
            return null;
        }
    });
    gameData = TestMapGameData.REVISED.getGameData();
}
Also used : CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList) InvocationOnMock(org.mockito.invocation.InvocationOnMock) CasualtyDetails(games.strategy.triplea.delegate.dataObjects.CasualtyDetails) BeforeEach(org.junit.jupiter.api.BeforeEach)

Example 5 with CasualtyList

use of games.strategy.triplea.delegate.dataObjects.CasualtyList in project triplea by triplea-game.

the class WW2V3Year41Test method setUp.

@BeforeEach
public void setUp() throws Exception {
    when(dummyPlayer.selectCasualties(any(), any(), anyInt(), any(), any(), any(), any(), any(), any(), anyBoolean(), any(), any(), any(), any(), anyBoolean())).thenAnswer(new Answer<CasualtyDetails>() {

        @Override
        public CasualtyDetails answer(final InvocationOnMock invocation) {
            final CasualtyList defaultCasualties = invocation.getArgument(11);
            if (defaultCasualties != null) {
                return new CasualtyDetails(defaultCasualties.getKilled(), defaultCasualties.getDamaged(), true);
            }
            return null;
        }
    });
    gameData = TestMapGameData.WW2V3_1941.getGameData();
}
Also used : CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList) InvocationOnMock(org.mockito.invocation.InvocationOnMock) CasualtyDetails(games.strategy.triplea.delegate.dataObjects.CasualtyDetails) BeforeEach(org.junit.jupiter.api.BeforeEach)

Aggregations

CasualtyList (games.strategy.triplea.delegate.dataObjects.CasualtyList)6 CasualtyDetails (games.strategy.triplea.delegate.dataObjects.CasualtyDetails)5 Unit (games.strategy.engine.data.Unit)3 ArrayList (java.util.ArrayList)3 List (java.util.List)3 GameData (games.strategy.engine.data.GameData)2 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)2 BeforeEach (org.junit.jupiter.api.BeforeEach)2 InvocationOnMock (org.mockito.invocation.InvocationOnMock)2 PlayerID (games.strategy.engine.data.PlayerID)1 UnitType (games.strategy.engine.data.UnitType)1 WeakAi (games.strategy.triplea.ai.weak.WeakAi)1 BattleDelegate (games.strategy.triplea.delegate.BattleDelegate)1 IBattle (games.strategy.triplea.delegate.IBattle)1 ITripleAPlayer (games.strategy.triplea.player.ITripleAPlayer)1 Dimension (java.awt.Dimension)1 ActionEvent (java.awt.event.ActionEvent)1 Collection (java.util.Collection)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 AtomicReference (java.util.concurrent.atomic.AtomicReference)1