1. 程式人生 > >最短路徑A*演算法原理及java程式碼實現(看不懂是我的失敗)

最短路徑A*演算法原理及java程式碼實現(看不懂是我的失敗)


package astar;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 
 * @author hjn
 * @version 1.0 2015-03-11
 * 
 */
public class AStar implements IMove {

    public static final int MOVE_TETN = 10;
    public static final int MOVE_SIDE = 14;
    public static final int LENGHT = 10;
    /* 開啟的列表 */
    Map<String, Point> openMap = new HashMap<String, Point>();
    /* 關閉的列表 */
    Map<String, Point> closeMap = new HashMap<String, Point>();
    /* 障礙物 */
    Set<Point> barrier;
    /* 起點 */
    Point startPoint;
    /* 終點 */
    Point endPoint;
    /* 當前使用節點 */
    Point currentPoint;
    /* 迴圈次數,為了防止目標不可到達 */
    int num = 0;
    
    Point lastPoint;

    /**
     * 獲取點1到點1的最佳路徑
     */
    @Override
    public Point move(int x1, int y1, int x2, int y2, Set<Point> barrier) {
        num = 0;
        this.lastPoint=new Point(x2,y2);
        this.barrier = barrier;
        this.startPoint = new Point(x1, y1);
        Point endPoint=new Point(x2,y2);
        this.endPoint = this.getNearPoint(endPoint,endPoint);
        this.closeMap.put(startPoint.getKey(), startPoint);
        this.currentPoint = this.startPoint;
        this.toOpen(x1, y1);
        return endPoint;
    }

    

    /**
     * 求亮點間的估算代價,效能由高到低 啟發函式一(曼哈頓距離): (Math.abs(x1 - x2) + Math.abs(y1 - y2)) *
     * 單位長度 啟發函式二(平方的歐幾里得距離):((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 -y1))*
     * 單位長度 啟發函式三(歐幾里得距離):(int) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) *
     * (y2 -y1))* 單位長度 啟發函式四(對角線距離):Math.max(Math.abs(x1 - x2), Math.abs(y1 -
     * y2)) * 單位長度 不用啟發函式:0
     * 
     * @param x1
     *            點1x軸
     * @param y1
     *            點1y軸
     * @param x2
     *            點2x軸
     * @param y2
     *            點2y軸
     * @return
     */
    private int getGuessLength(int x1, int y1, int x2, int y2) {
        //return ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 -y1))* AStar.LENGHT;
        return (Math.abs(x1 - x2) + Math.abs(y1 - y2)) * AStar.LENGHT;
        // return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2)) * AStar.LENGHT;
        // return 0;
    }

    /**
     * 把該節點相鄰點加入開啟的列表
     * 
     * @param x
     * @param y
     */
    private void toOpen(int x, int y) {
        this.addOpenPoint(new Point(x - 1, y), AStar.MOVE_TETN);
        this.addOpenPoint(new Point(x + 1, y), AStar.MOVE_TETN);
        this.addOpenPoint(new Point(x, y - 1), AStar.MOVE_TETN);
        this.addOpenPoint(new Point(x, y + 1), AStar.MOVE_TETN);
        this.addOpenPoint(new Point(x - 1, y - 1), AStar.MOVE_SIDE);
        this.addOpenPoint(new Point(x - 1, y + 1), AStar.MOVE_SIDE);
        this.addOpenPoint(new Point(x + 1, y - 1), AStar.MOVE_SIDE);
        this.addOpenPoint(new Point(x + 1, y + 1), AStar.MOVE_SIDE);
        num++;
        if (num <= 4000) {
            this.toClose(x, y);
        }

    }

