Search in sources :

Example 1 with TerritoryAttachment

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

the class BattleDelegate method doKamikazeSuicideAttacks.

/**
 * KamikazeSuicideAttacks are attacks that are made during an Opponent's turn, using Resources that you own that have
 * been designated.
 * The resources are designated in PlayerAttachment, and hold information like the attack power of the resource.
 * KamikazeSuicideAttacks are done in any territory that is a kamikazeZone, and the attacks are done by the original
 * owner of that
 * territory.
 * The user has the option not to do any attacks, and they make target any number of units with any number of resource
 * tokens.
 * The units are then attacked individually by each resource token (meaning that casualties do not get selected
 * because the attacks are
 * targeted).
 * The enemies of current player should decide all their attacks before the attacks are rolled.
 */
private void doKamikazeSuicideAttacks() {
    final GameData data = getData();
    if (!Properties.getUseKamikazeSuicideAttacks(data)) {
        return;
    }
    // the current player is not the one who is doing these attacks, it is the all the enemies of this player who will
    // do attacks
    final Collection<PlayerID> enemies = CollectionUtils.getMatches(data.getPlayerList().getPlayers(), Matches.isAtWar(player, data));
    if (enemies.isEmpty()) {
        return;
    }
    final Predicate<Unit> canBeAttackedDefault = Matches.unitIsOwnedBy(player).and(Matches.unitIsSea()).and(Matches.unitIsNotTransportButCouldBeCombatTransport()).and(Matches.unitIsNotSub());
    final boolean onlyWhereThereAreBattlesOrAmphibious = Properties.getKamikazeSuicideAttacksOnlyWhereBattlesAre(data);
    final Collection<Territory> pendingBattles = battleTracker.getPendingBattleSites(false);
    // create a list of all kamikaze zones, listed by enemy
    final Map<PlayerID, Collection<Territory>> kamikazeZonesByEnemy = new HashMap<>();
    for (final Territory t : data.getMap().getTerritories()) {
        final TerritoryAttachment ta = TerritoryAttachment.get(t);
        if (ta == null || !ta.getKamikazeZone()) {
            continue;
        }
        final PlayerID owner = !Properties.getKamikazeSuicideAttacksDoneByCurrentTerritoryOwner(data) ? ta.getOriginalOwner() : t.getOwner();
        if (owner == null) {
            continue;
        }
        if (enemies.contains(owner)) {
            if (t.getUnits().getUnits().stream().noneMatch(Matches.unitIsOwnedBy(player))) {
                continue;
            }
            if (onlyWhereThereAreBattlesOrAmphibious) {
                // if no battle or amphibious from here, ignore it
                if (!pendingBattles.contains(t)) {
                    if (!Matches.territoryIsWater().test(t)) {
                        continue;
                    }
                    boolean amphib = false;
                    final Collection<Territory> landNeighbors = data.getMap().getNeighbors(t, Matches.territoryIsLand());
                    for (final Territory neighbor : landNeighbors) {
                        final IBattle battle = battleTracker.getPendingBattle(neighbor, false, BattleType.NORMAL);
                        if (battle == null) {
                            final Map<Territory, Collection<Unit>> whereFrom = battleTracker.getFinishedBattlesUnitAttackFromMap().get(neighbor);
                            if (whereFrom != null && whereFrom.containsKey(t)) {
                                amphib = true;
                                break;
                            }
                            continue;
                        }
                        if (battle.isAmphibious() && ((battle instanceof MustFightBattle && ((MustFightBattle) battle).getAmphibiousAttackTerritories().contains(t)) || (battle instanceof NonFightingBattle && ((NonFightingBattle) battle).getAmphibiousAttackTerritories().contains(t)))) {
                            amphib = true;
                            break;
                        }
                    }
                    if (!amphib) {
                        continue;
                    }
                }
            }
            final Collection<Territory> currentTerrs = kamikazeZonesByEnemy.getOrDefault(owner, new ArrayList<>());
            currentTerrs.add(t);
            kamikazeZonesByEnemy.put(owner, currentTerrs);
        }
    }
    if (kamikazeZonesByEnemy.isEmpty()) {
        return;
    }
    for (final Entry<PlayerID, Collection<Territory>> entry : kamikazeZonesByEnemy.entrySet()) {
        final PlayerID currentEnemy = entry.getKey();
        final PlayerAttachment pa = PlayerAttachment.get(currentEnemy);
        if (pa == null) {
            continue;
        }
        Predicate<Unit> canBeAttacked = canBeAttackedDefault;
        final Set<UnitType> suicideAttackTargets = pa.getSuicideAttackTargets();
        if (suicideAttackTargets != null) {
            canBeAttacked = Matches.unitIsOwnedBy(player).and(Matches.unitIsOfTypes(suicideAttackTargets));
        }
        // See if the player has any attack tokens
        final IntegerMap<Resource> resourcesAndAttackValues = pa.getSuicideAttackResources();
        if (resourcesAndAttackValues.size() <= 0) {
            continue;
        }
        final IntegerMap<Resource> playerResourceCollection = currentEnemy.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) {
            continue;
        }
        // now let the enemy decide if they will do attacks
        final Collection<Territory> kamikazeZones = entry.getValue();
        final HashMap<Territory, Collection<Unit>> possibleUnitsToAttack = new HashMap<>();
        for (final Territory t : kamikazeZones) {
            final List<Unit> validTargets = t.getUnits().getMatches(canBeAttacked);
            if (!validTargets.isEmpty()) {
                possibleUnitsToAttack.put(t, validTargets);
            }
        }
        final Map<Territory, HashMap<Unit, IntegerMap<Resource>>> attacks = getRemotePlayer(currentEnemy).selectKamikazeSuicideAttacks(possibleUnitsToAttack);
        if (attacks == null || attacks.isEmpty()) {
            continue;
        }
        // now validate that we have the resources and those units are valid targets
        for (final Entry<Territory, HashMap<Unit, IntegerMap<Resource>>> territoryEntry : attacks.entrySet()) {
            final Territory t = territoryEntry.getKey();
            final Collection<Unit> possibleUnits = possibleUnitsToAttack.get(t);
            if (possibleUnits == null || !possibleUnits.containsAll(territoryEntry.getValue().keySet())) {
                throw new IllegalStateException("Player has chosen illegal units during Kamikaze Suicide Attacks");
            }
            for (final IntegerMap<Resource> resourceMap : territoryEntry.getValue().values()) {
                attackTokens.subtract(resourceMap);
            }
        }
        if (!attackTokens.isPositive()) {
            throw new IllegalStateException("Player has chosen illegal resource during Kamikaze Suicide Attacks");
        }
        for (final Entry<Territory, HashMap<Unit, IntegerMap<Resource>>> territoryEntry : attacks.entrySet()) {
            final Territory location = territoryEntry.getKey();
            for (final Entry<Unit, IntegerMap<Resource>> unitEntry : territoryEntry.getValue().entrySet()) {
                final Unit unitUnderFire = unitEntry.getKey();
                final IntegerMap<Resource> numberOfAttacks = unitEntry.getValue();
                if (numberOfAttacks != null && numberOfAttacks.size() > 0 && numberOfAttacks.totalValues() > 0) {
                    fireKamikazeSuicideAttacks(unitUnderFire, numberOfAttacks, resourcesAndAttackValues, currentEnemy, location);
                }
            }
        }
    }
}
Also used : PlayerID(games.strategy.engine.data.PlayerID) GameData(games.strategy.engine.data.GameData) HashMap(java.util.HashMap) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) PlayerAttachment(games.strategy.triplea.attachments.PlayerAttachment) UnitType(games.strategy.engine.data.UnitType) IntegerMap(games.strategy.util.IntegerMap) Territory(games.strategy.engine.data.Territory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) Resource(games.strategy.engine.data.Resource) Collection(java.util.Collection) ResourceCollection(games.strategy.engine.data.ResourceCollection)

