I’m working on a game which has tank battles on a tiled map. If a tank is on a cell, that cell is considered unpassable in the A* algorithm, therefore, whenever an unit needs to attack another, I need to plan a path which brings the attacker into range (if range=1, then next to the target).
Currently, I use an iterative approach with increasing radius to find a path to a nearby cell and choose a cell which minimizes the A-Cell-B distance. Unfortunately, this is slow for one unit, not to mention for 50 units.
Is there a way to extract a partial path from a regular A* search data structures?
Just for reference, here is the implementation I have.
Set<T> closedSet = U.newHashSet();
Map<T, T> cameFrom = U.newHashMap();
final Map<T, Integer> gScore = U.newHashMap();
final Map<T, Integer> hScore = U.newHashMap();
final Map<T, Integer> fScore = U.newHashMap();
final Comparator<T> smallestF = new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
int g1 = fScore.get(o1);
int g2 = fScore.get(o2);
return g1 < g2 ? -1 : (g1 > g2 ? 1 : 0);
}
};
Set<T> openSet2 = U.newHashSet();
List<T> openSet = U.newArrayList();
gScore.put(initial, 0);
hScore.put(initial, estimation.invoke(initial, destination));
fScore.put(initial, gScore.get(initial) + hScore.get(initial));
openSet.add(initial);
openSet2.add(initial);
while (!openSet.isEmpty()) {
T current = openSet.get(0);
if (current.equals(destination)) {
return reconstructPath(cameFrom, destination);
}
openSet.remove(0);
openSet2.remove(current);
closedSet.add(current);
for (T loc : neighbors.invoke(current)) {
if (!closedSet.contains(loc)) {
int tentativeScore = gScore.get(current)
+ distance.invoke(current, loc);
if (!openSet2.contains(loc)) {
cameFrom.put(loc, current);
gScore.put(loc, tentativeScore);
hScore.put(loc, estimation.invoke(loc, destination));
fScore.put(loc, gScore.get(loc) + hScore.get(loc));
openSet.add(loc);
Collections.sort(openSet, smallestF);
openSet2.add(loc);
} else
if (tentativeScore < gScore.get(loc)) {
cameFrom.put(loc, current);
gScore.put(loc, tentativeScore);
hScore.put(loc, estimation.invoke(loc, destination));
fScore.put(loc, gScore.get(loc) + hScore.get(loc));
Collections.sort(openSet, smallestF);
}
}
}
}
return Collections.emptyList();
A solution that seems to work (replacing the last return Collections.emptyList();):
Where the trueDistance gives the eucleidian distance of two points. (The base algorithm uses a simpler function yielding 1000 for X-X or YY neightbor, 1414 for XY neighbor).