astar 注释

This commit is contained in:
yhh
2020-07-09 16:36:42 +08:00
parent a80bb4b6f3
commit 877fc4c9bf
10 changed files with 153 additions and 3 deletions
+1
View File
@@ -61,6 +61,7 @@ declare class PriorityQueue<T extends PriorityQueueNode> {
constructor(maxNodes: number);
clear(): void;
readonly count: number;
readonly maxSize: number;
contains(node: T): boolean;
enqueue(node: T, priority: number): void;
dequeue(): T;
+15
View File
@@ -418,7 +418,22 @@ var PriorityQueue = (function () {
enumerable: true,
configurable: true
});
Object.defineProperty(PriorityQueue.prototype, "maxSize", {
get: function () {
return this._nodes.length - 1;
},
enumerable: true,
configurable: true
});
PriorityQueue.prototype.contains = function (node) {
if (!node) {
console.error("node cannot be null");
return false;
}
if (node.queueIndex < 0 || node.queueIndex >= this._nodes.length) {
console.error("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?");
return false;
}
return (this._nodes[node.queueIndex] == node);
};
PriorityQueue.prototype.enqueue = function (node, priority) {
File diff suppressed because one or more lines are too long
+1
View File
@@ -61,6 +61,7 @@ declare class PriorityQueue<T extends PriorityQueueNode> {
constructor(maxNodes: number);
clear(): void;
readonly count: number;
readonly maxSize: number;
contains(node: T): boolean;
enqueue(node: T, priority: number): void;
dequeue(): T;
+15
View File
@@ -418,7 +418,22 @@ var PriorityQueue = (function () {
enumerable: true,
configurable: true
});
Object.defineProperty(PriorityQueue.prototype, "maxSize", {
get: function () {
return this._nodes.length - 1;
},
enumerable: true,
configurable: true
});
PriorityQueue.prototype.contains = function (node) {
if (!node) {
console.error("node cannot be null");
return false;
}
if (node.queueIndex < 0 || node.queueIndex >= this._nodes.length) {
console.error("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?");
return false;
}
return (this._nodes[node.queueIndex] == node);
};
PriorityQueue.prototype.enqueue = function (node, priority) {
+1 -1
View File
File diff suppressed because one or more lines are too long
@@ -3,6 +3,12 @@
* IAstarGraph和开始/
*/
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>();
@@ -60,6 +66,12 @@ class AStarPathfinder {
return 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;
@@ -33,13 +33,18 @@ class AstarGridGraph implements IAstarGraph<Vector2> {
}
/**
*
* walls是不可逾越的
* @param node
*/
public isNodePassable(node: Vector2): boolean {
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
}
/**
* AStarPathfinder.search的快捷方式
* @param start
* @param goal
*/
public search(start: Vector2, goal: Vector2){
return AStarPathfinder.search(this, start, goal);
}
@@ -1,5 +1,22 @@
/**
* graph的接口AstarPathfinder.search方法
*/
interface IAstarGraph<T> {
/**
* getNeighbors方法应该返回从传入的节点可以到达的任何相邻节点
* @param node
*/
getNeighbors(node: T): Array<T>;
/**
* from到to的成本
* @param from
* @param to
*/
cost(from: T, to: T): number;
/**
* node到to的启发式WeightedGridGraph了解常用的Manhatten方法
* @param node
* @param goal
*/
heuristic(node: T, goal: T);
}
@@ -1,27 +1,74 @@
/**
* 使 O(1)
* 使5-10
* IPriorityQueue.contains()
*/
class PriorityQueue<T extends PriorityQueueNode> {
private _numNodes: number;
private _nodes: T[];
private _numNodesEverEnqueued;
/**
*
* @param maxNodes (undefined的行为)
*/
constructor(maxNodes: number) {
this._numNodes = 0;
this._nodes = new Array(maxNodes + 1);
this._numNodesEverEnqueued = 0;
}
/**
*
* O(n)
*/
public clear() {
this._nodes.splice(1, this._numNodes);
this._numNodes = 0;
}
/**
*
* O(1)
*/
public get count() {
return this._numNodes;
}
/**
* (Count == MaxSize)undefined的行为
* O(1)
*/
public get maxSize() {
return this._nodes.length - 1;
}
/**
* (O(1))
* O (1)
* @param node
*/
public contains(node: T): boolean {
if (!node){
console.error("node cannot be null");
return false;
}
if (node.queueIndex < 0 || node.queueIndex >= this._nodes.length){
console.error("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?");
return false;
}
return (this._nodes[node.queueIndex] == node);
}
/**
*
* undefinedundefined
* O(log n)
* @param node
* @param priority
*/
public enqueue(node: T, priority: number) {
node.priority = priority;
this._numNodes++;
@@ -31,12 +78,21 @@ class PriorityQueue<T extends PriorityQueueNode> {
this.cascadeUp(this._nodes[this._numNodes]);
}
/**
* (;)undefined
* O(log n)
*/
public dequeue(): T {
let returnMe = this._nodes[1];
this.remove(returnMe);
return returnMe;
}
/**
* Contains()
* O(log n)
* @param node
*/
public remove(node: T) {
if (node.queueIndex == this._numNodes) {
this._nodes[this._numNodes] = null;
@@ -52,6 +108,9 @@ class PriorityQueue<T extends PriorityQueueNode> {
this.onNodeUpdated(formerLastNode);
}
/**
* /
*/
public isValidQueue(): boolean {
for (let i = 1; i < this._nodes.length; i++) {
if (this._nodes[i]) {
@@ -71,24 +130,29 @@ class PriorityQueue<T extends PriorityQueueNode> {
}
private onNodeUpdated(node: T) {
// 将更新后的节点按适当的方式向上或向下冒泡
let parentIndex = Math.floor(node.queueIndex / 2);
let parentNode = this._nodes[parentIndex];
if (parentIndex > 0 && this.hasHigherPriority(node, parentNode)) {
this.cascadeUp(node);
} else {
// 注意,如果parentNode == node(即节点是根),则将调用CascadeDown。
this.cascadeDown(node);
}
}
private cascadeDown(node: T) {
// 又名Heapify-down
let newParent: T;
let finalQueueIndex = node.queueIndex;
while (true) {
newParent = node;
let childLeftIndex = 2 * finalQueueIndex;
// 检查左子节点的优先级是否高于当前节点
if (childLeftIndex > this._numNodes) {
// 这可以放在循环之外,但是我们必须检查newParent != node两次
node.queueIndex = finalQueueIndex;
this._nodes[finalQueueIndex] = node;
break;
@@ -99,6 +163,7 @@ class PriorityQueue<T extends PriorityQueueNode> {
newParent = childLeft;
}
// 检查右子节点的优先级是否高于当前节点或左子节点
let childRightIndex = childLeftIndex + 1;
if (childRightIndex <= this._numNodes) {
let childRight = this._nodes[childRightIndex];
@@ -107,13 +172,17 @@ class PriorityQueue<T extends PriorityQueueNode> {
}
}
// 如果其中一个子节点具有更高(更小)的优先级,则交换并继续级联
if (newParent != node) {
// 将新的父节点移动到它的新索引
// 节点将被移动一次,这样做比调用Swap()少一个赋值操作。
this._nodes[finalQueueIndex] = newParent;
let temp = newParent.queueIndex;
newParent.queueIndex = finalQueueIndex;
finalQueueIndex = temp;
} else {
// 参见上面的笔记
node.queueIndex = finalQueueIndex;
this._nodes[finalQueueIndex] = node;
break;
@@ -121,13 +190,20 @@ class PriorityQueue<T extends PriorityQueueNode> {
}
}
/**
*
* @param node
*/
private cascadeUp(node: T) {
// 又名Heapify-up
let parent = Math.floor(node.queueIndex / 2);
while (parent >= 1) {
let parentNode = this._nodes[parent];
if (this.hasHigherPriority(parentNode, node))
break;
// 节点具有较低的优先级值,因此将其向上移动到堆中
// 出于某种原因,使用Swap()比使用单独的操作更快,如CascadeDown()
this.swap(node, parentNode);
parent = Math.floor(node.queueIndex / 2);
@@ -135,14 +211,22 @@ class PriorityQueue<T extends PriorityQueueNode> {
}
private swap(node1: T, node2: T) {
// 交换节点
this._nodes[node1.queueIndex] = node2;
this._nodes[node2.queueIndex] = node1;
// 交换他们的indicies
let temp = node1.queueIndex;
node1.queueIndex = node2.queueIndex;
node2.queueIndex = temp;
}
/**
* higher的优先级高于lowertruefalse
* HasHigherPriority()()false
* @param higher
* @param lower
*/
private hasHigherPriority(higher: T, lower: T) {
return (higher.priority < lower.priority ||
(higher.priority == lower.priority && higher.insertionIndex < lower.insertionIndex));