Example 2 with TerritoryAttachment

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

the class AbstractPlaceDelegate method getUnitsToBePlacedAllDefault.

protected Collection<Unit> getUnitsToBePlacedAllDefault(final Territory to, final Collection<Unit> allUnits, final PlayerID player) {
    final boolean water = to.isWater();
    if (water && (!isWW2V2() && !isUnitPlacementInEnemySeas()) && to.getUnits().anyMatch(Matches.enemyUnit(player, getData()))) {
        return null;
    }
    final Collection<Unit> units = new ArrayList<>(allUnits);
    // if water, remove land. if land, remove water.
    units.removeAll(CollectionUtils.getMatches(units, water ? Matches.unitIsLand() : Matches.unitIsSea()));
    final Collection<Unit> placeableUnits = new ArrayList<>();
    final Collection<Unit> unitsAtStartOfTurnInTo = unitsAtStartOfStepInTerritory(to);
    final Collection<Unit> allProducedUnits = unitsPlacedInTerritorySoFar(to);
    final boolean isBid = GameStepPropertiesHelper.isBid(getData());
    final boolean wasFactoryThereAtStart = wasOwnedUnitThatCanProduceUnitsOrIsFactoryInTerritoryAtStartOfStep(to, player);
    // we add factories and constructions later
    if (water || wasFactoryThereAtStart || (!water && isPlayerAllowedToPlacementAnyTerritoryOwnedLand(player))) {
        final Predicate<Unit> seaOrLandMatch = water ? Matches.unitIsSea() : Matches.unitIsLand();
        placeableUnits.addAll(CollectionUtils.getMatches(units, seaOrLandMatch.and(Matches.unitIsNotConstruction())));
        if (!water) {
            placeableUnits.addAll(CollectionUtils.getMatches(units, Matches.unitIsAir().and(Matches.unitIsNotConstruction())));
        } else if (((isBid || canProduceFightersOnCarriers() || AirThatCantLandUtil.isLhtrCarrierProduction(getData())) && allProducedUnits.stream().anyMatch(Matches.unitIsCarrier())) || ((isBid || canProduceNewFightersOnOldCarriers() || AirThatCantLandUtil.isLhtrCarrierProduction(getData())) && to.getUnits().anyMatch(Matches.unitIsCarrier()))) {
            placeableUnits.addAll(CollectionUtils.getMatches(units, Matches.unitIsAir().and(Matches.unitCanLandOnCarrier())));
        }
    }
    if (units.stream().anyMatch(Matches.unitIsConstruction())) {
        final IntegerMap<String> constructionsMap = howManyOfEachConstructionCanPlace(to, to, units, player);
        final Collection<Unit> skipUnits = new ArrayList<>();
        for (final Unit currentUnit : CollectionUtils.getMatches(units, Matches.unitIsConstruction())) {
            final int maxUnits = howManyOfConstructionUnit(currentUnit, constructionsMap);
            if (maxUnits > 0) {
                // max placement by constructionType of each unitType
                if (skipUnits.contains(currentUnit)) {
                    continue;
                }
                placeableUnits.addAll(CollectionUtils.getNMatches(units, maxUnits, Matches.unitIsOfType(currentUnit.getType())));
                skipUnits.addAll(CollectionUtils.getMatches(units, Matches.unitIsOfType(currentUnit.getType())));
            }
        }
    }
    // remove any units that require other units to be consumed on creation, if we don't have enough to consume (veqryn)
    if (placeableUnits.stream().anyMatch(Matches.unitConsumesUnitsOnCreation())) {
        final Collection<Unit> unitsWhichConsume = CollectionUtils.getMatches(placeableUnits, Matches.unitConsumesUnitsOnCreation());
        for (final Unit unit : unitsWhichConsume) {
            if (Matches.unitWhichConsumesUnitsHasRequiredUnits(unitsAtStartOfTurnInTo).negate().test(unit)) {
                placeableUnits.remove(unit);
            }
        }
    }
    // now check stacking limits
    final Collection<Unit> placeableUnits2 = new ArrayList<>();
    final Collection<UnitType> typesAlreadyChecked = new ArrayList<>();
    for (final Unit currentUnit : placeableUnits) {
        final UnitType ut = currentUnit.getType();
        if (typesAlreadyChecked.contains(ut)) {
            continue;
        }
        typesAlreadyChecked.add(ut);
        placeableUnits2.addAll(CollectionUtils.getNMatches(placeableUnits, UnitAttachment.getMaximumNumberOfThisUnitTypeToReachStackingLimit("placementLimit", ut, to, player, getData()), Matches.unitIsOfType(ut)));
    }
    if (!isUnitPlacementRestrictions()) {
        return placeableUnits2;
    }
    final Collection<Unit> placeableUnits3 = new ArrayList<>();
    for (final Unit currentUnit : placeableUnits2) {
        final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
        // Can be null!
        final TerritoryAttachment ta = TerritoryAttachment.get(to);
        if (ua.getCanOnlyBePlacedInTerritoryValuedAtX() != -1 && ua.getCanOnlyBePlacedInTerritoryValuedAtX() > (ta == null ? 0 : ta.getProduction())) {
            continue;
        }
        if (unitWhichRequiresUnitsHasRequiredUnits(to, false).negate().test(currentUnit)) {
            continue;
        }
        if (Matches.unitCanOnlyPlaceInOriginalTerritories().test(currentUnit) && !Matches.territoryIsOriginallyOwnedBy(player).test(to)) {
            continue;
        }
        // account for any unit placement restrictions by territory
        final String[] terrs = ua.getUnitPlacementRestrictions();
        final Collection<Territory> listedTerrs = getListedTerritories(terrs);
        if (!listedTerrs.contains(to)) {
            placeableUnits3.add(currentUnit);
        }
    }
    return placeableUnits3;
}
Also used : Territory(games.strategy.engine.data.Territory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) UnitType(games.strategy.engine.data.UnitType)

