Search in sources :

Example 1 with MustMoveWithDetails

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

the class MovePanel method getTransportsToLoad.

/**
 * Allow the user to select what transports to load.
 * If null is returned, the move should be canceled.
 */
private Collection<Unit> getTransportsToLoad(final Route route, final Collection<Unit> unitsToLoad, final boolean disablePrompts) {
    if (!route.isLoad()) {
        return Collections.emptyList();
    }
    if (unitsToLoad.stream().anyMatch(Matches.unitIsAir())) {
        return Collections.emptyList();
    }
    final Collection<Unit> endOwnedUnits = route.getEnd().getUnits().getUnits();
    final PlayerID unitOwner = getUnitOwner(unitsToLoad);
    final MustMoveWithDetails endMustMoveWith = MoveValidator.getMustMoveWith(route.getEnd(), endOwnedUnits, dependentUnits, getData(), unitOwner);
    int minTransportCost = defaultMinTransportCost;
    for (final Unit unit : unitsToLoad) {
        minTransportCost = Math.min(minTransportCost, UnitAttachment.get(unit.getType()).getTransportCost());
    }
    final Predicate<Unit> candidateTransportsMatch = Matches.unitIsTransport().and(Matches.alliedUnit(unitOwner, getGameData()));
    final List<Unit> candidateTransports = CollectionUtils.getMatches(endOwnedUnits, candidateTransportsMatch);
    // remove transports that don't have enough capacity
    final Iterator<Unit> transportIter = candidateTransports.iterator();
    while (transportIter.hasNext()) {
        final Unit transport = transportIter.next();
        final int capacity = TransportTracker.getAvailableCapacity(transport);
        if (capacity < minTransportCost) {
            transportIter.remove();
        }
    }
    // nothing to choose
    if (candidateTransports.isEmpty()) {
        return Collections.emptyList();
    }
    // sort transports in preferred load order
    sortTransportsToLoad(candidateTransports, route);
    final List<Unit> availableUnits = new ArrayList<>(unitsToLoad);
    final IntegerMap<Unit> availableCapacityMap = new IntegerMap<>();
    for (final Unit transport : candidateTransports) {
        final int capacity = TransportTracker.getAvailableCapacity(transport);
        availableCapacityMap.put(transport, capacity);
    }
    final Set<Unit> defaultSelections = new HashSet<>();
    // Algorithm to choose defaultSelections (transports to load)
    // We are trying to determine which transports are the best defaults to select for loading,
    // and so we need a modified algorithm based strictly on candidateTransports order:
    // - owned, capable transports are chosen first; attempt to fill them
    // - allied, capable transports are chosen next; attempt to fill them
    // - finally, incapable transports are chosen last (will generate errors)
    // Note that if any allied transports qualify as defaults, we will always prompt with a
    // UnitChooser later on so that it is obvious to the player.
    boolean useAlliedTransports = false;
    final Collection<Unit> capableTransports = new ArrayList<>(candidateTransports);
    // only allow incapable transports for updateUnitsThatCanMoveOnRoute
    // so that we can have a nice UI error shown if these transports
    // are selected, since it may not be obvious
    final Collection<Unit> incapableTransports = CollectionUtils.getMatches(capableTransports, Matches.transportCannotUnload(route.getEnd()));
    capableTransports.removeAll(incapableTransports);
    final Predicate<Unit> alliedMatch = transport -> !transport.getOwner().equals(unitOwner);
    final Collection<Unit> alliedTransports = CollectionUtils.getMatches(capableTransports, alliedMatch);
    capableTransports.removeAll(alliedTransports);
    // First, load capable transports
    final Map<Unit, Unit> unitsToCapableTransports = TransportUtils.mapTransportsToLoadUsingMinTransports(availableUnits, capableTransports);
    for (final Unit unit : unitsToCapableTransports.keySet()) {
        final Unit transport = unitsToCapableTransports.get(unit);
        final int unitCost = UnitAttachment.get(unit.getType()).getTransportCost();
        availableCapacityMap.add(transport, (-1 * unitCost));
        defaultSelections.add(transport);
    }
    availableUnits.removeAll(unitsToCapableTransports.keySet());
    // Next, load allied transports
    final Map<Unit, Unit> unitsToAlliedTransports = TransportUtils.mapTransportsToLoadUsingMinTransports(availableUnits, alliedTransports);
    for (final Unit unit : unitsToAlliedTransports.keySet()) {
        final Unit transport = unitsToAlliedTransports.get(unit);
        final int unitCost = UnitAttachment.get(unit.getType()).getTransportCost();
        availableCapacityMap.add(transport, (-1 * unitCost));
        defaultSelections.add(transport);
        useAlliedTransports = true;
    }
    availableUnits.removeAll(unitsToAlliedTransports.keySet());
    // are selected, since it may not be obvious
    if (getSelectedEndpointTerritory() == null) {
        final Map<Unit, Unit> unitsToIncapableTransports = TransportUtils.mapTransportsToLoadUsingMinTransports(availableUnits, incapableTransports);
        for (final Unit unit : unitsToIncapableTransports.keySet()) {
            final Unit transport = unitsToIncapableTransports.get(unit);
            final int unitCost = UnitAttachment.get(unit.getType()).getTransportCost();
            availableCapacityMap.add(transport, (-1 * unitCost));
            defaultSelections.add(transport);
        }
        availableUnits.removeAll(unitsToIncapableTransports.keySet());
    } else {
        candidateTransports.removeAll(incapableTransports);
    }
    // return defaults if we aren't allowed to prompt
    if (disablePrompts) {
        return defaultSelections;
    }
    // force UnitChooser to pop up if we are choosing allied transports
    if (!useAlliedTransports) {
        if (candidateTransports.size() == 1) {
            return candidateTransports;
        }
        // all the same type, dont ask unless we have more than 1 unit type
        if (UnitSeperator.categorize(candidateTransports, endMustMoveWith.getMustMoveWith(), true, false).size() == 1 && unitsToLoad.size() == 1) {
            return candidateTransports;
        }
        // Players will need to load incrementally in such cases.
        if (defaultSelections.containsAll(candidateTransports)) {
            return candidateTransports;
        }
    }
    // the match criteria to ensure that chosen transports will match selected units
    final Predicate<Collection<Unit>> transportsToLoadMatch = units -> {
        final Collection<Unit> transports = CollectionUtils.getMatches(units, Matches.unitIsTransport());
        // prevent too many transports from being selected
        return (transports.size() <= Math.min(unitsToLoad.size(), candidateTransports.size()));
    };
    final UnitChooser chooser = new UnitChooser(candidateTransports, defaultSelections, endMustMoveWith.getMustMoveWith(), /* categorizeMovement */
    true, /* categorizeTransportCost */
    false, /* allowTwoHit */
    false, getMap().getUiContext(), transportsToLoadMatch);
    chooser.setTitle("What transports do you want to load");
    final int option = JOptionPane.showOptionDialog(getTopLevelAncestor(), chooser, "What transports do you want to load", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE, null, null, null);
    if (option != JOptionPane.OK_OPTION) {
        return Collections.emptyList();
    }
    return chooser.getSelected(false);
}
Also used : IntegerMap(games.strategy.util.IntegerMap) BaseEditDelegate(games.strategy.triplea.delegate.BaseEditDelegate) KeyListener(java.awt.event.KeyListener) GameStepPropertiesHelper(games.strategy.triplea.delegate.GameStepPropertiesHelper) UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) Point(java.awt.Point) HashMap(java.util.HashMap) TechAttachment(games.strategy.triplea.attachments.TechAttachment) PredicateBuilder(games.strategy.util.PredicateBuilder) Properties(games.strategy.triplea.Properties) UnitSeperator(games.strategy.triplea.util.UnitSeperator) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Route(games.strategy.engine.data.Route) TransportTracker(games.strategy.triplea.delegate.TransportTracker) UnitCategory(games.strategy.triplea.util.UnitCategory) MoveValidator(games.strategy.triplea.delegate.MoveValidator) Map(java.util.Map) MoveType(games.strategy.triplea.delegate.AbstractMoveDelegate.MoveType) UnitType(games.strategy.engine.data.UnitType) TripleAUnit(games.strategy.triplea.TripleAUnit) LinkedHashSet(java.util.LinkedHashSet) CollectionUtils(games.strategy.util.CollectionUtils) IntegerMap(games.strategy.util.IntegerMap) Unit(games.strategy.engine.data.Unit) Iterator(java.util.Iterator) Image(java.awt.Image) Predicate(java.util.function.Predicate) Collection(java.util.Collection) UnitComparator(games.strategy.triplea.delegate.UnitComparator) Set(java.util.Set) Territory(games.strategy.engine.data.Territory) KeyEvent(java.awt.event.KeyEvent) JOptionPane(javax.swing.JOptionPane) MouseEvent(java.awt.event.MouseEvent) ClientLogger(games.strategy.debug.ClientLogger) GameData(games.strategy.engine.data.GameData) MoveDescription(games.strategy.triplea.delegate.dataObjects.MoveDescription) List(java.util.List) PlayerID(games.strategy.engine.data.PlayerID) Matches(games.strategy.triplea.delegate.Matches) MoveValidationResult(games.strategy.triplea.delegate.dataObjects.MoveValidationResult) AbstractMoveDelegate(games.strategy.triplea.delegate.AbstractMoveDelegate) Comparator(java.util.Comparator) Collections(java.util.Collections) MustMoveWithDetails(games.strategy.triplea.delegate.dataObjects.MustMoveWithDetails) TransportUtils(games.strategy.triplea.util.TransportUtils) PlayerID(games.strategy.engine.data.PlayerID) ArrayList(java.util.ArrayList) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) Point(java.awt.Point) Collection(java.util.Collection) MustMoveWithDetails(games.strategy.triplea.delegate.dataObjects.MustMoveWithDetails) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet)

