Search in sources :

Example 1 with UnitCategory

use of games.strategy.triplea.util.UnitCategory in project triplea by triplea-game.

the class BattleCalculator method categorizeLowLuckAirUnits.

/**
 * http://triplea.sourceforge.net/mywiki/Forum#nabble-td4658925%7Ca4658925
 * returns two lists, the first list is the air units that can be evenly divided into groups of 3 or 6 (depending on
 * radar)
 * the second list is all the air units that do not fit in the first list
 */
private static Tuple<List<List<Unit>>, List<Unit>> categorizeLowLuckAirUnits(final Collection<Unit> units, final int groupSize) {
    final Collection<UnitCategory> categorizedAir = UnitSeperator.categorize(units, null, false, true);
    final List<List<Unit>> groupsOfSize = new ArrayList<>();
    final List<Unit> toRoll = new ArrayList<>();
    for (final UnitCategory uc : categorizedAir) {
        final int remainder = uc.getUnits().size() % groupSize;
        final int splitPosition = uc.getUnits().size() - remainder;
        final List<Unit> group = new ArrayList<>(uc.getUnits().subList(0, splitPosition));
        if (!group.isEmpty()) {
            for (int i = 0; i < splitPosition; i += groupSize) {
                final List<Unit> miniGroup = new ArrayList<>(uc.getUnits().subList(i, i + groupSize));
                if (!miniGroup.isEmpty()) {
                    groupsOfSize.add(miniGroup);
                }
            }
        }
        toRoll.addAll(uc.getUnits().subList(splitPosition, uc.getUnits().size()));
    }
    return Tuple.of(groupsOfSize, toRoll);
}
Also used : ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) CasualtyList(games.strategy.triplea.delegate.dataObjects.CasualtyList) List(java.util.List) Unit(games.strategy.engine.data.Unit) UnitCategory(games.strategy.triplea.util.UnitCategory)

Example 2 with UnitCategory

use of games.strategy.triplea.util.UnitCategory in project triplea by triplea-game.

the class MoveValidator method validateTransport.