Example 3 with TerritoryAttachment

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

the class AbstractPlaceDelegate method canUnitsBePlaced.

public String canUnitsBePlaced(final Territory to, final Collection<Unit> units, final PlayerID player) {
    final Collection<Unit> allowedUnits = getUnitsToBePlaced(to, units, player);
    if (allowedUnits == null || !allowedUnits.containsAll(units)) {
        return "Cannot place these units in " + to.getName();
    }
    final IntegerMap<String> constructionMap = howManyOfEachConstructionCanPlace(to, to, units, player);
    for (final Unit currentUnit : CollectionUtils.getMatches(units, Matches.unitIsConstruction())) {
        final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
        /*
       * if (ua.getIsFactory() && !ua.getIsConstruction())
       * constructionMap.add("factory", -1);
       * else
       */
        constructionMap.add(ua.getConstructionType(), -1);
    }
    if (!constructionMap.isPositive()) {
        return "Too many constructions in " + to.getName();
    }
    final List<Territory> capitalsListOwned = new ArrayList<>(TerritoryAttachment.getAllCurrentlyOwnedCapitals(player, getData()));
    if (!capitalsListOwned.contains(to) && isPlacementInCapitalRestricted(player)) {
        return "Cannot place these units outside of the capital";
    }
    if (to.isWater()) {
        final String canLand = validateNewAirCanLandOnCarriers(to, units);
        if (canLand != null) {
            return canLand;
        }
    } else {
        // make sure we own the territory
        if (!to.getOwner().equals(player)) {
            if (GameStepPropertiesHelper.isBid(getData())) {
                final PlayerAttachment pa = PlayerAttachment.get(to.getOwner());
                if ((pa == null || pa.getGiveUnitControl() == null || !pa.getGiveUnitControl().contains(player)) && !to.getUnits().anyMatch(Matches.unitIsOwnedBy(player))) {
                    return "You don't own " + to.getName();
                }
            } else {
                return "You don't own " + to.getName();
            }
        }
        // make sure all units are land
        if (units.isEmpty() || !units.stream().allMatch(Matches.unitIsNotSea())) {
            return "Cant place sea units on land";
        }
    }
    // make sure we can place consuming units
    if (!canWeConsumeUnits(units, to, false, null)) {
        return "Not Enough Units To Upgrade or Be Consumed";
    }
    // now check for stacking limits
    final Collection<UnitType> typesAlreadyChecked = new ArrayList<>();
    for (final Unit currentUnit : units) {
        final UnitType ut = currentUnit.getType();
        if (typesAlreadyChecked.contains(ut)) {
            continue;
        }
        typesAlreadyChecked.add(ut);
        final int maxForThisType = UnitAttachment.getMaximumNumberOfThisUnitTypeToReachStackingLimit("placementLimit", ut, to, player, getData());
        if (CollectionUtils.countMatches(units, Matches.unitIsOfType(ut)) > maxForThisType) {
            return "UnitType " + ut.getName() + " is over stacking limit of " + maxForThisType;
        }
    }
    if (!PlayerAttachment.getCanTheseUnitsMoveWithoutViolatingStackingLimit("placementLimit", units, to, player, getData())) {
        return "Units Cannot Go Over Stacking Limit";
    }
    // now return null (valid placement) if we have placement restrictions disabled in game options
    if (!isUnitPlacementRestrictions()) {
        return null;
    }
    // account for any unit placement restrictions by territory
    for (final Unit currentUnit : units) {
        final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
        // Can be null!
        final TerritoryAttachment ta = TerritoryAttachment.get(to);
        if (ua.getCanOnlyBePlacedInTerritoryValuedAtX() != -1 && ua.getCanOnlyBePlacedInTerritoryValuedAtX() > (ta == null ? 0 : ta.getProduction())) {
            return "Cannot place these units in " + to.getName() + " due to Unit Placement Restrictions on Territory Value";
        }
        final String[] terrs = ua.getUnitPlacementRestrictions();
        final Collection<Territory> listedTerrs = getListedTerritories(terrs);
        if (listedTerrs.contains(to)) {
            return "Cannot place these units in " + to.getName() + " due to Unit Placement Restrictions";
        }
        if (Matches.unitCanOnlyPlaceInOriginalTerritories().test(currentUnit) && !Matches.territoryIsOriginallyOwnedBy(player).test(to)) {
            return "Cannot place these units in " + to.getName() + " as territory is not originally owned";
        }
    }
    return null;
}
Also used : Territory(games.strategy.engine.data.Territory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) PlayerAttachment(games.strategy.triplea.attachments.PlayerAttachment) UnitType(games.strategy.engine.data.UnitType)

