| | |
| | | import com.zy.common.model.NavigateNode; |
| | | import com.zy.core.enums.MapNodeType; |
| | | import java.util.*; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | import java.util.function.BiFunction; |
| | | |
| | | /** |
| | | * A*算法实现类 |
| | |
| | | //用来存放已经出现过的结点。 |
| | | Map<String, Integer> bestGMap = new HashMap<>(); |
| | | |
| | | public List<List<NavigateNode>> getStationMap() { |
| | | public List<List<NavigateNode>> getStationMap(int lev) { |
| | | BasMapService basMapService = SpringUtils.getBean(BasMapService.class); |
| | | BasMap basMap = basMapService.selectOne(new EntityWrapper<BasMap>().eq("lev", 1)); |
| | | BasMap basMap = basMapService.selectOne(new EntityWrapper<BasMap>().eq("lev", lev)); |
| | | if (basMap == null) { |
| | | throw new CoolException("地图不存在"); |
| | | } |
| | |
| | | |
| | | JSONObject valueObj = JSON.parseObject(map.getString("value")); |
| | | List<String> directionList = valueObj.getJSONArray("direction").toJavaList(String.class); |
| | | navigateNode.setDirectionList(directionList); |
| | | }else { |
| | | navigateNode.setValue(MapNodeType.DISABLE.id); |
| | | } |
| | | |
| | | navigateNode.setNodeType(nodeType); |
| | | navigateNode.setNodeValue(map.getString("value")); |
| | | navigateNodeRow.add(navigateNode); |
| | | } |
| | | navigateNodeList.add(navigateNodeRow); |
| | | } |
| | | |
| | | return navigateNodeList; |
| | | } |
| | | |
| | | public List<List<NavigateNode>> getRgvTrackMap(int lev) { |
| | | BasMapService basMapService = SpringUtils.getBean(BasMapService.class); |
| | | BasMap basMap = basMapService.selectOne(new EntityWrapper<BasMap>().eq("lev", lev)); |
| | | if (basMap == null) { |
| | | throw new CoolException("地图不存在"); |
| | | } |
| | | |
| | | List<List<JSONObject>> dataList = JSON.parseObject(basMap.getData(), List.class); |
| | | |
| | | List<List<NavigateNode>> navigateNodeList = new ArrayList<>(); |
| | | for (int i = 0; i < dataList.size(); i++) { |
| | | List<JSONObject> row = dataList.get(i); |
| | | List<NavigateNode> navigateNodeRow = new ArrayList<>(); |
| | | for (int j = 0; j < row.size(); j++) { |
| | | JSONObject map = row.get(j); |
| | | NavigateNode navigateNode = new NavigateNode(i, j); |
| | | |
| | | String nodeType = map.getString("type"); |
| | | if(nodeType == null) { |
| | | navigateNode.setValue(MapNodeType.DISABLE.id); |
| | | }else if(nodeType.equals("rgv")){ |
| | | navigateNode.setValue(MapNodeType.NORMAL_PATH.id); |
| | | JSONObject valueObj = JSON.parseObject(map.getString("value")); |
| | | |
| | | //RGV暂不控制行走方向,默认上下左右都可走 |
| | | List<String> directionList = new ArrayList<>(); |
| | | directionList.add("top"); |
| | | directionList.add("bottom"); |
| | | directionList.add("left"); |
| | | directionList.add("right"); |
| | | navigateNode.setDirectionList(directionList); |
| | | }else { |
| | | navigateNode.setValue(MapNodeType.DISABLE.id); |
| | |
| | | } |
| | | //如果遍历完所有出现的结点都没有找到最终的结点,返回null |
| | | return null; |
| | | } |
| | | |
| | | public List<List<NavigateNode>> allSimplePaths( |
| | | List<List<NavigateNode>> map, |
| | | NavigateNode start, |
| | | NavigateNode end, |
| | | int maxDepth, // 最大步数(边数). 建议:50/100/200;<=0 表示不限制(不建议) |
| | | int maxPaths, // 最大返回条数. 建议:100/500/2000;<=0 表示不限制(不建议) |
| | | int maxCost // 最大总代价(含拐点惩罚). <=0 表示不限制 |
| | | ) { |
| | | List<List<NavigateNode>> results = new ArrayList<>(); |
| | | if (map == null || map.isEmpty() || map.get(0).isEmpty()) return results; |
| | | if (start == null || end == null) return results; |
| | | if (start.getValue() == MapNodeType.DISABLE.id || end.getValue() == MapNodeType.DISABLE.id) return results; |
| | | |
| | | // visited 用坐标 key,避免 NavigateNode equals/hashCode 不可靠导致重复判断失效 |
| | | Set<String> visited = new HashSet<>(map.size() * map.get(0).size() * 2); |
| | | LinkedList<NavigateNode> path = new LinkedList<>(); |
| | | |
| | | String startKey = keyOf(start); |
| | | visited.add(startKey); |
| | | path.add(start); |
| | | |
| | | AtomicInteger pathCount = new AtomicInteger(0); |
| | | |
| | | dfsAllSimplePaths(map, start, end, |
| | | visited, path, results, |
| | | 0, // depth |
| | | 0, // cost |
| | | maxDepth, maxPaths, maxCost, |
| | | pathCount |
| | | ); |
| | | |
| | | return results; |
| | | } |
| | | |
| | | /** |
| | | * DFS + 回溯:枚举所有简单路径(路径中不允许重复节点) |
| | | */ |
| | | private void dfsAllSimplePaths( |
| | | List<List<NavigateNode>> map, |
| | | NavigateNode current, |
| | | NavigateNode end, |
| | | Set<String> visited, |
| | | LinkedList<NavigateNode> path, |
| | | List<List<NavigateNode>> results, |
| | | int depth, // 当前步数(边数) |
| | | int cost, // 当前总代价(你可以认为是 g) |
| | | int maxDepth, |
| | | int maxPaths, |
| | | int maxCost, |
| | | AtomicInteger pathCount |
| | | ) { |
| | | // 防爆:条数限制 |
| | | if (maxPaths > 0 && pathCount.get() >= maxPaths) return; |
| | | |
| | | // 到达终点:收集路径 |
| | | if (current.getX() == end.getX() && current.getY() == end.getY()) { |
| | | results.add(new ArrayList<>(path)); |
| | | pathCount.incrementAndGet(); |
| | | return; |
| | | } |
| | | |
| | | // 防爆:深度限制(depth 表示已走的边数) |
| | | if (maxDepth > 0 && depth >= maxDepth) return; |
| | | |
| | | // 扩展邻居(严格复用你自己的可行走方向规则) |
| | | ArrayList<NavigateNode> neighbors = extend_current_node(map, current); |
| | | if (neighbors == null || neighbors.isEmpty()) return; |
| | | |
| | | for (NavigateNode next : neighbors) { |
| | | // 防爆:条数限制 |
| | | if (maxPaths > 0 && pathCount.get() >= maxPaths) return; |
| | | |
| | | if (next == null) continue; |
| | | if (next.getValue() == MapNodeType.DISABLE.id) continue; |
| | | |
| | | String nk = keyOf(next); |
| | | |
| | | // 简单路径:不允许重复节点 |
| | | if (visited.contains(nk)) continue; |
| | | |
| | | // 你的代价规则:每步 1 + 拐点惩罚 |
| | | int stepCost = 1 + calcNodeExtraCost(current, next, end); |
| | | int newCost = cost + stepCost; |
| | | |
| | | // 防爆:总代价限制 |
| | | if (maxCost > 0 && newCost > maxCost) continue; |
| | | |
| | | // 进入 |
| | | visited.add(nk); |
| | | path.addLast(next); |
| | | |
| | | dfsAllSimplePaths(map, next, end, |
| | | visited, path, results, |
| | | depth + 1, |
| | | newCost, |
| | | maxDepth, maxPaths, maxCost, |
| | | pathCount |
| | | ); |
| | | |
| | | // 回溯 |
| | | path.removeLast(); |
| | | visited.remove(nk); |
| | | } |
| | | } |
| | | |
| | | private String keyOf(NavigateNode n) { |
| | | return n.getX() + "_" + n.getY(); |
| | | } |
| | | |
| | | public ArrayList<NavigateNode> extend_current_node(List<List<NavigateNode>> map, NavigateNode current_node) { |
| | |
| | | return null; |
| | | } |
| | | |
| | | public NavigateNode findTrackSiteNoNavigateNode(List<List<NavigateNode>> map, int trackSiteNo) { |
| | | for(int x = 0; x < map.size(); x++) { |
| | | for(int y = 0; y < map.get(0).size(); y++) { |
| | | NavigateNode node = map.get(x).get(y); |
| | | if("rgv".equals(node.getNodeType())) { |
| | | JSONObject valueObj = JSON.parseObject(node.getNodeValue()); |
| | | if(valueObj.getInteger("trackSiteNo") == trackSiteNo) { |
| | | return node; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | //------------------A*启发函数------------------// |
| | | |
| | | //计算通过现在的结点的位置和最终结点的位置计算H值(曼哈顿法:坐标分别取差值相加) |