package games.strategy.triplea.delegate;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import games.strategy.engine.data.PlayerID;
import games.strategy.engine.data.Route;
import games.strategy.engine.data.Unit;
import games.strategy.triplea.TripleAUnit;
import games.strategy.triplea.attachments.UnitAttachment;
import games.strategy.triplea.util.TransportUtils;
import games.strategy.util.IntegerMap;
import games.strategy.util.Match;
public class UnitComparator {
public static Comparator<Unit> getLowestToHighestMovementComparator() {
return (u1, u2) -> {
final int left1 = TripleAUnit.get(u1).getMovementLeft();
final int left2 = TripleAUnit.get(u2).getMovementLeft();
if (left1 == left2) {
return 0;
}
if (left1 > left2) {
return 1;
}
return -1;
};
}
public static Comparator<Unit> getHighestToLowestMovementComparator() {
return (u1, u2) -> {
final int left1 = TripleAUnit.get(u1).getMovementLeft();
final int left2 = TripleAUnit.get(u2).getMovementLeft();
if (left1 == left2) {
return 0;
}
if (left1 < left2) {
return 1;
}
return -1;
};
}
public static Comparator<Unit> getIncreasingCapacityComparator(final List<Unit> transports) {
return getCapacityComparator(transports, true);
}
private static Comparator<Unit> getDecreasingCapacityComparator(final List<Unit> transports) {
return getCapacityComparator(transports, false);
}
private static Comparator<Unit> getCapacityComparator(final List<Unit> transports, final boolean increasing) {
// this makes it more efficient
final IntegerMap<Unit> capacityMap = new IntegerMap<>(transports.size() + 1, 1);
for (final Unit transport : transports) {
final Collection<Unit> transporting = TripleAUnit.get(transport).getTransporting();
capacityMap.add(transport, TransportUtils.getTransportCost(transporting));
}
return (t1, t2) -> {
final int cost1 = capacityMap.getInt(t1);
final int cost2 = capacityMap.getInt(t2);
if (increasing) {
return cost1 - cost2;
} else {
return cost2 - cost1;
}
};
}
/**
* Return a Comparator that will order the specified transports in preferred load order.
*/
public static Comparator<Unit> getLoadableTransportsComparator(final List<Unit> transports, final Route route,
final PlayerID player) {
final Comparator<Unit> decreasingCapacityComparator = getDecreasingCapacityComparator(transports);
final Match<Unit> incapableTransportMatch = Matches.transportCannotUnload(route.getEnd());
return (u1, u2) -> {
final TripleAUnit t1 = TripleAUnit.get(u1);
final TripleAUnit t2 = TripleAUnit.get(u2);
// Check if transport is incapable due to game state
final boolean isIncapable1 = incapableTransportMatch.match(t1);
final boolean isIncapable2 = incapableTransportMatch.match(t2);
if (!isIncapable1 && isIncapable2) {
return -1;
}
if (isIncapable1 && !isIncapable2) {
return 1;
}
// Use allied transports as a last resort
final boolean isAlliedTrn1 = !t1.getOwner().equals(player);
final boolean isAlliedTrn2 = !t2.getOwner().equals(player);
if (!isAlliedTrn1 && isAlliedTrn2) {
return -1;
}
if (isAlliedTrn1 && !isAlliedTrn2) {
return 1;
}
// Sort by decreasing transport capacity
final int compareCapacity = decreasingCapacityComparator.compare(t1, t2);
if (compareCapacity != 0) {
return compareCapacity;
}
// Sort by decreasing movement
final int left1 = t1.getMovementLeft();
final int left2 = t1.getMovementLeft();
if (left1 != left2) {
return left2 - left1;
}
return Integer.compare(t1.hashCode(), t2.hashCode());
};
}
/**
* Return a Comparator that will order the specified transports in preferred unload order.
*/
public static Comparator<Unit> getUnloadableTransportsComparator(final List<Unit> transports, final Route route,
final PlayerID player, final boolean noTies) {
final Comparator<Unit> decreasingCapacityComparator = getDecreasingCapacityComparator(transports);
final Match<Unit> incapableTransportMatch = Matches.transportCannotUnload(route.getEnd());
return (t1, t2) -> {
// Check if transport is incapable due to game state
final boolean isIncapable1 = incapableTransportMatch.match(t1);
final boolean isIncapable2 = incapableTransportMatch.match(t2);
if (!isIncapable1 && isIncapable2) {
return -1;
}
if (isIncapable1 && !isIncapable2) {
return 1;
}
// Prioritize allied transports
final boolean isAlliedTrn1 = !t1.getOwner().equals(player);
final boolean isAlliedTrn2 = !t2.getOwner().equals(player);
if (isAlliedTrn1 && !isAlliedTrn2) {
return -1;
}
if (!isAlliedTrn1 && isAlliedTrn2) {
return 1;
}
// Sort by decreasing transport capacity
final int compareCapacity = decreasingCapacityComparator.compare(t1, t2);
if (compareCapacity != 0) {
return compareCapacity;
}
// Sort by increasing movement
final int left1 = TripleAUnit.get(t1).getMovementLeft();
final int left2 = TripleAUnit.get(t2).getMovementLeft();
if (left1 != left2) {
return left1 - left2;
}
// If noTies is set, sort by hashcode so that result is deterministic
if (noTies) {
return Integer.compare(t1.hashCode(), t2.hashCode());
} else {
return 0;
}
};
}
/**
* Return a Comparator that will order the specified units in preferred move order.
*/
public static Comparator<Unit> getMovableUnitsComparator(final List<Unit> units, final Route route) {
final Comparator<Unit> decreasingCapacityComparator = getDecreasingCapacityComparator(units);
return (u1, u2) -> {
// Ensure units have enough movement
final int left1 = TripleAUnit.get(u1).getMovementLeft();
final int left2 = TripleAUnit.get(u2).getMovementLeft();
if (route != null) {
if (left1 >= route.getMovementCost(u1) && left2 < route.getMovementCost(u2)) {
return -1;
}
if (left1 < route.getMovementCost(u1) && left2 >= route.getMovementCost(u2)) {
return 1;
}
}
// Prefer transports for which dependents are also selected
final Collection<Unit> transporting1 = TripleAUnit.get(u1).getTransporting();
final Collection<Unit> transporting2 = TripleAUnit.get(u2).getTransporting();
final int hasDepends1 = units.containsAll(transporting1) ? 1 : 0;
final int hasDepends2 = units.containsAll(transporting2) ? 1 : 0;
if (hasDepends1 != hasDepends2) {
return hasDepends1 - hasDepends2;
}
// Sort by decreasing transport capacity (only valid for transports)
final int compareCapacity = decreasingCapacityComparator.compare(u1, u2);
if (compareCapacity != 0) {
return compareCapacity;
}
// Sort by increasing movement normally, but by decreasing movement during loading
if (left1 != left2) {
if (route != null && route.isLoad()) {
return left2 - left1;
} else {
return left1 - left2;
}
}
return Integer.compare(u1.hashCode(), u2.hashCode());
};
}
/**
* Return a Comparator that will order the specified units in preferred unload order.
* If needed it may also inspect the transport holding the units.
*/
public static Comparator<Unit> getUnloadableUnitsComparator(final List<Unit> units, final Route route,
final PlayerID player) {
// compare transports
final Comparator<Unit> unloadableTransportsComparator =
getUnloadableTransportsComparator(units, route, player, false);
// if noTies is set, sort by hashcode so that result is deterministic
final Comparator<Unit> movableUnitsComparator = getMovableUnitsComparator(units, route);
return (u1, u2) -> {
final Unit t1 = TripleAUnit.get(u1).getTransportedBy();
final Unit t2 = TripleAUnit.get(u2).getTransportedBy();
// check if unloadable units are in a transport
if (t1 != null && t2 == null) {
return -1;
}
if (t1 == null && t2 != null) {
return 1;
}
if (t1 != null && t2 != null) {
final int compareTransports = unloadableTransportsComparator.compare(t1, t2);
if (compareTransports != 0) {
return compareTransports;
}
}
// we are sorting air units, or no difference found yet
// if noTies is set, sort by hashcode so that result is deterministic
return movableUnitsComparator.compare(u1, u2);
};
}
public static Comparator<Unit> getDecreasingAttackComparator(final PlayerID player) {
return (u1, u2) -> {
final UnitAttachment ua1 = UnitAttachment.get(u1.getType());
final UnitAttachment ua2 = UnitAttachment.get(u2.getType());
final int attack1 = ua1.getAttack(player);
final int attack2 = ua2.getAttack(player);
if (attack1 == attack2) {
return 0;
}
if (attack1 < attack2) {
return 1;
}
return -1;
};
}
}