Files
esengine/source/src/AI/Pathfinding/AStar/AStarPathfinder.ts

111 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
///<reference path="./PriorityQueueNode.ts" />
module es {
/**
* 计算路径给定的IAstarGraph和开始/目标位置
*/
export class AStarPathfinder {
/**
* 尽可能从开始到目标找到一条路径。如果没有找到路径则返回null。
* @param graph
* @param start
* @param goal
*/
public static search<T>(graph: IAstarGraph<T>, start: T, goal: T) {
let foundPath = false;
let cameFrom = new Map<T, T>();
cameFrom.set(start, start);
let costSoFar = new Map<T, number>();
let frontier = new PriorityQueue<AStarNode<T>>(1000);
frontier.enqueue(new AStarNode<T>(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<T>(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<T>(cameFrom: Map<T, T>, 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<T>(map: Map<T, number>, compareKey: T) {
let iterator = map.keys();
let r: IteratorResult<T>;
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<T>(map: Map<T, T>, compareKey: T) {
let iterator = map.keys();
let valueIterator = map.values();
let r: IteratorResult<T>;
let v: IteratorResult<T>;
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<T> extends PriorityQueueNode {
public data: T;
constructor(data: T) {
super();
this.data = data;
}
}
}