Java很慢执行A * Pathfinding算法

时间:2014-09-19 09:11:03

标签: java android algorithm graph-algorithm path-finding

我正在用java创建一个迷宫游戏,并希望添加一个聪明的幽灵(如Pacman),向用户位置移动以抓住他。对于聪明的幽灵我选择了A * PathFinding算法,并在下面找到了实现这个算法的链接:

https://code.google.com/p/a-star/source/browse/trunk/java/PathFinder.java?r=8

https://code.google.com/p/a-star/source/browse/trunk/java/AStar.java?r=8

PathFinder.java

import java.util.*;

/*
 * Example.
 */
public class PathFinder extends AStar<PathFinder.Node>
{
                private int[][] map;

                public static class Node{
                                public int x;
                                public int y;
                                Node(int x, int y){
                                                this.x = x; 
                                                this.y = y;
                                }
                                public String toString(){
                                                return "(" + x + ", " + y + ") ";
                                } 
                }
                public PathFinder(int[][] map){
                                this.map = map;
                }

                protected boolean isGoal(Node node){
                                return (node.x == map[0].length - 1) && (node.y == map.length - 1);
                }

                protected Double g(Node from, Node to){

                                if(from.x == to.x && from.y == to.y)
                                                return 0.0;

                                if(map[to.y][to.x] == 1)
                                                return 1.0;

                                return Double.MAX_VALUE;
                }

                protected Double h(Node from, Node to){
                                /* Use the Manhattan distance heuristic.  */
                                return new Double(Math.abs(map[0].length - 1 - to.x) + Math.abs(map.length - 1 - to.y));
                }

                protected List<Node> generateSuccessors(Node node){
                                List<Node> ret = new LinkedList<Node>();
                                int x = node.x;
                                int y = node.y;
                                if(y < map.length - 1 && map[y+1][x] == 1)
                                                ret.add(new Node(x, y+1));

                                if(x < map[0].length - 1 && map[y][x+1] == 1)
                                                ret.add(new Node(x+1, y));

if(y > 0 && map[y-1][x] == 1)
                ret.add(new Node(x, y-1));
if(x > 0 && map[y][x-1] == 1)
                ret.add(new Node(x-1, y));
                                return ret;
                }

                public static void main(String [] args){
                                int [][] map = new int[][]{
                                                {1, 1, 1, 1, 1, 1, 1, 1, 1},
                                                {0, 0, 1, 0, 0, 0, 0, 0, 1},
                                                {1, 1, 1, 1, 0, 1, 1, 0, 1},
                                                {1, 1, 1, 1, 1, 1, 1, 0, 0},
                                                {1, 0, 0, 0, 0, 1, 0, 0, 0},
                                                {1, 1, 1, 1, 0, 1, 1, 1, 1},
                                                {1, 1, 1, 1, 0, 1, 0, 0, 1},
                                                {1, 1, 1, 1, 0, 1, 0, 0, 1},
                                                {1, 1, 1, 1, 0, 1, 0, 0, 1},
                                                {1, 1, 1, 1, 0, 1, 0, 0, 0},
                                                {1, 1, 1, 1, 0, 1, 1, 1, 1},
                                };
                                PathFinder pf = new PathFinder(map);

                                System.out.println("Find a path from the top left corner to the right bottom one.");

                                for(int i = 0; i < map.length; i++){
                                                for(int j = 0; j < map[0].length; j++)
                                                                System.out.print(map[i][j] + " ");
                                                System.out.println();
                                }

                                long begin = System.currentTimeMillis();

                                List<Node> nodes = pf.compute(new PathFinder.Node(0, 0));

                                long end = System.currentTimeMillis();


                                System.out.println("Time = " + (end - begin) + " ms" );
                                System.out.println("Expanded = " + pf.getExpandedCounter());
                                System.out.println("Cost = " + pf.getCost());

                                if(nodes == null)
                                                System.out.println("No path");
                                else{
                                                System.out.print("Path = ");
                                                for(Node n : nodes)
                                                                System.out.print(n);
                                                System.out.println();
                                }
                }

}

AStar.java

import java.util.*;

/**
 * A* algorithm implementation using the method design pattern.
 * 
 * @author Giuseppe Scrivano
 */
public abstract class AStar<T>
{
                private class Path implements Comparable{
                                public T point;
                                public Double f;
                                public Double g;
                                public Path parent;

                                /**
                                 * Default c'tor.
                                 */
                                public Path(){
                                                parent = null;
                                                point = null;
                                                g = f = 0.0;
                                }

                                /**
                                 * C'tor by copy another object.
                                 * 
                                 * @param p The path object to clone.
                                 */
                                public Path(Path p){
                                                this();
                                                parent = p;
                                                g = p.g;
                                                f = p.f;
                                }

                                /**
                                 * Compare to another object using the total cost f.
                                 *
                                 * @param o The object to compare to.
                                 * @see       Comparable#compareTo()
                                 * @return <code>less than 0</code> This object is smaller
                                 * than <code>0</code>;
                                 *        <code>0</code> Object are the same.
                                 *        <code>bigger than 0</code> This object is bigger
                                 * than o.
                                 */
                                public int compareTo(Object o){
                                                Path p = (Path)o;
                                                return (int)(f - p.f);
                                }