Example 4 with TerritoryAttachment

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

the class AbstractPlaceDelegate method getMaxUnitsToBePlacedFrom.

/**
 * Returns -1 if can place unlimited units.
 */
protected int getMaxUnitsToBePlacedFrom(final Territory producer, final Collection<Unit> units, final Territory to, final PlayerID player, final boolean countSwitchedProductionToNeighbors, final Collection<Territory> notUsableAsOtherProducers, final Map<Territory, Integer> currentAvailablePlacementForOtherProducers) {
    // we may have special units with requiresUnits restrictions
    final Collection<Unit> unitsCanBePlacedByThisProducer = (isUnitPlacementRestrictions() ? CollectionUtils.getMatches(units, unitWhichRequiresUnitsHasRequiredUnits(producer, true)) : new ArrayList<>(units));
    if (unitsCanBePlacedByThisProducer.size() <= 0) {
        return 0;
    }
    // if its an original factory then unlimited production
    // Can be null!
    final TerritoryAttachment ta = TerritoryAttachment.get(producer);
    final Predicate<Unit> factoryMatch = Matches.unitIsOwnedAndIsFactoryOrCanProduceUnits(player).and(Matches.unitIsBeingTransported().negate()).and(producer.isWater() ? Matches.unitIsLand().negate() : Matches.unitIsSea().negate());
    final Collection<Unit> factoryUnits = producer.getUnits().getMatches(factoryMatch);
    // boolean placementRestrictedByFactory = isPlacementRestrictedByFactory();
    final boolean unitPlacementPerTerritoryRestricted = isUnitPlacementPerTerritoryRestricted();
    final boolean originalFactory = (ta != null && ta.getOriginalFactory());
    final boolean playerIsOriginalOwner = factoryUnits.size() > 0 && this.player.equals(getOriginalFactoryOwner(producer));
    final RulesAttachment ra = (RulesAttachment) player.getAttachment(Constants.RULES_ATTACHMENT_NAME);
    final Collection<Unit> alreadProducedUnits = getAlreadyProduced(producer);
    final int unitCountAlreadyProduced = alreadProducedUnits.size();
    if (originalFactory && playerIsOriginalOwner) {
        if (ra != null && ra.getMaxPlacePerTerritory() != -1) {
            return Math.max(0, ra.getMaxPlacePerTerritory() - unitCountAlreadyProduced);
        }
        return -1;
    }
    // Restricts based on the STARTING number of units in a territory (otherwise it is infinite placement)
    if (unitPlacementPerTerritoryRestricted) {
        if (ra != null && ra.getPlacementPerTerritory() > 0) {
            final int allowedPlacement = ra.getPlacementPerTerritory();
            final int ownedUnitsInTerritory = CollectionUtils.countMatches(to.getUnits().getUnits(), Matches.unitIsOwnedBy(player));
            if (ownedUnitsInTerritory >= allowedPlacement) {
                return 0;
            }
            if (ra.getMaxPlacePerTerritory() == -1) {
                return -1;
            }
            return Math.max(0, ra.getMaxPlacePerTerritory() - unitCountAlreadyProduced);
        }
    }
    // a factory can produce the same number of units as the number of PUs the territory generates each turn (or not, if
    // it has canProduceXUnits)
    final int maxConstructions = howManyOfEachConstructionCanPlace(to, producer, unitsCanBePlacedByThisProducer, player).totalValues();
    final boolean wasFactoryThereAtStart = wasOwnedUnitThatCanProduceUnitsOrIsFactoryInTerritoryAtStartOfStep(producer, player);
    // If there's NO factory, allow placement of the factory
    if (!wasFactoryThereAtStart) {
        if (ra != null && ra.getMaxPlacePerTerritory() > 0) {
            return Math.max(0, Math.min(maxConstructions, ra.getMaxPlacePerTerritory() - unitCountAlreadyProduced));
        }
        return Math.max(0, maxConstructions);
    }
    // getHowMuchCanUnitProduce accounts for IncreasedFactoryProduction, but does not account for maxConstructions
    int production = TripleAUnit.getProductionPotentialOfTerritory(unitsAtStartOfStepInTerritory(producer), producer, player, getData(), true, true);
    // increase the production by the number of constructions allowed
    if (maxConstructions > 0) {
        production += maxConstructions;
    }
    // return 0 if less than 0
    if (production < 0) {
        return 0;
    }
    production += CollectionUtils.countMatches(alreadProducedUnits, Matches.unitIsConstruction());
    // Now we check if units we have already produced here could be produced by a different producer
    int unitCountHaveToAndHaveBeenBeProducedHere = unitCountAlreadyProduced;
    if (countSwitchedProductionToNeighbors && unitCountAlreadyProduced > 0) {
        if (notUsableAsOtherProducers == null) {
            throw new IllegalStateException("notUsableAsOtherProducers cannot be null if countSwitchedProductionToNeighbors is true");
        }
        if (currentAvailablePlacementForOtherProducers == null) {
            throw new IllegalStateException("currentAvailablePlacementForOtherProducers cannot be null if countSwitchedProductionToNeighbors is true");
        }
        int productionCanNotBeMoved = 0;
        int productionThatCanBeTakenOver = 0;
        // try to find a placement move (to an adjacent sea zone) that can be taken over by some other territory factory
        for (final UndoablePlacement placementMove : placements) {
            if (placementMove.getProducerTerritory().equals(producer)) {
                final Territory placeTerritory = placementMove.getPlaceTerritory();
                final Collection<Unit> unitsPlacedByCurrentPlacementMove = placementMove.getUnits();
                // for our special 'move shit around' methods.
                if (!placeTerritory.isWater() || (isUnitPlacementRestrictions() && unitsPlacedByCurrentPlacementMove.stream().anyMatch(Matches.unitRequiresUnitsOnCreation()))) {
                    productionCanNotBeMoved += unitsPlacedByCurrentPlacementMove.size();
                } else {
                    final int maxProductionThatCanBeTakenOverFromThisPlacement = unitsPlacedByCurrentPlacementMove.size();
                    // find other producers for this placement move to the same water territory
                    final List<Territory> newPotentialOtherProducers = getAllProducers(placeTerritory, player, unitsCanBePlacedByThisProducer);
                    newPotentialOtherProducers.removeAll(notUsableAsOtherProducers);
                    newPotentialOtherProducers.sort(getBestProducerComparator(placeTerritory, unitsCanBePlacedByThisProducer, player));
                    int productionThatCanBeTakenOverFromThisPlacement = 0;
                    for (final Territory potentialOtherProducer : newPotentialOtherProducers) {
                        Integer potential = currentAvailablePlacementForOtherProducers.get(potentialOtherProducer);
                        if (potential == null) {
                            potential = getMaxUnitsToBePlacedFrom(potentialOtherProducer, unitsPlacedInTerritorySoFar(placeTerritory), placeTerritory, player);
                        }
                        if (potential == -1) {
                            currentAvailablePlacementForOtherProducers.put(potentialOtherProducer, -1);
                            productionThatCanBeTakenOverFromThisPlacement = maxProductionThatCanBeTakenOverFromThisPlacement;
                            break;
                        }
                        final int needed = maxProductionThatCanBeTakenOverFromThisPlacement - productionThatCanBeTakenOverFromThisPlacement;
                        final int surplus = potential - needed;
                        if (surplus > 0) {
                            currentAvailablePlacementForOtherProducers.put(potentialOtherProducer, surplus);
                            productionThatCanBeTakenOverFromThisPlacement += needed;
                        } else {
                            currentAvailablePlacementForOtherProducers.put(potentialOtherProducer, 0);
                            productionThatCanBeTakenOverFromThisPlacement += potential;
                            notUsableAsOtherProducers.add(potentialOtherProducer);
                        }
                        if (surplus >= 0) {
                            break;
                        }
                    }
                    if (productionThatCanBeTakenOverFromThisPlacement > maxProductionThatCanBeTakenOverFromThisPlacement) {
                        throw new IllegalStateException("productionThatCanBeTakenOverFromThisPlacement should never be larger " + "than maxProductionThatCanBeTakenOverFromThisPlacement");
                    }
                    productionThatCanBeTakenOver += productionThatCanBeTakenOverFromThisPlacement;
                }
                if (productionThatCanBeTakenOver >= unitCountAlreadyProduced - productionCanNotBeMoved) {
                    break;
                }
            }
        }
        unitCountHaveToAndHaveBeenBeProducedHere = Math.max(0, unitCountAlreadyProduced - productionThatCanBeTakenOver);
    }
    if (ra != null && ra.getMaxPlacePerTerritory() > 0) {
        return Math.max(0, Math.min(production - unitCountHaveToAndHaveBeenBeProducedHere, ra.getMaxPlacePerTerritory() - unitCountHaveToAndHaveBeenBeProducedHere));
    }
    return Math.max(0, production - unitCountHaveToAndHaveBeenBeProducedHere);
}
Also used : Territory(games.strategy.engine.data.Territory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) RulesAttachment(games.strategy.triplea.attachments.RulesAttachment)

