package com.zy.common.utils; import com.zy.common.model.NavigateNode; import java.util.ArrayList; import java.util.List; import java.util.PriorityQueue; /** * A*算法实现类 */ public class NavigateSolution { // -1 -> 墙壁, 1 -> 起点 2 -> 终点 3-> 母轨 4->站点 int[][] map = {{}}; public NavigateSolution() { //载入地图 NavigateMapData mapData = new NavigateMapData(); int[][] data = mapData.getData(); this.map = data; } public NavigateSolution(Integer mapType, Integer lev, List whitePoints, List shuttlePoints) { //载入地图指定层高地图 NavigateMapData mapData = new NavigateMapData(lev); int[][] data = mapData.getDataFromRedis(mapType, whitePoints, shuttlePoints); if (data == null) { data = mapData.getData(mapType, whitePoints, shuttlePoints); } this.map = data; } public NavigateSolution(int[][] data) { this.map = data; } // Open表用优先队列 public PriorityQueue Open = new PriorityQueue(); //Close表用普通的数组 public ArrayList Close = new ArrayList(); //Exist表用来存放已经出现过的结点。 public ArrayList Exist = new ArrayList(); public NavigateNode astarSearch(NavigateNode start, NavigateNode end) { //把第一个开始的结点加入到Open表中 this.Open.add(start); //把出现过的结点加入到Exist表中 this.Exist.add(start); //主循环 while (Open.size() > 0) { //取优先队列顶部元素并且把这个元素从Open表中删除 NavigateNode current_node = Open.poll(); //将这个结点加入到Close表中 Close.add(current_node); //对当前结点进行扩展,得到一个四周结点的数组 ArrayList neighbour_node = extend_current_node(current_node); //对这个结点遍历,看是否有目标结点出现 for (NavigateNode node : neighbour_node) { // G + H + E (对启发函数增加去拐点方案calcNodeExtraCost) int gCost = calcNodeCost(current_node, node) * calcNodeExtraCost(current_node, node, end); if (node.getX() == end.getX() && node.getY() == end.getY()) {//找到目标结点就返回 //init_node操作把这个邻居结点的父节点设置为当前结点 //并且计算出G, F, H等值 node.init_node(current_node, end); return node; } //(对启发函数增加去拐点方案calcNodeExtraCost) if (is_exist(node)) { if (gCost < node.getG()) { node.setFather(current_node); node.setG(gCost); node.setF(node.getG() + node.getH()); } }else { //没出现过的结点加入到Open表中并且设置父节点 //进行计算对G, F, H 等值 node.init_node(current_node, end); node.setG(gCost); node.setH(calcNodeCost(node, end)); node.setF(node.getG() + node.getH()); Open.add(node); Exist.add(node); } } } //如果遍历完所有出现的结点都没有找到最终的结点,返回null return null; } public ArrayList extend_current_node(NavigateNode current_node) { //获取当前结点的x, y int x = current_node.getX(); int y = current_node.getY(); //如果当前结点的邻结点合法,就加入到neighbour_node ArrayList neighbour_node = new ArrayList(); // if (map[x][y] == 0 || map[x][y] == 3) { // //只有子轨和母轨才能进行左右移动 // if (is_valid(x, y + 1)) // { // Node node = new Node(x, y + 1); // neighbour_node.add(node); // } // if (is_valid(x, y - 1)) // { // Node node = new Node(x, y - 1); // neighbour_node.add(node); // } // } // // if (map[x][y] == 3) { // //只有母轨才能进行上下移动 // if (is_valid(x + 1, y)) // { // Node node = new Node(x + 1, y); // neighbour_node.add(node); // } // if (is_valid(x - 1, y)) // { // Node node = new Node(x -1, y); // neighbour_node.add(node); // } // } if (map[x][y] == 3) { //母轨才能进行左右移动 if (is_valid(x, y + 1)) { NavigateNode node = new NavigateNode(x, y + 1); neighbour_node.add(node); } if (is_valid(x, y - 1)) { NavigateNode node = new NavigateNode(x, y - 1); neighbour_node.add(node); } } if (map[x][y] == 0 || map[x][y] == 3 || map[x][y] == 4 || map[x][y] == 5) { //子轨和母轨、输送线、充电桩才能进行上下移动 if (is_valid(x + 1, y)) { NavigateNode node = new NavigateNode(x + 1, y); neighbour_node.add(node); } if (is_valid(x - 1, y)) { NavigateNode node = new NavigateNode(x -1, y); neighbour_node.add(node); } } return neighbour_node; } public boolean is_valid(int x, int y) { // 如果结点的位置小于0,则不合法 if (map[x][y] < 0) return false; for (NavigateNode node : Exist) { //如果结点出现过,不合法 if (node.getX() == x && node.getY() == y) { return false; } if (is_exist(new NavigateNode(x, y))) { return false; } } //以上情况都没有则合法 return true; } public boolean is_exist(NavigateNode node) { for (NavigateNode exist_node : Exist) { if (node.getX() == exist_node.getX() && node.getY() == exist_node.getY()) { return true; } } return false; } //------------------A*启发函数------------------// //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) private int calcNodeCost(NavigateNode node1, NavigateNode node2) { return Math.abs(node2.getX() - node1.getX()) + Math.abs(node2.getY() - node1.getY()); } //去除拐点算法,给直线增加优先级 private int calcNodeExtraCost(NavigateNode currNode, NavigateNode nextNode, NavigateNode endNode) { // 第一个点或直线点 if (currNode.getFather() == null || nextNode.getX() == currNode.getFather().getX() || nextNode.getY() == currNode.getFather().getY()) { return 0; } // 拐向终点的点 if (nextNode.getX() == endNode.getX() || nextNode.getY() == endNode.getY()) { return 1; } // 普通拐点 /* 拐点判断逻辑 拿到父节点和下一节点 通过判断父节点和下一节点的x数据和y数据都不相同时,则表明当前坐标是一个拐点 */ return 10; } //------------------A*启发函数-end------------------// }