package robombs.game.ai;
import robombs.game.model.*;
import java.util.*;
/**
* Modified A*-implementation...
*/
public class AStar {
private final static int BLOCKED=9999;
private final static int MAX_ITERATIONS=500;
private MapMask mask=null;
private MapMask dec=null;
private Set<AIGridPosition> closed=null;
private Set<AIGridPosition> open=null;
private AIGridPosition result=null;
private int itCnt=0;
private boolean crateBlock=false;
public AStar(MapMask mm, boolean cratesAreBlocks) {
this.mask=mm;
closed=new HashSet<AIGridPosition>();
open=new HashSet<AIGridPosition>();
crateBlock=cratesAreBlocks;
}
public void clear() {
closed.clear();
open.clear();
result=null;
itCnt=0;
dec=null;
}
public void setDecisionMask(MapMask dec) {
this.dec=dec;
}
public AIGridPosition getPathToTarget(GridPosition source, GridPosition target) {
result=null;
AIGridPosition agp=new AIGridPosition(source);
agp.setValue(agp.getDistanceTo(target));
getPathToTarget(agp, target);
return result;
}
public GridPosition[] getPath(AIGridPosition result) {
List<GridPosition> res=new ArrayList<GridPosition>();
while (result.getParent()!=null) {
res.add(result);
result=result.getParent();
}
GridPosition[] gps=new GridPosition[res.size()];
for (int i=res.size()-1; i>=0; i--) {
gps[gps.length-1-i]=(GridPosition) res.get(i);
}
return gps;
}
private void getPathToTarget(AIGridPosition gp, GridPosition target) {
itCnt++;
if (itCnt>MAX_ITERATIONS) {
// That's enough. Maybe there is no solution (yet).
return;
}
AIGridPosition best=null;
AIGridPosition opened[]=null;
int openedCnt=0;
int gpx=gp.getX();
int gpz=gp.getZ();
AIGridPosition ngp=null;
do {
if (opened!=null) {
for (int i=0; i<openedCnt; i++) {
open.remove(opened[i]);
}
openedCnt=0;
}
best=null;
for (int x=-1; x<2; x++) {
int xx=gpx+x;
for (int z=-1; z<2; z++) {
if (z!=0||x!=0) {
int zz=gpz+z;
if (!mask.isObstacle(xx, zz)) {
float addCost=1;
if (!crateBlock) {
if (mask.isSemiBlocked(xx, zz)) {
addCost=1.3f;
}
} else {
if (mask.isBlocked(xx, zz)) {
addCost=BLOCKED;
}
}
if (z!=0&&x!=0 && addCost!=BLOCKED) {
addCost=3f;
int cc=mask.doCornerCheck(gp, x, z);
if (cc==MapMask.CORNER_SINGLE) {
addCost=5000;
} else {
if (cc==MapMask.CORNER_DOUBLE) {
addCost=BLOCKED;
}
}
}
if (dec!=null && addCost!=BLOCKED) {
int di=dec.getMaskAt(xx, zz);
if (di==-1) {
// Bomb's blow ahead...cross this only if needed!
addCost=500f;
}
if (di==-2) {
// Bomb ahead...don't go there
addCost=BLOCKED;
}
}
if (addCost!=BLOCKED) {
if (ngp==null) {
ngp=new AIGridPosition(xx, zz);
} else {
// Recycling of unused instances...
ngp.set(xx,zz);
}
if (!open.contains(ngp)&&!closed.contains(ngp)) {
if (opened==null) {
opened=new AIGridPosition[8];
}
open.add(ngp);
opened[openedCnt]=ngp;
openedCnt++;
ngp.setParent(gp);
ngp.setValue(target.getDistanceTo(ngp)+addCost);
if (best==null) {
best=ngp;
} else {
if (ngp.getValue()<best.getValue()) {
best=ngp;
}
}
ngp=null;
}
}
}
}
}
}
if (best!=null) {
if (best.equals(target)) {
result=best;
return;
}
getPathToTarget(best, target);
}
} while (best!=null && result==null && itCnt<MAX_ITERATIONS);
closed.add(gp);
open.remove(gp);
}
}