Example 5 with TerritoryAttachment

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

the class AbstractPlaceDelegate method howManyOfEachConstructionCanPlace.

/**
 * @param to
 *        referring territory.
 * @param units
 *        units to place
 * @param player
 *        PlayerID
 * @return an empty IntegerMap if you can't produce any constructions (will never return null)
 */
public IntegerMap<String> howManyOfEachConstructionCanPlace(final Territory to, final Territory producer, final Collection<Unit> units, final PlayerID player) {
    // constructions can ONLY be produced BY the same territory that they are going into!
    if (!to.equals(producer) || units == null || units.isEmpty() || units.stream().noneMatch(Matches.unitIsConstruction())) {
        return new IntegerMap<>();
    }
    final Collection<Unit> unitsAtStartOfTurnInTo = unitsAtStartOfStepInTerritory(to);
    final Collection<Unit> unitsInTo = to.getUnits().getUnits();
    final Collection<Unit> unitsPlacedAlready = getAlreadyProduced(to);
    // build an integer map of each unit we have in our list of held units, as well as integer maps for maximum units
    // and units per turn
    final IntegerMap<String> unitMapHeld = new IntegerMap<>();
    final IntegerMap<String> unitMapMaxType = new IntegerMap<>();
    final IntegerMap<String> unitMapTypePerTurn = new IntegerMap<>();
    final int maxFactory = Properties.getFactoriesPerCountry(getData());
    // Can be null!
    final TerritoryAttachment terrAttachment = TerritoryAttachment.get(to);
    int toProduction = 0;
    if (terrAttachment != null) {
        toProduction = terrAttachment.getProduction();
    }
    for (final Unit currentUnit : CollectionUtils.getMatches(units, Matches.unitIsConstruction())) {
        final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
        // account for any unit placement restrictions by territory
        if (isUnitPlacementRestrictions()) {
            final String[] terrs = ua.getUnitPlacementRestrictions();
            final Collection<Territory> listedTerrs = getListedTerritories(terrs);
            if (listedTerrs.contains(to)) {
                continue;
            }
            if (ua.getCanOnlyBePlacedInTerritoryValuedAtX() != -1 && ua.getCanOnlyBePlacedInTerritoryValuedAtX() > toProduction) {
                continue;
            }
            if (unitWhichRequiresUnitsHasRequiredUnits(to, false).negate().test(currentUnit)) {
                continue;
            }
        }
        // remove any units that require other units to be consumed on creation (veqryn)
        if (Matches.unitConsumesUnitsOnCreation().test(currentUnit) && Matches.unitWhichConsumesUnitsHasRequiredUnits(unitsAtStartOfTurnInTo).negate().test(currentUnit)) {
            continue;
        }
        unitMapHeld.add(ua.getConstructionType(), 1);
        unitMapTypePerTurn.put(ua.getConstructionType(), ua.getConstructionsPerTerrPerTypePerTurn());
        if (ua.getConstructionType().equals(Constants.CONSTRUCTION_TYPE_FACTORY)) {
            unitMapMaxType.put(ua.getConstructionType(), maxFactory);
        } else {
            unitMapMaxType.put(ua.getConstructionType(), ua.getMaxConstructionsPerTypePerTerr());
        }
    }
    final boolean moreWithoutFactory = Properties.getMoreConstructionsWithoutFactory(getData());
    final boolean moreWithFactory = Properties.getMoreConstructionsWithFactory(getData());
    final boolean unlimitedConstructions = Properties.getUnlimitedConstructions(getData());
    final boolean wasFactoryThereAtStart = wasOwnedUnitThatCanProduceUnitsOrIsFactoryInTerritoryAtStartOfStep(to, player);
    // build an integer map of each construction unit in the territory
    final IntegerMap<String> unitMapTo = new IntegerMap<>();
    if (unitsInTo.stream().anyMatch(Matches.unitIsConstruction())) {
        for (final Unit currentUnit : CollectionUtils.getMatches(unitsInTo, Matches.unitIsConstruction())) {
            final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
            /*
         * if (Matches.UnitIsFactory.test(currentUnit) && !ua.getIsConstruction())
         * unitMapTO.add("factory", 1);
         * else
         */
            unitMapTo.add(ua.getConstructionType(), 1);
        }
        // account for units already in the territory, based on max
        for (final String constructionType : unitMapHeld.keySet()) {
            int unitMax = unitMapMaxType.getInt(constructionType);
            if (wasFactoryThereAtStart && !constructionType.equals(Constants.CONSTRUCTION_TYPE_FACTORY) && !constructionType.endsWith("structure")) {
                unitMax = Math.max(Math.max(unitMax, (moreWithFactory ? toProduction : 0)), (unlimitedConstructions ? 10000 : 0));
            }
            if (!wasFactoryThereAtStart && !constructionType.equals(Constants.CONSTRUCTION_TYPE_FACTORY) && !constructionType.endsWith("structure")) {
                unitMax = Math.max(Math.max(unitMax, (moreWithoutFactory ? toProduction : 0)), (unlimitedConstructions ? 10000 : 0));
            }
            unitMapHeld.put(constructionType, Math.max(0, Math.min(unitMax - unitMapTo.getInt(constructionType), unitMapHeld.getInt(constructionType))));
        }
    }
    // deal with already placed units
    for (final Unit currentUnit : CollectionUtils.getMatches(unitsPlacedAlready, Matches.unitIsConstruction())) {
        final UnitAttachment ua = UnitAttachment.get(currentUnit.getType());
        unitMapTypePerTurn.add(ua.getConstructionType(), -1);
    }
    // modify this list based on how many we can place per turn
    final IntegerMap<String> unitsAllowed = new IntegerMap<>();
    for (final String constructionType : unitMapHeld.keySet()) {
        final int unitAllowed = Math.max(0, Math.min(unitMapTypePerTurn.getInt(constructionType), unitMapHeld.getInt(constructionType)));
        if (unitAllowed > 0) {
            unitsAllowed.put(constructionType, unitAllowed);
        }
    }
    // return our integer map
    return unitsAllowed;
}
Also used : IntegerMap(games.strategy.util.IntegerMap) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) Territory(games.strategy.engine.data.Territory) TerritoryAttachment(games.strategy.triplea.attachments.TerritoryAttachment) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit)

