use of org.openbw.bwapi4j.util.Pair in project BWAPI4J by OpenBW.
the class BwemExt method makeBoundingBoxIncludePoint.
// Enlarges the bounding box [topLeft, bottomRight] so that it includes A.
public static Pair<TilePosition, TilePosition> makeBoundingBoxIncludePoint(final TilePosition topLeft, final TilePosition bottomRight, final TilePosition point) {
int topLeftX = topLeft.getX();
int topLeftY = topLeft.getY();
int bottomRightX = bottomRight.getX();
int bottomRightY = bottomRight.getY();
if (point.getX() < topLeftX)
topLeftX = point.getX();
if (point.getX() > bottomRightX)
bottomRightX = point.getX();
if (point.getY() < topLeftY)
topLeftY = point.getY();
if (point.getY() > bottomRightY)
bottomRightY = point.getY();
return new Pair<>(new TilePosition(topLeftX, topLeftY), new TilePosition(bottomRightX, bottomRightY));
}
use of org.openbw.bwapi4j.util.Pair in project BWAPI4J by OpenBW.
the class Graph method createChokePoints.
// ----------------------------------------------------------------------
// //////////////////////////////////////////////////////////////////////
// Creates a new Area for each pair (top, miniTiles) in AreasList (See Area::top() and Area::miniTiles())
public void createChokePoints(final List<StaticBuilding> staticBuildings, final List<Mineral> minerals, final List<MutablePair<MutablePair<AreaId, AreaId>, WalkPosition>> rawFrontier) {
Index newIndex = new Index(0);
final List<Neutral> blockingNeutrals = new ArrayList<>();
for (final StaticBuilding s : staticBuildings) {
if (s.isBlocking()) {
blockingNeutrals.add(s);
}
}
for (final Mineral m : minerals) {
if (m.isBlocking()) {
blockingNeutrals.add(m);
}
}
// Note: pseudoChokePointsToCreate is only used for pre-allocating the GetChokePoints array size.
// This number will highly likely be very small. There is no reason to set a minimum size.
// int pseudoChokePointsToCreate = 0;
// for (final Neutral blockingNeutral : blockingNeutrals) {
// if (blockingNeutral.getNextStacked() == null) {
// ++pseudoChokePointsToCreate;
// }
// }
// 1) size the matrix
initializeChokePointsMatrix(this.chokePointsMatrix, getAreaCount());
// 2) Dispatch the global raw frontier between all the relevant pairs of areas:
final java.util.Map<MutablePair<AreaId, AreaId>, List<WalkPosition>> rawFrontierByAreaPair = createRawFrontierByAreaPairMap(rawFrontier);
// 3) For each pair of areas (A, B):
for (final java.util.Map.Entry<MutablePair<AreaId, AreaId>, List<WalkPosition>> entry : rawFrontierByAreaPair.entrySet()) {
MutablePair<AreaId, AreaId> rawleft = entry.getKey();
final List<WalkPosition> rawFrontierAB = entry.getValue();
// Because our dispatching preserved order,
// and because Map::m_RawFrontier was populated in descending order of the altitude (see Map::computeAreas),
// we know that rawFrontierAB is also ordered the same way, but let's check it:
{
final List<Altitude> altitudes = new ArrayList<>();
for (final WalkPosition w : rawFrontierAB) {
altitudes.add(getMap().getData().getMiniTile(w).getAltitude());
}
// bwem_assert(is_sorted(altitudes.rbegin(), altitudes.rend()));
for (int i = 1; i < altitudes.size(); ++i) {
final int prev = altitudes.get(i - 1).intValue();
final int curr = altitudes.get(i).intValue();
if (prev < curr) {
throw new IllegalStateException();
}
}
}
// 3.1) Use that information to efficiently cluster rawFrontierAB in one or several chokepoints.
// Each cluster will be populated starting with the center of a chokepoint (max altitude)
// and finishing with the ends (min altitude).
final int clusterMinDist = (int) Math.sqrt(BwemExt.lake_max_miniTiles);
final List<List<WalkPosition>> clusters = new ArrayList<>();
for (final WalkPosition w : rawFrontierAB) {
boolean added = false;
for (final List<WalkPosition> cluster : clusters) {
final int distToFront = BwemExt.queenWiseDist(cluster.get(0), w);
final int distToBack = BwemExt.queenWiseDist(cluster.get(cluster.size() - 1), w);
if (Math.min(distToFront, distToBack) <= clusterMinDist) {
if (distToFront < distToBack) {
cluster.add(0, w);
} else {
cluster.add(w);
}
added = true;
break;
}
}
if (!added) {
final List<WalkPosition> list = new ArrayList<>();
list.add(w);
clusters.add(list);
}
}
// 3.2) Create one Chokepoint for each cluster:
final AreaId a = rawleft.getLeft();
final AreaId b = rawleft.getRight();
// getChokePoints(a, b).reserve(clusters.size() + pseudoChokePointsToCreate);
for (final List<WalkPosition> cluster : clusters) {
getChokePoints(a, b).add(new ChokePointImpl(this, newIndex, getArea(a), getArea(b), cluster));
newIndex = newIndex.add(1);
}
}
// 4) Create one Chokepoint for each pair of blocked areas, for each blocking Neutral:
for (final Neutral blockingNeutral : blockingNeutrals) {
if (blockingNeutral.getNextStacked() == null) {
// in the case where several neutrals are stacked, we only consider the top
final List<Area> blockedAreas = blockingNeutral.getBlockedAreas();
for (final Area blockedAreaA : blockedAreas) for (final Area blockedAreaB : blockedAreas) {
if (blockedAreaB.equals(blockedAreaA)) {
// breaks symmetry
break;
}
final WalkPosition center = getMap().breadthFirstSearch(blockingNeutral.getCenter().toWalkPosition(), // findCond
args -> {
Object ttile = args[0];
if (!(ttile instanceof MiniTile)) {
throw new IllegalArgumentException();
}
MiniTile miniTile = (MiniTile) ttile;
return miniTile.isWalkable();
}, // visitCond
args -> true);
final List<WalkPosition> list = new ArrayList<>();
list.add(center);
getChokePoints(blockedAreaA, blockedAreaB).add(new ChokePointImpl(this, newIndex, blockedAreaA, blockedAreaB, list, blockingNeutral));
newIndex = newIndex.add(1);
}
}
}
// 5) Set the references to the freshly created Chokepoints:
for (int loopA = 1; loopA <= getAreaCount(); ++loopA) for (int loopB = 1; loopB < loopA; ++loopB) {
final AreaId a = new AreaId(loopA);
final AreaId b = new AreaId(loopB);
if (!getChokePoints(a, b).isEmpty()) {
((AreaInitializer) getArea(a)).addChokePoints(getArea(b), getChokePoints(a, b));
((AreaInitializer) getArea(b)).addChokePoints(getArea(a), getChokePoints(a, b));
this.chokePoints.addAll(getChokePoints(a, b));
}
}
}
use of org.openbw.bwapi4j.util.Pair in project BWAPI4J by OpenBW.
the class AreaInitializerImpl method computeDistances.
@Override
public int[] computeDistances(final TilePosition start, final List<TilePosition> targets) {
final int[] distances = new int[targets.size()];
TileImpl.getStaticMarkable().unmarkAll();
// a priority queue holding the tiles to visit ordered by their distance to start.
final Queue<Pair<Integer, TilePosition>> toVisit = new PriorityQueue<>(Comparator.comparingInt(Pair::getFirst));
toVisit.offer(new Pair<>(0, start));
int remainingTargets = targets.size();
while (!toVisit.isEmpty()) {
final Pair<Integer, TilePosition> distanceAndTilePosition = toVisit.poll();
final int currentDist = distanceAndTilePosition.getFirst();
final TilePosition current = distanceAndTilePosition.getSecond();
final Tile currentTile = getMap().getData().getTile(current, CheckMode.NO_CHECK);
// bwem_assert(currentTile.InternalData() == currentDist);
if (!(((TileImpl) currentTile).getInternalData() == currentDist)) {
throw new IllegalStateException("currentTile.InternalData().intValue()=" + ((TileImpl) currentTile).getInternalData() + ", currentDist=" + currentDist);
}
// resets Tile::m_internalData for future usage
((TileImpl) currentTile).setInternalData(0);
((TileImpl) currentTile).getMarkable().setMarked();
for (int i = 0; i < targets.size(); ++i) {
if (current.equals(targets.get(i))) {
distances[i] = (int) Math.round(currentDist * 32.0 / 10000.0);
--remainingTargets;
}
}
if (remainingTargets == 0) {
break;
}
final TilePosition[] deltas = { new TilePosition(-1, -1), new TilePosition(0, -1), new TilePosition(+1, -1), new TilePosition(-1, 0), new TilePosition(+1, 0), new TilePosition(-1, +1), new TilePosition(0, +1), new TilePosition(+1, +1) };
for (final TilePosition delta : deltas) {
final boolean diagonalMove = (delta.getX() != 0) && (delta.getY() != 0);
final int newNextDist = currentDist + (diagonalMove ? 14142 : 10000);
final TilePosition next = current.add(delta);
if (getMap().getData().getMapData().isValid(next)) {
final Tile nextTile = getMap().getData().getTile(next, CheckMode.NO_CHECK);
if (!((TileImpl) nextTile).getMarkable().isMarked()) {
if (((TileImpl) nextTile).getInternalData() != 0) {
// next already in toVisit
if (newNextDist < ((TileImpl) nextTile).getInternalData()) {
// nextNewDist < nextOldDist
// To update next's distance, we need to remove-insert it from toVisit:
// bwem_assert(iNext != range.second);
final boolean removed = toVisit.remove(new Pair<>(((TileImpl) nextTile).getInternalData(), next));
if (!removed) {
throw new IllegalStateException();
}
((TileImpl) nextTile).setInternalData(newNextDist);
toVisit.offer(new Pair<>(newNextDist, next));
}
} else if ((nextTile.getAreaId().equals(getId())) || (nextTile.getAreaId().equals(UNINITIALIZED))) {
((TileImpl) nextTile).setInternalData(newNextDist);
toVisit.offer(new Pair<>(newNextDist, next));
}
}
}
}
}
// bwem_assert(!remainingTargets);
if (!(remainingTargets == 0)) {
throw new IllegalStateException();
}
for (final Pair<Integer, TilePosition> distanceAndTilePosition : toVisit) {
final TileImpl tileToUpdate = ((TileImpl) getMap().getData().getTile(distanceAndTilePosition.getSecond(), CheckMode.NO_CHECK));
tileToUpdate.setInternalData(0);
}
return distances;
}
use of org.openbw.bwapi4j.util.Pair in project BWAPI4J by OpenBW.
the class Graph method computeDistances.
// //////////////////////////////////////////////////////////////////////
// Returns Distances such that Distances[i] == ground_distance(start, targets[i]) in pixels
// Any Distances[i] may be 0 (meaning targets[i] is not reachable).
// This may occur in the case where start and targets[i] leave in different continents or due to Bloqued intermediate ChokePoint(s).
// For each reached target, the shortest path can be derived using
// the backward trace set in cp->getPathBackTrace() for each intermediate ChokePoint cp from the target.
// Note: same algo than Area::computeDistances (derived from Dijkstra)
private int[] computeDistances(final ChokePoint start, final List<ChokePoint> targets) {
final int[] distances = new int[targets.size()];
TileImpl.getStaticMarkable().unmarkAll();
final Queue<Pair<Integer, ChokePoint>> toVisit = new PriorityQueue<>(Comparator.comparingInt(a -> a.first));
toVisit.offer(new Pair<>(0, start));
int remainingTargets = targets.size();
while (!toVisit.isEmpty()) {
final Pair<Integer, ChokePoint> distanceAndChokePoint = toVisit.poll();
final int currentDist = distanceAndChokePoint.first;
final ChokePoint current = distanceAndChokePoint.second;
final Tile currentTile = getMap().getData().getTile(current.getCenter().toTilePosition(), CheckMode.NO_CHECK);
// bwem_assert(currentTile.InternalData() == currentDist);
if (!(((TileImpl) currentTile).getInternalData() == currentDist)) {
throw new IllegalStateException();
}
// resets Tile::m_internalData for future usage
((TileImpl) currentTile).setInternalData(0);
((TileImpl) currentTile).getMarkable().setMarked();
for (int i = 0; i < targets.size(); ++i) {
if (current == targets.get(i)) {
distances[i] = currentDist;
--remainingTargets;
}
}
if (remainingTargets == 0) {
break;
}
if (current.isBlocked() && (!current.equals(start))) {
continue;
}
for (final Area pArea : new Area[] { current.getAreas().getFirst(), current.getAreas().getSecond() }) {
for (final ChokePoint next : pArea.getChokePoints()) {
if (!next.equals(current)) {
final int newNextDist = currentDist + distance(current, next);
final Tile nextTile = getMap().getData().getTile(next.getCenter().toTilePosition(), CheckMode.NO_CHECK);
if (!((TileImpl) nextTile).getMarkable().isMarked()) {
if (((TileImpl) nextTile).getInternalData() != 0) {
// next already in toVisit
if (newNextDist < ((TileImpl) nextTile).getInternalData()) {
// nextNewDist < nextOldDist
// To update next's distance, we need to remove-insert it from toVisit:
// bwem_assert(iNext != range.second);
final boolean removed = toVisit.remove(new Pair<>(((TileImpl) nextTile).getInternalData(), next));
if (!removed) {
throw new IllegalStateException();
}
((TileImpl) nextTile).setInternalData(newNextDist);
((ChokePointImpl) next).setPathBackTrace(current);
toVisit.offer(new Pair<>(newNextDist, next));
}
} else {
((TileImpl) nextTile).setInternalData(newNextDist);
((ChokePointImpl) next).setPathBackTrace(current);
toVisit.offer(new Pair<>(newNextDist, next));
}
}
}
}
}
}
// reset Tile::m_internalData for future usage
for (Pair<Integer, ChokePoint> distanceToChokePoint : toVisit) {
((TileImpl) getMap().getData().getTile(distanceToChokePoint.second.getCenter().toTilePosition(), CheckMode.NO_CHECK)).setInternalData(0);
}
return distances;
}
Aggregations