use of games.strategy.engine.data.Territory 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;
}
use of games.strategy.engine.data.Territory in project triplea by triplea-game.
the class AbstractPlaceDelegate method getListedTerritories.
protected Collection<Territory> getListedTerritories(final String[] list) {
final List<Territory> territories = new ArrayList<>();
if (list == null) {
return territories;
}
for (final String name : list) {
// Validate all territories exist
final Territory territory = getData().getMap().getTerritory(name);
if (territory == null) {
throw new IllegalStateException("Rules & Conditions: No territory called:" + name);
}
territories.add(territory);
}
return territories;
}
use of games.strategy.engine.data.Territory in project triplea by triplea-game.
the class AbstractPlaceDelegate method getCanAllUnitsWithRequiresUnitsBePlacedCorrectly.
private boolean getCanAllUnitsWithRequiresUnitsBePlacedCorrectly(final Collection<Unit> units, final Territory to) {
if (!isUnitPlacementRestrictions() || units.stream().noneMatch(Matches.unitRequiresUnitsOnCreation())) {
return true;
}
final IntegerMap<Territory> producersMap = getMaxUnitsToBePlacedMap(units, to, player, true);
final List<Territory> producers = getAllProducers(to, player, units);
if (producers.isEmpty()) {
return false;
}
producers.sort(getBestProducerComparator(to, units, player));
final Collection<Unit> unitsLeftToPlace = new ArrayList<>(units);
for (final Territory t : producers) {
if (unitsLeftToPlace.isEmpty()) {
return true;
}
final int productionHere = producersMap.getInt(t);
final List<Unit> canBePlacedHere = CollectionUtils.getMatches(unitsLeftToPlace, unitWhichRequiresUnitsHasRequiredUnits(t, true));
if (productionHere == -1 || productionHere >= canBePlacedHere.size()) {
unitsLeftToPlace.removeAll(canBePlacedHere);
continue;
}
canBePlacedHere.sort(getHardestToPlaceWithRequiresUnitsRestrictions(true));
final Collection<Unit> placedHere = CollectionUtils.getNMatches(canBePlacedHere, productionHere, Matches.always());
unitsLeftToPlace.removeAll(placedHere);
}
return unitsLeftToPlace.isEmpty();
}
use of games.strategy.engine.data.Territory in project triplea by triplea-game.
the class AirBattle method queryRetreat.
private void queryRetreat(final boolean defender, final IDelegateBridge bridge, final Collection<Territory> availableTerritories) {
if (availableTerritories.isEmpty()) {
return;
}
final Collection<Unit> units = defender ? new ArrayList<>(m_defendingUnits) : new ArrayList<>(m_attackingUnits);
if (units.isEmpty()) {
return;
}
final PlayerID retreatingPlayer = defender ? m_defender : m_attacker;
final String text = retreatingPlayer.getName() + " retreat?";
final String step = defender ? DEFENDERS_WITHDRAW : ATTACKERS_WITHDRAW;
getDisplay(bridge).gotoBattleStep(m_battleID, step);
final Territory retreatTo = getRemote(retreatingPlayer, bridge).retreatQuery(m_battleID, false, m_battleSite, availableTerritories, text);
if (retreatTo != null && !availableTerritories.contains(retreatTo)) {
System.err.println("Invalid retreat selection :" + retreatTo + " not in " + MyFormatter.defaultNamedToTextList(availableTerritories));
Thread.dumpStack();
return;
}
if (retreatTo != null) {
if (!m_headless) {
bridge.getSoundChannelBroadcaster().playSoundForAll(SoundPath.CLIP_BATTLE_RETREAT_AIR, m_attacker);
}
retreat(units, defender, bridge);
final String messageShort = retreatingPlayer.getName() + " retreats";
final String messageLong = retreatingPlayer.getName() + " retreats all units to " + retreatTo.getName();
getDisplay(bridge).notifyRetreat(messageShort, messageLong, step, retreatingPlayer);
}
}
use of games.strategy.engine.data.Territory in project triplea by triplea-game.
the class AirMovementValidator method validateAirCaughtByMovingCarriersAndOwnedAndAlliedAir.
private static void validateAirCaughtByMovingCarriersAndOwnedAndAlliedAir(final MoveValidationResult result, final List<Territory> landingSpots, final Collection<Territory> potentialCarrierOrigins, final Map<Unit, Collection<Unit>> movedCarriersAndTheirFighters, final Collection<Unit> airThatMustLandOnCarriers, final Collection<Unit> airNotToConsider, final PlayerID player, final Route route, final GameData data) {
final Predicate<Unit> ownedCarrierMatch = Matches.unitIsOwnedBy(player).and(Matches.unitIsCarrier());
final Predicate<Unit> ownedAirMatch = Matches.unitIsOwnedBy(player).and(Matches.unitIsAir()).and(Matches.unitCanLandOnCarrier());
final Predicate<Unit> alliedNotOwnedAirMatch = Matches.unitIsOwnedBy(player).negate().and(Matches.isUnitAllied(player, data)).and(Matches.unitIsAir()).and(Matches.unitCanLandOnCarrier());
final Predicate<Unit> alliedNotOwnedCarrierMatch = Matches.unitIsOwnedBy(player).negate().and(Matches.isUnitAllied(player, data)).and(Matches.unitIsCarrier());
final Territory routeEnd = route.getEnd();
final boolean areNeutralsPassableByAir = areNeutralsPassableByAir(data);
final IntegerMap<Territory> landingSpotsWithCarrierCapacity = // fill our landing spot capacity with capacity from allied carriers and potential building of new carriers
populateStaticAlliedAndBuildingCarrierCapacity(landingSpots, movedCarriersAndTheirFighters, player, data);
final LinkedHashMap<Unit, Integer> movementLeftForAirToValidate = // calculate movement left only once
getMovementLeftForValidatingAir(airThatMustLandOnCarriers, player, route);
for (final Territory landingSpot : landingSpots) {
// since we are here, no point looking at this place twice
potentialCarrierOrigins.remove(landingSpot);
final List<Unit> airCanReach = new ArrayList<>();
for (final Unit air : airThatMustLandOnCarriers) {
if (canAirReachThisSpot(data, player, air, routeEnd, movementLeftForAirToValidate.get(air), landingSpot, areNeutralsPassableByAir)) {
// get all air that can reach this spot
airCanReach.add(air);
}
}
if (airCanReach.isEmpty()) {
continue;
}
final Collection<Unit> unitsInLandingSpot = landingSpot.getUnits().getUnits();
unitsInLandingSpot.removeAll(movedCarriersAndTheirFighters.keySet());
// make sure to remove any units we have already moved, or units that are excluded
unitsInLandingSpot.removeAll(airNotToConsider);
// because they are in our mouse selection
for (final Collection<Unit> ftrs : movedCarriersAndTheirFighters.values()) {
// also remove any fighters that are being moved with carriers that we have already moved
unitsInLandingSpot.removeAll(ftrs);
}
final Collection<Unit> ownedCarriersInLandingSpot = CollectionUtils.getMatches(unitsInLandingSpot, ownedCarrierMatch);
// get air we own here, but exclude any air that can fly to allied land
final Collection<Unit> airInLandingSpot = CollectionUtils.getMatches(CollectionUtils.getMatches(unitsInLandingSpot, ownedAirMatch), unitCanFindLand(data, landingSpot).negate());
// add allied air (it can't fly away)
airInLandingSpot.addAll(CollectionUtils.getMatches(unitsInLandingSpot, alliedNotOwnedAirMatch));
// make sure we don't count this again
// airNotToConsider.addAll(airInLandingSpot);
// get the current capacity
int landingSpotCapacity = landingSpotsWithCarrierCapacity.getInt(landingSpot);
// add capacity of owned carriers
landingSpotCapacity += carrierCapacity(ownedCarriersInLandingSpot, landingSpot);
// minus capacity of air in the territory
landingSpotCapacity -= carrierCost(airInLandingSpot);
if (!airCanReach.isEmpty()) {
final Iterator<Unit> airIter = airCanReach.iterator();
while (airIter.hasNext()) {
final Unit air = airIter.next();
final int carrierCost = carrierCost(air);
if (landingSpotCapacity >= carrierCost) {
landingSpotCapacity -= carrierCost;
// we can land this one here, yay
airThatMustLandOnCarriers.remove(air);
airIter.remove();
}
}
}
if (airThatMustLandOnCarriers.isEmpty()) {
// all can land here, so return
return;
}
// final int lowestCarrierCost = getLowestCarrierCost(airCanReach);
// now bring carriers here...
final Iterator<Territory> iter = potentialCarrierOrigins.iterator();
while (iter.hasNext()) {
final Territory carrierSpot = iter.next();
final Collection<Unit> unitsInCarrierSpot = carrierSpot.getUnits().getUnits();
// remove carriers we have already moved
unitsInCarrierSpot.removeAll(movedCarriersAndTheirFighters.keySet());
// remove units we do not want to consider because they are in our mouse selection
unitsInCarrierSpot.removeAll(airNotToConsider);
for (final Collection<Unit> ftrs : movedCarriersAndTheirFighters.values()) {
// remove the fighters that are moving with the carriers we have already moved
unitsInCarrierSpot.removeAll(ftrs);
}
final Collection<Unit> ownedCarriersInCarrierSpot = CollectionUtils.getMatches(unitsInCarrierSpot, ownedCarrierMatch);
if (ownedCarriersInCarrierSpot.isEmpty()) {
iter.remove();
continue;
}
final Collection<Unit> ownedAirInCarrierSpot = CollectionUtils.getMatches(// exclude any owned air that can fly to land
CollectionUtils.getMatches(unitsInCarrierSpot, ownedAirMatch), unitCanFindLand(data, carrierSpot).negate());
final Collection<Unit> alliedNotOwnedAirInCarrierSpot = CollectionUtils.getMatches(unitsInCarrierSpot, alliedNotOwnedAirMatch);
final Map<Unit, Collection<Unit>> mustMoveWithMap = // this only returns the allied cargo
MoveValidator.carrierMustMoveWith(ownedCarriersInCarrierSpot, carrierSpot, data, player);
// planes that MUST travel with the carrier
// get the current capacity for the carrier spot
int carrierSpotCapacity = landingSpotsWithCarrierCapacity.getInt(carrierSpot);
// we don't have it because this spot is not in the landing zone area.
if (!landingSpotsWithCarrierCapacity.containsKey(carrierSpot)) {
// we still have a capacity for allied carriers, but only to carry other allied or local owned units, not to
// carry our selected
// units.
carrierSpotCapacity = carrierCapacity(carrierSpot.getUnits().getMatches(alliedNotOwnedCarrierMatch), carrierSpot);
landingSpotsWithCarrierCapacity.put(carrierSpot, carrierSpotCapacity);
}
// we have allied air here, so we need to account for them before moving any carriers
if (!alliedNotOwnedAirInCarrierSpot.isEmpty() || !mustMoveWithMap.isEmpty()) {
// them
if (mustMoveWithMap.isEmpty()) {
// allied carriers can carry enough
carrierSpotCapacity -= carrierCost(alliedNotOwnedAirInCarrierSpot);
// we do not want to consider these units again
airNotToConsider.addAll(alliedNotOwnedAirInCarrierSpot);
if (carrierSpotCapacity > 0) {
// we can hold some of the owned air here too
final Iterator<Unit> ownedIter = ownedAirInCarrierSpot.iterator();
while (ownedIter.hasNext()) {
final Unit air = ownedIter.next();
final int carrierCost = carrierCost(air);
if (carrierSpotCapacity >= carrierCost) {
carrierSpotCapacity -= carrierCost;
// we do not want to consider this one again
airNotToConsider.add(air);
ownedIter.remove();
}
}
}
// put correct value for future reference now that we
// have considered the allied air
landingSpotsWithCarrierCapacity.put(carrierSpot, carrierSpotCapacity);
} else {
// carrierMustMoveWith does not account for any allied cargo already moved out.
for (final Collection<Unit> airMovingWith : mustMoveWithMap.values()) {
for (final Collection<Unit> ftrs : movedCarriersAndTheirFighters.values()) {
// remove the fighters that are moving with the carriers we have already moved
airMovingWith.removeAll(ftrs);
}
}
for (final Collection<Unit> airMovingWith : mustMoveWithMap.values()) {
// we will consider these as part of their moving carrier
alliedNotOwnedAirInCarrierSpot.removeAll(airMovingWith);
}
carrierSpotCapacity -= carrierCost(alliedNotOwnedAirInCarrierSpot);
// we do not want to consider these units again
airNotToConsider.addAll(alliedNotOwnedAirInCarrierSpot);
// put correct value for future reference now that we
// have considered the allied air
landingSpotsWithCarrierCapacity.put(carrierSpot, carrierSpotCapacity);
}
}
final Route toLandingSpot = data.getMap().getRoute(carrierSpot, landingSpot, Matches.seaCanMoveOver(player, data));
if (toLandingSpot == null) {
continue;
}
final List<Unit> carrierCanReach = CollectionUtils.getMatches(ownedCarriersInCarrierSpot, Matches.unitHasEnoughMovementForRoute(toLandingSpot));
if (carrierCanReach.isEmpty()) {
// none can reach
continue;
}
final List<Unit> carrierNotReach = new ArrayList<>(ownedCarriersInCarrierSpot);
// we want to see if the air units can be put on the carriers that cannot make it
// first, before taking up room on the carriers that can make it
carrierNotReach.removeAll(carrierCanReach);
final List<Unit> allCarriers = new ArrayList<>(carrierNotReach);
// so we remove them from the list then re-add them so that they will be at the end of the list
allCarriers.addAll(carrierCanReach);
// now we want to make a map of the carriers to the units they must carry with them (both allied and owned)
final Map<Unit, Collection<Unit>> carriersToMove = new HashMap<>();
final List<Unit> carrierFull = new ArrayList<>();
for (final Unit carrier : allCarriers) {
final Collection<Unit> airMovingWith = new ArrayList<>();
// first add allied cargo
final Collection<Unit> alliedMovingWith = mustMoveWithMap.get(carrier);
if (alliedMovingWith != null) {
airMovingWith.addAll(alliedMovingWith);
}
// now test if our carrier has any room for owned fighters
int carrierCapacity = carrierCapacity(carrier, carrierSpot);
carrierCapacity -= carrierCost(airMovingWith);
final Iterator<Unit> ownedIter = ownedAirInCarrierSpot.iterator();
while (ownedIter.hasNext()) {
final Unit air = ownedIter.next();
final int carrierCost = carrierCost(air);
if (carrierCapacity >= carrierCost) {
carrierCapacity -= carrierCost;
airMovingWith.add(air);
ownedIter.remove();
}
}
carriersToMove.put(carrier, airMovingWith);
if (carrierCapacity <= 0) {
carrierFull.add(carrier);
}
}
// if all carriers full, remove this carrier spot from consideration
if (carrierFull.containsAll(allCarriers)) {
iter.remove();
continue;
}
if (carrierFull.containsAll(carrierNotReach)) {
iter.remove();
}
// ok, now lets move them.
for (final Unit carrier : carrierCanReach) {
movedCarriersAndTheirFighters.put(carrier, carriersToMove.get(carrier));
landingSpotCapacity += carrierCapacity(carrier, carrierSpot);
landingSpotCapacity -= carrierCost(carriersToMove.get(carrier));
}
// optional for debugging
final Iterator<Unit> reachIter = airCanReach.iterator();
while (reachIter.hasNext()) {
final Unit air = reachIter.next();
final int carrierCost = carrierCost(air);
if (landingSpotCapacity >= carrierCost) {
landingSpotCapacity -= carrierCost;
// we can land this one here, yay
airThatMustLandOnCarriers.remove(air);
reachIter.remove();
}
}
if (airThatMustLandOnCarriers.isEmpty()) {
// all can land here, so return
return;
}
}
}
// anyone left over cannot land
for (final Unit air : airThatMustLandOnCarriers) {
result.addDisallowedUnit(NOT_ALL_AIR_UNITS_CAN_LAND, air);
}
}
Aggregations