private static MoveValidationResult validateTransport(final boolean isNonCombat, final GameData data, final List<UndoableMove> undoableMoves, final Collection<Unit> units, final Route route, final PlayerID player, final Collection<Unit> transportsToLoad, final MoveValidationResult result) {
    final boolean isEditMode = getEditMode(data);
    if (!units.isEmpty() && units.stream().allMatch(Matches.unitIsAir())) {
        return result;
    }
    if (!route.hasWater()) {
        return result;
    }
    // If there are non-sea transports return
    final boolean seaOrNoTransportsPresent = transportsToLoad.isEmpty() || transportsToLoad.stream().anyMatch(Matches.unitIsSea().and(Matches.unitCanTransport()));
    if (!seaOrNoTransportsPresent) {
        return result;
    }
    final Territory routeEnd = route.getEnd();
    final Territory routeStart = route.getStart();
    // if unloading make sure length of route is only 1
    if (!isEditMode && route.isUnload()) {
        if (route.hasMoreThenOneStep()) {
            return result.setErrorReturnResult("Unloading units must stop where they are unloaded");
        }
        for (final Unit unit : TransportTracker.getUnitsLoadedOnAlliedTransportsThisTurn(units)) {
            result.addDisallowedUnit(CANNOT_LOAD_AND_UNLOAD_AN_ALLIED_TRANSPORT_IN_THE_SAME_ROUND, unit);
        }
        final Collection<Unit> transports = TransportUtils.mapTransports(route, units, null).values();
        final boolean isScramblingOrKamikazeAttacksEnabled = Properties.getScrambleRulesInEffect(data) || Properties.getUseKamikazeSuicideAttacks(data);
        final boolean submarinesPreventUnescortedAmphibAssaults = Properties.getSubmarinesPreventUnescortedAmphibiousAssaults(data);
        final Predicate<Unit> enemySubmarineMatch = Matches.unitIsEnemyOf(data, player).and(Matches.unitIsSub());
        final Predicate<Unit> ownedSeaNonTransportMatch = Matches.unitIsOwnedBy(player).and(Matches.unitIsSea()).and(Matches.unitIsNotTransportButCouldBeCombatTransport());
        for (final Unit transport : transports) {
            if (!isNonCombat && route.numberOfStepsIncludingStart() == 2) {
                if (Matches.territoryHasEnemyUnits(player, data).test(routeEnd) || Matches.isTerritoryEnemyAndNotUnownedWater(player, data).test(routeEnd)) {
                    // this is an amphibious assault
                    if (submarinesPreventUnescortedAmphibAssaults && !Matches.territoryHasUnitsThatMatch(ownedSeaNonTransportMatch).test(routeStart) && Matches.territoryHasUnitsThatMatch(enemySubmarineMatch).test(routeStart)) {
                        // stops our unloading for amphibious assault
                        for (final Unit unit : TransportTracker.transporting(transport)) {
                            result.addDisallowedUnit(ENEMY_SUBMARINE_PREVENTING_UNESCORTED_AMPHIBIOUS_ASSAULT_LANDING, unit);
                        }
                    }
                } else if (!AbstractMoveDelegate.getBattleTracker(data).wasConquered(routeEnd)) {
                    // this is an unload to a friendly territory
                    if (isScramblingOrKamikazeAttacksEnabled || !Matches.territoryIsEmptyOfCombatUnits(data, player).test(routeStart)) {
                        // TODO: should we use the battle tracker for this instead?
                        for (final Unit unit : TransportTracker.transporting(transport)) {
                            result.addDisallowedUnit(TRANSPORT_MAY_NOT_UNLOAD_TO_FRIENDLY_TERRITORIES_UNTIL_AFTER_COMBAT_IS_RESOLVED, unit);
                        }
                    }
                }
            }
            // in which they perform their actions. check whether transport has already unloaded
            if (TransportTracker.hasTransportUnloadedInPreviousPhase(transport)) {
                for (final Unit unit : TransportTracker.transporting(transport)) {
                    result.addDisallowedUnit(TRANSPORT_HAS_ALREADY_UNLOADED_UNITS_IN_A_PREVIOUS_PHASE, unit);
                }
            // check whether transport is restricted to another territory
            } else if (TransportTracker.isTransportUnloadRestrictedToAnotherTerritory(transport, route.getEnd())) {
                final Territory alreadyUnloadedTo = getTerritoryTransportHasUnloadedTo(undoableMoves, transport);
                for (final Unit unit : TransportTracker.transporting(transport)) {
                    result.addDisallowedUnit(TRANSPORT_HAS_ALREADY_UNLOADED_UNITS_TO + alreadyUnloadedTo.getName(), unit);
                }
            // Check if the transport has already loaded after being in combat
            } else if (TransportTracker.isTransportUnloadRestrictedInNonCombat(transport)) {
                for (final Unit unit : TransportTracker.transporting(transport)) {
                    result.addDisallowedUnit(TRANSPORT_CANNOT_LOAD_AND_UNLOAD_AFTER_COMBAT, unit);
                }
            }
        }
    }
    // if we are land make sure no water in route except for transport situations
    final Collection<Unit> land = CollectionUtils.getMatches(units, Matches.unitIsLand());
    final Collection<Unit> landAndAir = CollectionUtils.getMatches(units, Matches.unitIsLand().or(Matches.unitIsAir()));
    // make sure we can be transported
    final Predicate<Unit> cantBeTransported = Matches.unitCanBeTransported().negate();
    for (final Unit unit : CollectionUtils.getMatches(land, cantBeTransported)) {
        result.addDisallowedUnit("Not all units can be transported", unit);
    }
    // make sure that the only the first or last territory is land don't want situation where they go sea land sea
    if (!isEditMode && route.hasLand() && !(route.getStart().isWater() || route.getEnd().isWater())) {
        // carried by the air and that the air has enough capacity
        if (nonParatroopersPresent(player, landAndAir)) {
            return result.setErrorReturnResult("Invalid move, only start or end can be land when route has water.");
        }
    }
    // TODO handle this
    if (!isEditMode && !route.getEnd().isWater() && !route.getStart().isWater() && nonParatroopersPresent(player, landAndAir)) {
        return result.setErrorReturnResult("Must stop units at a transport on route");
    }
    if (route.getEnd().isWater() && route.getStart().isWater()) {
        // make sure units and transports stick together
        for (final Unit unit : units) {
            final UnitAttachment ua = UnitAttachment.get(unit.getType());
            // make sure transports dont leave their units behind
            if (ua.getTransportCapacity() != -1) {
                final Collection<Unit> holding = TransportTracker.transporting(unit);
                if (!units.containsAll(holding)) {
                    result.addDisallowedUnit("Transports cannot leave their units", unit);
                }
            }
            // make sure units dont leave their transports behind
            if (ua.getTransportCost() != -1) {
                final Unit transport = TransportTracker.transportedBy(unit);
                if (transport != null && !units.contains(transport)) {
                    result.addDisallowedUnit("Unit must stay with its transport while moving", unit);
                }
            }
        }
    }
    if (route.isLoad()) {
        if (!isEditMode && !route.hasExactlyOneStep() && nonParatroopersPresent(player, landAndAir)) {
            return result.setErrorReturnResult("Units cannot move before loading onto transports");
        }
        final Predicate<Unit> enemyNonSubmerged = Matches.enemyUnit(player, data).and(Matches.unitIsSubmerged().negate());
        if (!Properties.getUnitsCanLoadInHostileSeaZones(data) && route.getEnd().getUnits().anyMatch(enemyNonSubmerged) && nonParatroopersPresent(player, landAndAir) && !onlyIgnoredUnitsOnPath(route, player, data, false) && !AbstractMoveDelegate.getBattleTracker(data).didAllThesePlayersJustGoToWarThisTurn(player, route.getEnd().getUnits().getUnits(), data)) {
            return result.setErrorReturnResult("Cannot load when enemy sea units are present");
        }
        final Map<Unit, Unit> unitsToTransports = TransportUtils.mapTransports(route, land, transportsToLoad);
        if (!isEditMode) {
            for (final Unit baseUnit : land) {
                final TripleAUnit unit = (TripleAUnit) baseUnit;
                if (Matches.unitHasMoved().test(unit)) {
                    result.addDisallowedUnit("Units cannot move before loading onto transports", unit);
                }
                final Unit transport = unitsToTransports.get(unit);
                if (transport == null) {
                    continue;
                }
                if (TransportTracker.hasTransportUnloadedInPreviousPhase(transport)) {
                    result.addDisallowedUnit(TRANSPORT_HAS_ALREADY_UNLOADED_UNITS_IN_A_PREVIOUS_PHASE, unit);
                } else if (TransportTracker.isTransportUnloadRestrictedToAnotherTerritory(transport, route.getEnd())) {
                    Territory alreadyUnloadedTo = getTerritoryTransportHasUnloadedTo(undoableMoves, transport);
                    for (final Unit transportToLoad : transportsToLoad) {
                        final TripleAUnit trn = (TripleAUnit) transportToLoad;
                        if (!TransportTracker.isTransportUnloadRestrictedToAnotherTerritory(trn, route.getEnd())) {
                            final UnitAttachment ua = UnitAttachment.get(unit.getType());
                            if (TransportTracker.getAvailableCapacity(trn) >= ua.getTransportCost()) {
                                alreadyUnloadedTo = null;
                                break;
                            }
                        }
                    }
                    if (alreadyUnloadedTo != null) {
                        result.addDisallowedUnit(TRANSPORT_HAS_ALREADY_UNLOADED_UNITS_TO + alreadyUnloadedTo.getName(), unit);
                    }
                }
            }
        }
        if (!unitsToTransports.keySet().containsAll(land)) {
            // some units didn't get mapped to a transport
            final Collection<UnitCategory> unitsToLoadCategories = UnitSeperator.categorize(land);
            if (unitsToTransports.size() == 0 || unitsToLoadCategories.size() == 1) {
                // set all unmapped units as disallowed if there are no transports or only one unit category
                for (final Unit unit : land) {
                    if (unitsToTransports.containsKey(unit)) {
                        continue;
                    }
                    final UnitAttachment ua = UnitAttachment.get(unit.getType());
                    if (ua.getTransportCost() != -1) {
                        result.addDisallowedUnit("Not enough transports", unit);
                    }
                }
            } else {
                // set all units as unresolved if there is at least one transport and mixed unit categories
                for (final Unit unit : land) {
                    final UnitAttachment ua = UnitAttachment.get(unit.getType());
                    if (ua.getTransportCost() != -1) {
                        result.addUnresolvedUnit("Not enough transports", unit);
                    }
                }
            }
        }
    }
    return result;
}
Also used : UnitAttachment(games.strategy.triplea.attachments.UnitAttachment) Territory(games.strategy.engine.data.Territory) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) TripleAUnit(games.strategy.triplea.TripleAUnit) UnitCategory(games.strategy.triplea.util.UnitCategory)

