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 + "] ");
}
}
}