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

111 lines
3.8 KiB
TypeScript
Raw Normal View History

2020-06-09 19:45:09 +08:00
///<reference path="./PriorityQueueNode.ts" />
2020-07-23 11:00:46 +08:00
module es {
2020-07-09 16:36:42 +08:00
/**
2020-07-23 11:00:46 +08:00
* IAstarGraph和开始/
2020-07-09 16:36:42 +08:00
*/
2020-07-23 11:00:46 +08:00
export class AStarPathfinder {
/**
* null
* @param graph
* @param start
* @param goal
*/
2020-07-28 16:25:20 +08:00
public static search<T>(graph: IAstarGraph<T>, start: T, goal: T) {
2020-07-23 11:00:46 +08:00
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);
2020-07-28 16:25:20 +08:00
while (frontier.count > 0) {
2020-07-23 11:00:46 +08:00
let current = frontier.dequeue();
2020-09-14 17:54:17 +08:00
if (current.data instanceof Vector2 && goal instanceof Vector2 && current.data.equals(goal)) {
foundPath = true;
break;
} else if (current.data == goal){
2020-07-23 11:00:46 +08:00
foundPath = true;
break;
}
2020-06-09 19:45:09 +08:00
2020-07-23 11:00:46 +08:00
graph.getNeighbors(current.data).forEach(next => {
let newCost = costSoFar.get(current.data) + graph.cost(current.data, next);
2020-07-28 16:25:20 +08:00
if (!this.hasKey(costSoFar, next) || newCost < costSoFar.get(next)) {
2020-07-23 11:00:46 +08:00
costSoFar.set(next, newCost);
let priority = newCost + graph.heuristic(next, goal);
frontier.enqueue(new AStarNode<T>(next), priority);
cameFrom.set(next, current.data);
}
});
}
2020-06-09 19:45:09 +08:00
2020-07-23 11:00:46 +08:00
return foundPath ? this.recontructPath(cameFrom, start, goal) : null;
}
2020-06-09 19:45:09 +08:00
2020-07-28 16:25:20 +08:00
/**
* 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) {
2020-07-23 11:00:46 +08:00
let iterator = map.keys();
let r: IteratorResult<T>;
while (r = iterator.next() , !r.done) {
2020-09-14 17:54:17 +08:00
if (r.value instanceof Vector2 && compareKey instanceof Vector2 && r.value.equals(compareKey))
return true;
else if (r.value == compareKey)
2020-07-23 11:00:46 +08:00
return true;
2020-06-09 19:45:09 +08:00
}
2020-07-23 11:00:46 +08:00
return false;
2020-06-09 19:45:09 +08:00
}
2020-07-28 16:25:20 +08:00
private static getKey<T>(map: Map<T, T>, compareKey: T) {
2020-07-23 11:00:46 +08:00
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) {
2020-09-14 17:54:17 +08:00
if (r.value instanceof Vector2 && compareKey instanceof Vector2 && r.value.equals(compareKey))
return v.value;
else if (r.value == compareKey)
2020-07-23 11:00:46 +08:00
return v.value;
}
2020-06-09 19:45:09 +08:00
2020-07-23 11:00:46 +08:00
return null;
2020-06-09 19:45:09 +08:00
}
}
2020-07-09 16:36:42 +08:00
/**
2020-07-23 11:00:46 +08:00
* 使PriorityQueue需要的额外字段将原始数据封装在一个小类中
2020-07-09 16:36:42 +08:00
*/
2020-07-23 11:00:46 +08:00
export class AStarNode<T> extends PriorityQueueNode {
public data: T;
2020-06-09 19:45:09 +08:00
2020-07-28 16:25:20 +08:00
constructor(data: T) {
2020-07-23 11:00:46 +08:00
super();
this.data = data;
}
2020-06-09 19:45:09 +08:00
}
}