Example 3 with UnitCategory

use of games.strategy.triplea.util.UnitCategory in project triplea by triplea-game.

the class MapPanel method paint.

@Override
public void paint(final Graphics g) {
    final Graphics2D g2d = (Graphics2D) g;
    super.paint(g2d);
    g2d.clip(new Rectangle2D.Double(0, 0, (getImageWidth() * scale), (getImageHeight() * scale)));
    int x = model.getX();
    int y = model.getY();
    final List<Tile> images = new ArrayList<>();
    final List<Tile> undrawnTiles = new ArrayList<>();
    final Stopwatch stopWatch = new Stopwatch(Logger.getLogger(MapPanel.class.getName()), Level.FINER, "Paint");
    // make sure we use the same data for the entire paint
    final GameData data = gameData;
    // if the map fits on screen, dont draw any overlap
    final boolean fitAxisX = !mapWidthFitsOnScreen() && uiContext.getMapData().scrollWrapX();
    final boolean fitAxisY = !mapHeightFitsOnScreen() && uiContext.getMapData().scrollWrapY();
    if (fitAxisX || fitAxisY) {
        if (fitAxisX && x + (int) getScaledWidth() > model.getMaxWidth()) {
            x -= model.getMaxWidth();
        }
        if (fitAxisY && y + (int) getScaledHeight() > model.getMaxHeight()) {
            y -= model.getMaxHeight();
        }
        // handle wrapping off the screen
        if (fitAxisX && x < 0) {
            if (fitAxisY && y < 0) {
                final Rectangle2D.Double leftUpperBounds = new Rectangle2D.Double(model.getMaxWidth() + x, model.getMaxHeight() + y, -x, -y);
                drawTiles(g2d, images, data, leftUpperBounds, undrawnTiles);
            }
            final Rectangle2D.Double leftBounds = new Rectangle2D.Double(model.getMaxWidth() + x, y, -x, getScaledHeight());
            drawTiles(g2d, images, data, leftBounds, undrawnTiles);
        }
        if (fitAxisY && y < 0) {
            final Rectangle2D.Double upperBounds = new Rectangle2D.Double(x, model.getMaxHeight() + y, getScaledWidth(), -y);
            drawTiles(g2d, images, data, upperBounds, undrawnTiles);
        }
    }
    // handle non overlap
    final Rectangle2D.Double mainBounds = new Rectangle2D.Double(x, y, getScaledWidth(), getScaledHeight());
    drawTiles(g2d, images, data, mainBounds, undrawnTiles);
    if (routeDescription != null && mouseShadowImage != null && routeDescription.getEnd() != null) {
        final AffineTransform t = new AffineTransform();
        t.translate(scale * normalizeX(routeDescription.getEnd().getX() - getXOffset()), scale * normalizeY(routeDescription.getEnd().getY() - getYOffset()));
        t.translate(mouseShadowImage.getWidth() / -2, mouseShadowImage.getHeight() / -2);
        t.scale(scale, scale);
        g2d.drawImage(mouseShadowImage, t, this);
    }
    if (routeDescription != null) {
        routeDrawer.drawRoute(g2d, routeDescription, movementLeftForCurrentUnits, movementFuelCost, uiContext.getResourceImageFactory());
    }
    // used to keep strong references to what is on the screen so it wont be garbage collected
    // other references to the images are weak references
    this.images.clear();
    this.images.addAll(images);
    if (highlightedUnits != null) {
        for (final Entry<Territory, List<Unit>> entry : highlightedUnits.entrySet()) {
            final Set<UnitCategory> categories = UnitSeperator.categorize(entry.getValue());
            for (final UnitCategory category : categories) {
                final List<Unit> territoryUnitsOfSameCategory = category.getUnits();
                if (territoryUnitsOfSameCategory.isEmpty()) {
                    continue;
                }
                final Rectangle r = tileManager.getUnitRect(territoryUnitsOfSameCategory, gameData);
                if (r == null) {
                    continue;
                }
                final Optional<Image> image = uiContext.getUnitImageFactory().getHighlightImage(category.getType(), category.getOwner(), category.hasDamageOrBombingUnitDamage(), category.getDisabled());
                if (image.isPresent()) {
                    final AffineTransform t = new AffineTransform();
                    t.translate(normalizeX(r.getX() - getXOffset()) * scale, normalizeY(r.getY() - getYOffset()) * scale);
                    t.scale(scale, scale);
                    g2d.drawImage(image.get(), t, this);
                }
            }
        }
    }
    // draw the tiles nearest us first
    // then draw farther away
    updateUndrawnTiles(undrawnTiles, 30, true);
    updateUndrawnTiles(undrawnTiles, 257, true);
    // when we are this far away, dont force the tiles to stay in memroy
    updateUndrawnTiles(undrawnTiles, 513, false);
    updateUndrawnTiles(undrawnTiles, 767, false);
    clearPendingDrawOperations();
    undrawnTiles.forEach(tile -> pendingDrawOperations.add(Tuple.of(tile, data)));
    stopWatch.done();
}
Also used : Territory(games.strategy.engine.data.Territory) GameData(games.strategy.engine.data.GameData) Rectangle2D(java.awt.geom.Rectangle2D) ArrayList(java.util.ArrayList) Stopwatch(games.strategy.triplea.util.Stopwatch) Rectangle(java.awt.Rectangle) Tile(games.strategy.triplea.ui.screen.Tile) TripleAUnit(games.strategy.triplea.TripleAUnit) Unit(games.strategy.engine.data.Unit) TimeUnit(java.util.concurrent.TimeUnit) Image(java.awt.Image) BufferedImage(java.awt.image.BufferedImage) Point(java.awt.Point) Graphics2D(java.awt.Graphics2D) AffineTransform(java.awt.geom.AffineTransform) List(java.util.List) ArrayList(java.util.ArrayList) UnitCategory(games.strategy.triplea.util.UnitCategory)