Aggregations

TerritoryAttachment (games.strategy.triplea.attachments.TerritoryAttachment)36 Territory (games.strategy.engine.data.Territory)29 Unit (games.strategy.engine.data.Unit)24 TripleAUnit (games.strategy.triplea.TripleAUnit)19 ArrayList (java.util.ArrayList)14 PlayerID (games.strategy.engine.data.PlayerID)13 GameData (games.strategy.engine.data.GameData)9 HashSet (java.util.HashSet)8 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)7 ProTerritory (games.strategy.triplea.ai.pro.data.ProTerritory)6 UnitType (games.strategy.engine.data.UnitType)5 ProBattleResult (games.strategy.triplea.ai.pro.data.ProBattleResult)5 CompositeChange (games.strategy.engine.data.CompositeChange)4 Resource (games.strategy.engine.data.Resource)4 ProOtherMoveOptions (games.strategy.triplea.ai.pro.data.ProOtherMoveOptions)4 PlayerAttachment (games.strategy.triplea.attachments.PlayerAttachment)4 IntegerMap (games.strategy.util.IntegerMap)4 RelationshipTracker (games.strategy.engine.data.RelationshipTracker)3 ProPlaceTerritory (games.strategy.triplea.ai.pro.data.ProPlaceTerritory)3 ProPurchaseTerritory (games.strategy.triplea.ai.pro.data.ProPurchaseTerritory)3