package games.strategy.triplea.delegate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.Territory;
import games.strategy.engine.data.Unit;
import games.strategy.engine.data.UnitType;
import games.strategy.triplea.MapSupport;
import games.strategy.triplea.attachments.PlayerAttachment;
import games.strategy.triplea.attachments.UnitAttachment;
import games.strategy.util.CompositeMatch;
import games.strategy.util.CompositeMatchAnd;
import games.strategy.util.IntegerMap;
import games.strategy.util.Match;
@MapSupport
public class BidPlaceDelegate extends AbstractPlaceDelegate {
public BidPlaceDelegate() {}
// Allow production of any number of units
@Override
protected String checkProduction(final Territory to, final Collection<Unit> units, final PlayerID player) {
return null;
}
// Return whether we can place bid in a certain territory
@Override
protected String canProduce(final Territory to, final Collection<Unit> units, final PlayerID player) {
return canProduce(to, to, units, player);
}
@Override
protected String canProduce(final Territory producer, final Territory to, final Collection<Unit> units,
final PlayerID player) {
// we can place if no enemy units and its water
if (to.isWater()) {
if (Match.someMatch(units, Matches.UnitIsLand)) {
return "Cant place land units at sea";
} else if (to.getUnits().someMatch(Matches.enemyUnit(player, getData()))) {
return "Cant place in sea zone containing enemy units";
} else if (!to.getUnits().someMatch(Matches.unitIsOwnedBy(player))) {
return "Cant place in sea zone that does not contain a unit owned by you";
} else {
return null;
}
} else {
// we can place on territories we own
if (Match.someMatch(units, Matches.UnitIsSea)) {
return "Cant place sea units on land";
} else if (to.getOwner() == null) {
return "You dont own " + to.getName();
} else if (!to.getOwner().equals(player)) {
final PlayerAttachment pa = PlayerAttachment.get(to.getOwner());
if (pa != null && pa.getGiveUnitControl() != null && pa.getGiveUnitControl().contains(player)) {
return null;
} else if (to.getUnits().someMatch(Matches.unitIsOwnedBy(player))) {
return null;
}
return "You dont own " + to.getName();
} else {
return null;
}
}
}
@Override
protected List<Territory> getAllProducers(final Territory to, final PlayerID player,
final Collection<Unit> unitsToPlace) {
final List<Territory> producers = new ArrayList<>();
producers.add(to);
return producers;
}
@Override
protected int getMaxUnitsToBePlaced(final Collection<Unit> units, final Territory to, final PlayerID player,
final boolean countSwitchedProductionToNeighbors) {
if (units == null) {
return -1;
}
return units.size();
}
@Override
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) {
if (units == null) {
return -1;
}
return units.size();
}
@Override
protected int getMaxUnitsToBePlacedFrom(final Territory producer, final Collection<Unit> units, final Territory to,
final PlayerID player) {
if (units == null) {
return -1;
}
return getMaxUnitsToBePlacedFrom(producer, units, to, player, false, null, null);
}
// Allow player to place as many units as they want in bid phase
protected int getMaxUnitsToBePlaced(final Territory to, final PlayerID player) {
return -1;
}
// Return collection of bid units which can placed in a land territory
@Override
protected Collection<Unit> getUnitsToBePlacedLand(final Territory to, final Collection<Unit> units,
final PlayerID player) {
final Collection<Unit> unitsAtStartOfTurnInTO = unitsAtStartOfStepInTerritory(to);
final Collection<Unit> placeableUnits = new ArrayList<>();
final CompositeMatch<Unit> groundUnits =
// we add factories and constructions later
new CompositeMatchAnd<>(Matches.UnitIsLand, Matches.UnitIsNotConstruction);
final CompositeMatch<Unit> airUnits = new CompositeMatchAnd<>(Matches.UnitIsAir, Matches.UnitIsNotConstruction);
placeableUnits.addAll(Match.getMatches(units, groundUnits));
placeableUnits.addAll(Match.getMatches(units, airUnits));
if (Match.someMatch(units, Matches.UnitIsConstruction)) {
final IntegerMap<String> constructionsMap = howManyOfEachConstructionCanPlace(to, to, units, player);
final Collection<Unit> skipUnit = new ArrayList<>();
for (final Unit currentUnit : Match.getMatches(units, Matches.UnitIsConstruction)) {
final int maxUnits = howManyOfConstructionUnit(currentUnit, constructionsMap);
if (maxUnits > 0) {
// we are doing this because we could have multiple unitTypes with the same constructionType, so we have to be
// able to place the
// max placement by constructionType of each unitType
if (skipUnit.contains(currentUnit)) {
continue;
}
placeableUnits.addAll(Match.getNMatches(units, maxUnits, Matches.unitIsOfType(currentUnit.getType())));
skipUnit.addAll(Match.getMatches(units, Matches.unitIsOfType(currentUnit.getType())));
}
}
}
// remove any units that require other units to be consumed on creation (veqryn)
if (Match.someMatch(placeableUnits, Matches.UnitConsumesUnitsOnCreation)) {
final Collection<Unit> unitsWhichConsume = Match.getMatches(placeableUnits, Matches.UnitConsumesUnitsOnCreation);
for (final Unit unit : unitsWhichConsume) {
if (Matches.UnitWhichConsumesUnitsHasRequiredUnits(unitsAtStartOfTurnInTO).invert().match(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(Match.getNMatches(placeableUnits, UnitAttachment.getMaximumNumberOfThisUnitTypeToReachStackingLimit(
"placementLimit", ut, to, player, getData()), Matches.unitIsOfType(ut)));
}
return placeableUnits2;
}
}