Example 4 with UnitCategory

use of games.strategy.triplea.util.UnitCategory in project triplea by triplea-game.

the class UnitChooser method createDefaultSelectionsMap.

private static IntegerMap<UnitCategory> createDefaultSelectionsMap(final Collection<UnitCategory> categories) {
    final IntegerMap<UnitCategory> defaultValues = new IntegerMap<>();
    for (final UnitCategory category : categories) {
        final int defaultValue = category.getUnits().size();
        defaultValues.put(category, defaultValue);
    }
    return defaultValues;
}
Also used : IntegerMap(games.strategy.util.IntegerMap) UnitCategory(games.strategy.triplea.util.UnitCategory)

Example 5 with UnitCategory

use of games.strategy.triplea.util.UnitCategory in project triplea by triplea-game.

the class TileManagerTest method testGetSortedUnitCategories.

@Test
public void testGetSortedUnitCategories() throws Exception {
    final GameData data = TestMapGameData.TWW.getGameData();
    final Territory northernGermany = territory("Northern Germany", data);
    northernGermany.getUnits().clear();
    final List<Unit> units = new ArrayList<>();
    final PlayerID italians = GameDataTestUtil.italy(data);
    units.addAll(GameDataTestUtil.italianInfantry(data).create(1, italians));
    units.addAll(GameDataTestUtil.italianFactory(data).create(1, italians));
    units.addAll(GameDataTestUtil.truck(data).create(1, italians));
    final PlayerID british = GameDataTestUtil.britain(data);
    units.addAll(GameDataTestUtil.britishInfantry(data).create(1, british));
    units.addAll(GameDataTestUtil.britishFactory(data).create(1, british));
    units.addAll(GameDataTestUtil.truck(data).create(1, british));
    final PlayerID germans = GameDataTestUtil.germany(data);
    units.addAll(GameDataTestUtil.germanInfantry(data).create(1, germans));
    units.addAll(GameDataTestUtil.germanFactory(data).create(1, germans));
    units.addAll(GameDataTestUtil.truck(data).create(1, germans));
    GameDataTestUtil.addTo(northernGermany, units);
    final List<UnitCategory> categories = TileManager.getSortedUnitCategories(northernGermany, data);
    final List<UnitCategory> expected = new ArrayList<>();
    expected.add(createUnitCategory("germanFactory", germans, data));
    expected.add(createUnitCategory("Truck", germans, data));
    expected.add(createUnitCategory("germanInfantry", germans, data));
    expected.add(createUnitCategory("italianFactory", italians, data));
    expected.add(createUnitCategory("Truck", italians, data));
    expected.add(createUnitCategory("italianInfantry", italians, data));
    expected.add(createUnitCategory("britishFactory", british, data));
    expected.add(createUnitCategory("Truck", british, data));
    expected.add(createUnitCategory("britishInfantry", british, data));
    assertEquals(expected, categories);
}
Also used : PlayerID(games.strategy.engine.data.PlayerID) Territory(games.strategy.engine.data.Territory) GameData(games.strategy.engine.data.GameData) TestMapGameData(games.strategy.triplea.xml.TestMapGameData) ArrayList(java.util.ArrayList) Unit(games.strategy.engine.data.Unit) UnitCategory(games.strategy.triplea.util.UnitCategory) Test(org.junit.jupiter.api.Test)

Aggregations

UnitCategory (games.strategy.triplea.util.UnitCategory)17 Unit (games.strategy.engine.data.Unit)8 ArrayList (java.util.ArrayList)7 Territory (games.strategy.engine.data.Territory)5 Point (java.awt.Point)5 GameData (games.strategy.engine.data.GameData)4 PlayerID (games.strategy.engine.data.PlayerID)4 UnitType (games.strategy.engine.data.UnitType)4 TripleAUnit (games.strategy.triplea.TripleAUnit)4 JPanel (javax.swing.JPanel)4 UnitAttachment (games.strategy.triplea.attachments.UnitAttachment)3 Image (java.awt.Image)3 Collection (java.util.Collection)3 LinkedHashSet (java.util.LinkedHashSet)3 List (java.util.List)3 BoxLayout (javax.swing.BoxLayout)3 ImageIcon (javax.swing.ImageIcon)3 JLabel (javax.swing.JLabel)3 Matches (games.strategy.triplea.delegate.Matches)2 UnitSeperator (games.strategy.triplea.util.UnitSeperator)2