/// module es { /** * 计算路径给定的IAstarGraph和开始/目标位置 */ export class AStarPathfinder { /** * 尽可能从开始到目标找到一条路径。如果没有找到路径,则返回null。 * @param graph * @param start * @param goal */ public static search(graph: IAstarGraph, start: T, goal: T) { let foundPath = false; let cameFrom = new Map(); cameFrom.set(start, start); let costSoFar = new Map(); let frontier = new PriorityQueue>(1000); frontier.enqueue(new AStarNode(start), 0); costSoFar.set(start, 0); while (frontier.count > 0) { let current = frontier.dequeue(); if (current.data instanceof Vector2 && goal instanceof Vector2 && current.data.equals(goal)) { foundPath = true; break; } else if (current.data == goal){ foundPath = true; break; } graph.getNeighbors(current.data).forEach(next => { let newCost = costSoFar.get(current.data) + graph.cost(current.data, next); if (!this.hasKey(costSoFar, next) || newCost < costSoFar.get(next)) { costSoFar.set(next, newCost); let priority = newCost + graph.heuristic(next, goal); frontier.enqueue(new AStarNode(next), priority); cameFrom.set(next, current.data); } }); } return foundPath ? this.recontructPath(cameFrom, start, goal) : null; } /** * 从cameFrom字典重新构造路径 * @param cameFrom * @param start * @param goal */ public static recontructPath(cameFrom: Map, start: T, goal: T): T[] { let path = []; let current = goal; path.push(goal); while (current != start) { current = this.getKey(cameFrom, current); path.push(current); } path.reverse(); return path; } private static hasKey(map: Map, compareKey: T) { let iterator = map.keys(); let r: IteratorResult; while (r = iterator.next() , !r.done) { if (r.value instanceof Vector2 && compareKey instanceof Vector2 && r.value.equals(compareKey)) return true; else if (r.value == compareKey) return true; } return false; } private static getKey(map: Map, compareKey: T) { let iterator = map.keys(); let valueIterator = map.values(); let r: IteratorResult; let v: IteratorResult; while (r = iterator.next(), v = valueIterator.next(), !r.done) { if (r.value instanceof Vector2 && compareKey instanceof Vector2 && r.value.equals(compareKey)) return v.value; else if (r.value == compareKey) return v.value; } return null; } } /** * 使用PriorityQueue需要的额外字段将原始数据封装在一个小类中 */ class AStarNode extends PriorityQueueNode { public data: T; constructor(data: T) { super(); this.data = data; } } }