Aggregations

ClientLogger (games.strategy.debug.ClientLogger)1 GameData (games.strategy.engine.data.GameData)1 PlayerID (games.strategy.engine.data.PlayerID)1 Route (games.strategy.engine.data.Route)1 Territory (games.strategy.engine.data.Territory)1 Unit (games.strategy.engine.data.Unit)1 UnitType (games.strategy.engine.data.UnitType)1 Properties (games.strategy.triplea.Properties)1 TripleAUnit (games.strategy.triplea.TripleAUnit)1 TechAttachment (games.strategy.triplea.attachments.TechAttachment)1 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)1 AbstractMoveDelegate (games.strategy.triplea.delegate.AbstractMoveDelegate)1 MoveType (games.strategy.triplea.delegate.AbstractMoveDelegate.MoveType)1 BaseEditDelegate (games.strategy.triplea.delegate.BaseEditDelegate)1 GameStepPropertiesHelper (games.strategy.triplea.delegate.GameStepPropertiesHelper)1 Matches (games.strategy.triplea.delegate.Matches)1 MoveValidator (games.strategy.triplea.delegate.MoveValidator)1 TransportTracker (games.strategy.triplea.delegate.TransportTracker)1 UnitComparator (games.strategy.triplea.delegate.UnitComparator)1 MoveDescription (games.strategy.triplea.delegate.dataObjects.MoveDescription)1