package ei.game.algo; import ei.game.algo.AStarNeighbour.Location; /** * * @author Árni Arent * */ public class AStarNode2D extends AStarNode { protected final static float adjacentCost = 1; protected final static float diagonalCost = (float)Math.sqrt(2)*adjacentCost; protected final static float tieBreaker = adjacentCost/(1024f/1024f); public enum Heuristic { Manhattan, Euclidean, Diagonal, DiagonalWithTieBreaking, DiagonalWithTieBreakingCrossProduct, } public static Heuristic heuristic = Heuristic.Euclidean; protected int x, y; public AStarNode2D(int x, int y, int nodeId) { super(nodeId); this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } @Override public float getEstimatedCostTo(AStarNode node, AStarNode startNode) { AStarNode2D goal = (AStarNode2D)node; AStarNode2D start = (AStarNode2D)startNode; float h = 0; /* * Manhattan distance heuristics. (no diagonal treatment) */ if(heuristic == Heuristic.Manhattan) { h = adjacentCost * (Math.abs(x-goal.x) + Math.abs(y-goal.y)); } /* * Euclidean distances (move at any angle, again no diagonal treatment). */ else if(heuristic == Heuristic.Euclidean) { h = adjacentCost * (float)Math.sqrt(Math.pow(x-goal.x, 2) + Math.pow(y-goal.y,2)); } /* * Diagonal distance heuristic. */ else if(heuristic == Heuristic.Diagonal || heuristic == Heuristic.DiagonalWithTieBreaking || heuristic == Heuristic.DiagonalWithTieBreakingCrossProduct) { float diagonal = Math.min(Math.abs(x-goal.x), Math.abs(y-goal.y)); float straight = (Math.abs(x-goal.x) + Math.abs(y-goal.y)); h = (diagonalCost * diagonal) + (adjacentCost * (straight - (2*diagonal))); /* * Normal tie-breaking. */ if(heuristic == Heuristic.DiagonalWithTieBreaking) { h *= (1.0 + tieBreaker); } /* * Add tie-breaking cross-product to the heuristics. * (Produces nicer looking diagonal paths, but weird with obstacles) */ else if(heuristic == Heuristic.DiagonalWithTieBreakingCrossProduct) { float dx1 = x - goal.x; float dy1 = y - goal.y; float dx2 = start.x - goal.x; float dy2 = start.y - goal.y; float cross = Math.abs(dx1*dy2 - dx2*dy1); h += cross*0.001; } } // Return the heuristic. return h; } @Override public float getCost(AStarNode node, Location location) { if(heuristic == Heuristic.Manhattan || heuristic == Heuristic.Euclidean) { return adjacentCost; } else { if(location == Location.Adjacent) { return adjacentCost; } else { return diagonalCost; } } } }