A*尋路

Jame!發表於2024-03-30

A*尋路演算法

在開始節點尋找四周節點,然後計算每個節點到終點需要走的步數,優先從最少的步數的節點開始走
每個節點都記錄是如何過來的,在最後找到終點後反向獲取整個路程
效果:


package test;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Jame!
 * @date 2024/3/30 上午 9:26
 */
public class Demo {

    static class Position {
        int x;
        int y;
    }

    static class MapItem {
        public MapItem(int type) {
            this.type = type;
        }
        public int type;
        /**
         * 0未走過
         * 1上
         * 2下
         * 3左
         * 4右
         */
        public int direction;
    }

    /**
     * 0路
     * 1障礙物
     * 2終點
     * 3起點
     */
    static int[][] map = {
            {3, 1, 0, 0, 0, 0, 0, 0},
            {0, 1, 0, 1, 0, 0, 0, 0},
            {0, 1, 0, 1, 0, 0, 0, 0},
            {0, 1, 0, 0, 0, 0, 0, 0},
            {0, 1, 0, 1, 0, 0, 0, 0},
            {0, 1, 0, 1, 0, 0, 0, 1},
            {0, 1, 0, 1, 0, 1, 1, 0},
            {0, 0, 0, 1, 0, 0, 0, 2}

    };

    static ArrayList<MapItem> pathItem = new ArrayList<>();
    static ArrayList<Position> path = new ArrayList<>();


    static MapItem[][] mapItems = null;

    static int successX = -1, successY = -1;


    public static void main(String[] args) {

        initMapItems();
        int result = find(0, 0, 7, 7);
        if (result == 2) {
            aa(successX, successY);
            System.out.println("找到路");
        } else {
            System.out.println("沒有路");
        }

        printResult();
    }

    /**
     * 1上
     * 2下
     * 3左
     * 4右
     */
    public static void aa(int currentX, int currentY) {
        MapItem item = mapItems[currentX][currentY];
        pathItem.add(item);
        Position position = new Position();
        position.x = currentX;
        position.y = currentY;
        path.add(position);
        if (item.type == 3) {
            return;
        }
        if (item.direction == 1) {
            aa(currentX + 1, currentY);
        } else if (item.direction == 2) {
            aa(currentX - 1, currentY);
        } else if (item.direction == 3) {
            aa(currentX, currentY + 1);
        } else if (item.direction == 4) {
            aa(currentX, currentY - 1);
        }
    }


    public static int computeEstimate(int currentX, int currentY, int endX, int endY) {
        //算出最少走的路
        int estimateX, estimateY;
        if (currentX < endX) {
            estimateX = endX - currentX;
        } else {
            estimateX = currentX - endX;
        }
        if (currentY < endY) {
            estimateY = endY - currentY;
        } else {
            estimateY = currentY - endY;
        }
        return estimateX + estimateY;
    }


    public static int find(int currentX, int currentY, int endX, int endY) {
        return move(currentX, currentY, endX, endY);
    }

    public static int move(int currentX, int currentY, int endX, int endY) {
        HashMap<String, Integer> mapEstimate = new HashMap<>();
        int top = -1, bottom = -1, left = -1, right = -1;
        if (currentY + 1 != map[currentX].length) {
            right = computeEstimate(currentX, currentY + 1, endX, endY);
        }
        if (currentY != 0) {
            left = computeEstimate(currentX, currentY - 1, endX, endY);
        }
        if (currentX != 0) {
            top = computeEstimate(currentX - 1, currentY, endX, endY);
        }
        if (currentX + 1 != map.length) {
            bottom = computeEstimate(currentX + 1, currentY, endX, endY);
        }

        if (top != -1 && mapItems[currentX - 1][currentY].direction != -1) {
            mapEstimate.put("top", top);
        }
        if (bottom != -1 && mapItems[currentX + 1][currentY].direction != -1) {
            mapEstimate.put("bottom", bottom);
        }
        if (left != -1 && mapItems[currentX][currentY - 1].direction != -1) {
            mapEstimate.put("left", left);
        }
        if (right != -1 && mapItems[currentX][currentY + 1].direction != -1) {
            mapEstimate.put("right", right);
        }
        //排序-將步數少排在前面,優先嚐試
        List<Map.Entry<String, Integer>> entries1 = mapEstimate.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toList());
        for (Map.Entry<String, Integer> entry : entries1) {
            String key = entry.getKey();
            int result = -1;
            if ("top".equals(key)) {
                result = findTop(currentX - 1, currentY, endX, endY);
            } else if ("bottom".equals(key)) {
                result = findBottom(currentX + 1, currentY, endX, endY);
            } else if ("right".equals(key)) {
                result = findRight(currentX, currentY + 1, endX, endY);
            } else if ("left".equals(key)) {
                result = findLeft(currentX, currentY - 1, endX, endY);
            }
            if (result == 2) {
                return 2;
            }
        }
        return -1;
    }

    public static int findRight(int currentX, int currentY, int endX, int endY) {
        MapItem mapItem = mapItems[currentX][currentY];
        if (mapItem.direction != 0 || mapItem.type == 1) {
            return mapItem.type;
        }

        mapItem.direction = 4;
        if (mapItem.type == 2) {
            successX = currentX;
            successY = currentY - 1;
            return mapItem.type;
        }
        return move(currentX, currentY, endX, endY);
    }

    public static int findLeft(int currentX, int currentY, int endX, int endY) {
        MapItem mapItem = mapItems[currentX][currentY];
        if (mapItem.direction != 0 || mapItem.type == 1) {
            return mapItem.type;
        }
        mapItem.direction = 3;
        if (mapItem.type == 2) {
            successX = currentX;
            successY = currentY + 1;
            return mapItem.type;
        }
        return move(currentX, currentY, endX, endY);
    }

    public static int findTop(int currentX, int currentY, int endX, int endY) {
        MapItem mapItem = mapItems[currentX][currentY];
        if (mapItem.direction != 0 || mapItem.type == 1) {
            return mapItem.type;
        }
        mapItem.direction = 1;
        if (mapItem.type == 2) {
            successX = currentX + 1;
            successY = currentY;
            return mapItem.type;
        }
        return move(currentX, currentY, endX, endY);
    }

    public static int findBottom(int currentX, int currentY, int endX, int endY) {
        MapItem mapItem = mapItems[currentX][currentY];
        if (mapItem.direction != 0 || mapItem.type == 1) {
            return mapItem.type;
        }
        mapItem.direction = 2;
        if (mapItem.type == 2) {
            successX = currentX - 1;
            successY = currentY;
            return mapItem.type;
        }
        return move(currentX, currentY, endX, endY);
    }


    public static void initMapItems() {
        mapItems = new MapItem[map.length][map[0].length];
        for (int i = 0; i < map.length; i++) {
            for (int i1 = 0; i1 < map[i].length; i1++) {
                mapItems[i][i1] = new MapItem(map[i][i1]);
            }
        }
    }

    public static void printResult() {
        for (MapItem[] mapItem : mapItems) {
            for (MapItem item : mapItem) {
                if (item.type == 1) {
                    System.out.print("牆");
                } else if (item.type == 2) {
                    System.out.print("終");
                } else if (item.type == 3) {
                    System.out.print("起");
                } else if (pathItem.contains(item)) {
                    System.out.print("走");
                } else {
                    System.out.print("口");
                }
            }
            System.out.println();
        }
        Collections.reverse(path);
        for (Position position : path) {
            System.out.print(" [" + position.x + "=" + position.y + "] ");
        }
    }

}




相關文章