| | |
| | | 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("地图不存在"); |
| | | } |
| | |
| | | return navigateNodeList; |
| | | } |
| | | |
| | | public List<List<NavigateNode>> getRgvTrackMap() { |
| | | public List<List<NavigateNode>> getRgvTrackMap(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("地图不存在"); |
| | | } |
| | |
| | | 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) { |
| | | //获取当前结点的x, y |
| | | int x = current_node.getX(); |