                                /**
                                 * Get the last point on the path.
                                 *
                                 * @return The last point visited by the path.
                                 */
                                public T getPoint(){
                                                return point;
                                }

                                /**
                                 * Set the 
                                 */
                                public void setPoint(T p){
                                                point = p;
                                }
                }

                /**
                 * Check if the current node is a goal for the problem.
                 *
                 * @param node The node to check.
                 * @return <code>true</code> if it is a goal, <code>false</else> otherwise.
                 */
                protected abstract boolean isGoal(T node);

                /**
                 * Cost for the operation to go to <code>to</code> from
                 * <code>from</from>.
                 *
                 * @param from The node we are leaving.
                 * @param to The node we are reaching.
                 * @return The cost of the operation.
                 */
                protected abstract Double g(T from, T to);

                /**
                 * Estimated cost to reach a goal node.
                 * An admissible heuristic never gives a cost bigger than the real
                 * one.
                 * <code>from</from>.
                 *
                 * @param from The node we are leaving.
                 * @param to The node we are reaching.
                 * @return The estimated cost to reach an object.
                 */
                protected abstract Double h(T from, T to);


                /**
                 * Generate the successors for a given node.
                 *
                 * @param node The node we want to expand.
                 * @return A list of possible next steps.
                 */
                protected abstract List<T> generateSuccessors(T node);


                private PriorityQueue<Path> paths;
                private HashMap<T, Double> mindists;
                private Double lastCost;
                private int expandedCounter;

                /**
                 * Check how many times a node was expanded.
                 *
                 * @return A counter of how many times a node was expanded.
                 */
                public int getExpandedCounter(){
                                return expandedCounter;
                }

                /**
                 * Default c'tor.
                 */
                public AStar(){
                                paths = new PriorityQueue<Path>();
                                mindists = new HashMap<T, Double>();
                                expandedCounter = 0;
                                lastCost = 0.0;
                }


                /**
                 * Total cost function to reach the node <code>to</code> from
                 * <code>from</code>.
                 *  
                 * The total cost is defined as: f(x) = g(x) + h(x).
                 * @param from The node we are leaving.
                 * @param to The node we are reaching.
                 * @return The total cost.
                 */
                protected Double f(Path p, T from, T to){
                                Double g =  g(from, to) + ((p.parent != null) ? p.parent.g : 0.0);
                                Double h = h(from, to);

                                p.g = g;
                                p.f = g + h;

                                return p.f;
                }

                /**
                 * Expand a path.
                 *
                 * @param path The path to expand.
                 */
                private void expand(Path path){
                                T p = path.getPoint();
                                Double min = mindists.get(path.getPoint());

                                /*
                                 * If a better path passing for this point already exists then
                                 * don't expand it.
                                 */
                                if(min == null || min.doubleValue() > path.f.doubleValue())
                                                mindists.put(path.getPoint(), path.f);
                                else
                                                return;

                                List<T> successors = generateSuccessors(p);

                                for(T t : successors){
                                                Path newPath = new Path(path);
                                                newPath.setPoint(t);
                                                f(newPath, path.getPoint(), t);
                                                paths.offer(newPath);
                                }

                                expandedCounter++;
                }

                /**
                 * Get the cost to reach the last node in the path.
                 *
                 * @return The cost for the found path.
                 */
                public Double getCost(){
                                return lastCost;
                }


                /**
                 * Find the shortest path to a goal starting from
                 * <code>start</code>.
                 *
                 * @param start The initial node.
                 * @return A list of nodes from the initial point to a goal,
                 * <code>null</code> if a path doesn't exist.
                 */
                public List<T> compute(T start){
                                try{
                                                Path root = new Path();
                                                root.setPoint(start);

                                                /* Needed if the initial point has a cost.  */
                                                f(root, start, start);

                                                expand(root);

                                                for(;;){
                                                                Path p = paths.poll();

                                                                if(p == null){
                                                                                lastCost = Double.MAX_VALUE;
                                                                                return null;
                                                                }

                                                                T last = p.getPoint();

                                                                lastCost = p.g;

                                                                if(isGoal(last)){
                                                                                LinkedList<T> retPath = new LinkedList<T>();

                                                                                for(Path i = p; i != null; i = i.parent){
                                                                                                retPath.addFirst(i.getPoint());
                                                                                }

                                                                                return retPath;
                                                                }
                                                                expand(p);
                                                }
                                }
                                catch(Exception e){
                                                e.printStackTrace();
                                }
                                return null;

                }
}

现在的问题是,在某些情况下代码执行超过2分钟(source =(8,8)和dest =(8,0))。我刚刚使用了[11] [9] 2-D矩阵。

我不明白哪部分代码会让它变慢?

Plz帮我解决了这个问题。

0 个答案:

没有答案