    /**
     * 把該節點相鄰點加入關閉的列表
     * 
     * @param x
     * @param y
     */
    private void toClose(int x, int y) {
        List<Point> list = new ArrayList<Point>(openMap.values());
        Collections.sort(list, new Comparator<Point>() {
            @Override
            public int compare(Point o1, Point o2) {
                if (o1.fTotal > o2.fTotal) {
                    return 1;
                } else if (o1.fTotal < o2.fTotal) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });
        if (list.size() > 0) {
            this.currentPoint = list.get(0);
            closeMap.put(this.currentPoint.getKey(), this.currentPoint);
            openMap.remove(this.currentPoint.getKey());
            if (!currentPoint.equals(endPoint)) {
                this.toOpen(this.currentPoint.x, this.currentPoint.y);
            } else {
                    endPoint = this.currentPoint;
            }
        }
    }

    /**
     * 新增開放的點
     * 
     * @param point
     *            點
     * @param gCost
     *            當前點到該點的消耗
     * @return
     */
    private void addOpenPoint(Point point, int gCost) {
        if (point.x < 0 || point.y < 0) {
            return;
        }
        String key = point.getKey();
        if (!barrier.contains(point) && !point.equals(this.currentPoint)) {
            int hEstimate = this.getGuessLength(point.x, point.y,
                    this.endPoint.x, this.endPoint.y);
            int totalGCost = this.currentPoint.gCost + gCost;
            int fTotal = totalGCost + hEstimate;
            if (!closeMap.containsKey(key)) {
                point.hEstimate = hEstimate;
                point.gCost = totalGCost;
                point.fTotal = fTotal;
                Point oldPoint = openMap.get(key);
                if (oldPoint != null) {
                    if (oldPoint.gCost > totalGCost) {
                        oldPoint.fTotal = fTotal;
                        oldPoint.prev = this.currentPoint;
                        openMap.put(key, oldPoint);
                    }
                } else {
                    point.prev = this.currentPoint;
                    openMap.put(key, point);
                }
            } else {
                Point oldPoint = closeMap.get(key);
                if (oldPoint != null) {
                    if ((oldPoint.gCost + gCost) < this.currentPoint.gCost) {
                        if (this.currentPoint.prev != oldPoint) {
                            this.currentPoint.fTotal = oldPoint.fTotal + gCost;
                            this.currentPoint.gCost = oldPoint.gCost + gCost;
                            this.currentPoint.prev = oldPoint;
                        }
                    }
                }
            }
        }
    }
    
    

    Map<String, Point> nearOutMap;

    public Point getNearPoint(Point point,Point point2) {
        if(this.barrier.contains(point)){
            nearOutMap = new HashMap<String, Point>();
            this.endPoint=point;
            this.toNearPoint(point,point2);
            List<Point> nearList = new ArrayList<Point>(nearOutMap.values());
            Collections.sort(nearList, new Comparator<Point>() {
                @Override
                public int compare(Point o1, Point o2) {
                    if (o1.gCost > o2.gCost) {
                        return 1;
                    } else if (o1.gCost < o2.gCost) {
                        return -1;
                    } else {
                        return 0;
                    }
                }
            });
            this.openMap=new HashMap<String,Point>();
            this.closeMap=new HashMap<String,Point>();
            if (nearList.size() > 0) {
                return nearList.get(0);
            }else{
                return point;
            }
        }else{
            return point;
        }
        
    }

    public void toNearPoint(Point point,Point point2) {
        int x = point.x;
        int y = point.y;
        this.addNearOpenPoint(new Point(x - 1, y),point2);
        this.addNearOpenPoint(new Point(x + 1, y),point2);
        this.addNearOpenPoint(new Point(x, y - 1),point2);
        this.addNearOpenPoint(new Point(x, y + 1),point2);
        this.addNearOpenPoint(new Point(x - 1, y - 1),point2);
        this.addNearOpenPoint(new Point(x - 1, y + 1),point2);
        this.addNearOpenPoint(new Point(x + 1, y - 1),point2);
        this.addNearOpenPoint(new Point(x + 1, y + 1),point2);
        if(this.nearOutMap.size()==0){
            List<Point> list = new ArrayList<Point>(openMap.values());
            Collections.sort(list, new Comparator<Point>() {
                @Override
                public int compare(Point o1, Point o2) {
                    int l1 = o1.gCost;
                    int l2 = o2.gCost;
                    if (l1 > l2) {
                        return 1;
                    } else if (l1 < l2) {
                        return -1;
                    } else {
                        return 0;
                    }
                }
            });
            if (list.size() > 0) {
                Point p = list.get(0);
                this.closeMap.put(p.getKey(), p);
                this.openMap.remove(p.getKey());
                this.toNearPoint(list.get(0),point2);
            }
        }
    }

    private void addNearOpenPoint(Point point,Point point2) {
        String key = point.getKey();
        int gCost = this.getGuessLength(point.x, point.y, point2.x,
                point2.y);
        point.gCost = gCost;
        if (this.barrier.contains(point)) {
            if (!this.openMap.containsKey(key)
                    && !this.closeMap.containsKey(key)) {
                this.openMap.put(key, point);
            }
        } else {
            this.nearOutMap.put(key, point);
        }

    }

    public Map<String, Point> getOpenMap() {
        return openMap;
    }

    public void setOpenMap(Map<String, Point> openMap) {
        this.openMap = openMap;
    }

    public Map<String, Point> getCloseMap() {
        return closeMap;
    }

    public void setCloseMap(Map<String, Point> closeMap) {
        this.closeMap = closeMap;
    }

    public Set<Point> getBarrier() {
        return barrier;
    }

    public void setBarrier(Set<Point> barrier) {
        this.barrier = barrier;
    }

    public Point getEndPoint() {
        return endPoint;
    }

    public void setEndPoint(Point endPoint) {
        this.endPoint = endPoint;
    }

    public Point getStartPoint() {
        return startPoint;
    }

    public void setStartPoint(Point startPoint) {
        this.startPoint = startPoint;
    }

}