新增AI-GOAP目标导向计划与ASTAR寻路配合使用

This commit is contained in:
yhh
2020-10-29 11:22:01 +08:00
parent 85cc4b4ecc
commit 1a78dada61
17 changed files with 3045 additions and 19 deletions
+186 -4
View File
@@ -31,10 +31,6 @@ declare module es {
private static hasKey;
private static getKey;
}
class AStarNode<T> extends PriorityQueueNode {
data: T;
constructor(data: T);
}
}
declare module es {
class AstarGridGraph implements IAstarGraph<Vector2> {
@@ -188,6 +184,96 @@ declare module es {
private static getKey;
}
}
declare module es {
class AStarStorage {
static readonly MAX_NODES: number;
_opened: AStarNode[];
_closed: AStarNode[];
_numOpened: number;
_numClosed: number;
_lastFoundOpened: number;
_lastFoundClosed: number;
constructor();
clear(): void;
findOpened(node: AStarNode): AStarNode;
findClosed(node: AStarNode): AStarNode;
hasOpened(): boolean;
removeOpened(node: AStarNode): void;
removeClosed(node: AStarNode): void;
isOpen(node: AStarNode): boolean;
isClosed(node: AStarNode): boolean;
addToOpenList(node: AStarNode): void;
addToClosedList(node: AStarNode): void;
removeCheapestOpenNode(): AStarNode;
}
}
declare module es {
class AStarNode implements IEquatable<AStarNode>, IPoolable {
worldState: WorldState;
costSoFar: number;
heuristicCost: number;
costSoFarAndHeuristicCost: number;
action: Action;
parent: AStarNode;
parentWorldState: WorldState;
depth: number;
equals(other: AStarNode): boolean;
compareTo(other: AStarNode): number;
reset(): void;
clone(): AStarNode;
toString(): string;
}
class AStar {
static storage: AStarStorage;
static plan(ap: ActionPlanner, start: WorldState, goal: WorldState, selectedNodes?: AStarNode[]): Action[];
static reconstructPlan(goalNode: AStarNode, selectedNodes: AStarNode[]): Action[];
static calculateHeuristic(fr: WorldState, to: WorldState): number;
}
}
declare module es {
class Action {
name: string;
cost: number;
_preConditions: Set<[string, boolean]>;
_postConditions: Set<[string, boolean]>;
constructor(name?: string, cost?: number);
setPrecondition(conditionName: string, value: boolean): void;
setPostcondition(conditionName: string, value: boolean): void;
validate(): boolean;
toString(): string;
}
}
declare module es {
class ActionPlanner {
static readonly MAX_CONDITIONS: number;
conditionNames: string[];
_actions: Action[];
_viableActions: Action[];
_preConditions: WorldState[];
_postConditions: WorldState[];
_numConditionNames: number;
constructor();
createWorldState(): WorldState;
addAction(action: Action): void;
plan(startState: WorldState, goalState: WorldState, selectedNode?: any): Action[];
getPossibleTransitions(fr: WorldState): AStarNode[];
applyPostConditions(ap: ActionPlanner, actionnr: number, fr: WorldState): WorldState;
findConditionNameIndex(conditionName: string): any;
findActionIndex(action: Action): number;
}
}
declare module es {
class WorldState implements IEquatable<WorldState> {
values: number;
dontCare: number;
planner: ActionPlanner;
static create(planner: ActionPlanner): WorldState;
constructor(planner: ActionPlanner, values: number, dontcare: number);
set(conditionId: number, value: boolean): boolean;
equals(other: WorldState): boolean;
describe(planner: ActionPlanner): string;
}
}
declare module es {
class Core extends egret.DisplayObjectContainer {
static emitter: Emitter<CoreEvents>;
@@ -1071,6 +1157,46 @@ declare module es {
protected removeFromProcessors(entity: Entity): void;
}
}
declare module es {
class FasterDictionary<TKey, TValue> {
_values: TValue[];
_valuesInfo: FastNode[];
_buckets: number[];
_freeValueCellIndex: number;
_collisions: number;
constructor(size?: number);
getValuesArray(count: {
value: number;
}): TValue[];
readonly valuesArray: TValue[];
readonly count: number;
add(key: TKey, value: TValue): void;
addValue(key: TKey, value: TValue, indexSet: {
value: number;
}): boolean;
remove(key: TKey): boolean;
trim(): void;
clear(): void;
fastClear(): void;
containsKey(key: TKey): boolean;
tryGetValue(key: TKey): TValue;
tryFindIndex(key: TKey, findIndex: {
value: number;
}): boolean;
getDirectValue(index: number): TValue;
getIndex(key: TKey): number;
static updateLinkedList(index: number, valuesInfo: FastNode[]): void;
static hash(key: any): number;
static reduce(x: number, n: number): number;
}
class FastNode {
readonly key: any;
readonly hashcode: number;
previous: number;
next: number;
constructor(key: any, hash: number, previousNode?: number);
}
}
declare module es {
class FastList<T> {
buffer: T[];
@@ -1087,6 +1213,18 @@ declare module es {
sort(comparer: IComparer<T>): void;
}
}
declare module es {
class HashHelpers {
static readonly hashCollisionThreshold: number;
static readonly hashPrime: number;
static readonly primes: number[];
static readonly maxPrimeArrayLength: number;
static isPrime(candidate: number): boolean;
static getPrime(min: number): number;
static expandPrime(oldSize: number): number;
static getHashCode(str: any): number;
}
}
declare module es {
class Matcher {
protected allSet: BitSet;
@@ -1317,6 +1455,45 @@ declare module es {
private computeTriangleIndices;
}
}
declare module es {
class GaussianBlur {
static createBlurredTexture(image: egret.Texture, deviation?: number): void;
static createBlurredTextureData(srcData: Color[], width: number, height: number, deviation?: number): Color[];
static gaussianConvolution(matrix: FasterDictionary<{
x: number;
y: number;
}, number>, deviation: number): FasterDictionary<{
x: number;
y: number;
}, number>;
static processPoint(matrix: FasterDictionary<{
x: number;
y: number;
}, number>, x: number, y: number, kernel: FasterDictionary<{
x: number;
y: number;
}, number>, direction: number): number;
static calculate1DSampleKernel(deviation: number): FasterDictionary<{
x: number;
y: number;
}, number>;
static calculate1DSampleKernelOfSize(deviation: number, size: number): FasterDictionary<{
x: number;
y: number;
}, number>;
static calculateNormalized1DSampleKernel(deviation: number): FasterDictionary<{
x: number;
y: number;
}, number>;
static normalizeMatrix(matrix: FasterDictionary<{
x: number;
y: number;
}, number>): FasterDictionary<{
x: number;
y: number;
}, number>;
}
}
declare module es {
abstract class SceneTransition {
loadsNewScene: boolean;
@@ -2212,6 +2389,11 @@ declare module es {
static free<T>(obj: Array<T>): void;
}
}
declare module es {
class NumberExtension {
static toNumber(value: any): number;
}
}
declare module es {
class Pair<T> implements IEquatable<Pair<T>> {
first: T;
+774 -1
View File
@@ -381,7 +381,6 @@ var es;
}
return AStarNode;
}(es.PriorityQueueNode));
es.AStarNode = AStarNode;
})(es || (es = {}));
var es;
(function (es) {
@@ -970,6 +969,365 @@ var es;
es.WeightedPathfinder = WeightedPathfinder;
})(es || (es = {}));
var es;
(function (es) {
var AStarStorage = (function () {
function AStarStorage() {
this._opened = new Array(AStarStorage.MAX_NODES);
this._closed = new Array(AStarStorage.MAX_NODES);
}
AStarStorage.prototype.clear = function () {
for (var i = 0; i < this._numOpened; i++) {
es.Pool.free(this._opened[i]);
this._opened[i] = null;
}
for (var i = 0; i < this._numClosed; i++) {
es.Pool.free(this._closed[i]);
this._closed[i] = null;
}
this._numOpened = this._numClosed = 0;
this._lastFoundClosed = this._lastFoundOpened = 0;
};
AStarStorage.prototype.findOpened = function (node) {
for (var i = 0; i < this._numOpened; i++) {
var care = node.worldState.dontCare ^ -1;
if ((node.worldState.values & care) == (this._opened[i].worldState.values & care)) {
this._lastFoundClosed = i;
return this._closed[i];
}
}
return null;
};
AStarStorage.prototype.findClosed = function (node) {
for (var i = 0; i < this._numClosed; i++) {
var care = node.worldState.dontCare ^ -1;
if ((node.worldState.values & care) == (this._closed[i].worldState.values & care)) {
this._lastFoundClosed = i;
return this._closed[i];
}
}
return null;
};
AStarStorage.prototype.hasOpened = function () {
return this._numClosed > 0;
};
AStarStorage.prototype.removeOpened = function (node) {
if (this._numOpened > 0)
this._opened[this._lastFoundOpened] = this._opened[this._numOpened - 1];
this._numOpened--;
};
AStarStorage.prototype.removeClosed = function (node) {
if (this._numClosed > 0)
this._closed[this._lastFoundClosed] = this._closed[this._numClosed - 1];
this._numClosed--;
};
AStarStorage.prototype.isOpen = function (node) {
return this._opened.indexOf(node) > -1;
};
AStarStorage.prototype.isClosed = function (node) {
return this._closed.indexOf(node) > -1;
};
AStarStorage.prototype.addToOpenList = function (node) {
this._opened[this._numOpened++] = node;
};
AStarStorage.prototype.addToClosedList = function (node) {
this._closed[this._numClosed++] = node;
};
AStarStorage.prototype.removeCheapestOpenNode = function () {
var lowestVal = Number.MAX_VALUE;
this._lastFoundOpened = -1;
for (var i = 0; i < this._numOpened; i++) {
if (this._opened[i].costSoFarAndHeuristicCost < lowestVal) {
lowestVal = this._opened[i].costSoFarAndHeuristicCost;
this._lastFoundOpened = i;
}
}
var val = this._opened[this._lastFoundOpened];
this.removeOpened(val);
return val;
};
AStarStorage.MAX_NODES = 128;
return AStarStorage;
}());
es.AStarStorage = AStarStorage;
})(es || (es = {}));
var es;
(function (es) {
var AStarNode = (function () {
function AStarNode() {
}
AStarNode.prototype.equals = function (other) {
var care = this.worldState.dontCare ^ -1;
return (this.worldState.values & care) == (other.worldState.values & care);
};
AStarNode.prototype.compareTo = function (other) {
return this.costSoFarAndHeuristicCost - other.costSoFarAndHeuristicCost;
};
AStarNode.prototype.reset = function () {
this.action = null;
this.parent = null;
};
AStarNode.prototype.clone = function () {
var node = new AStarNode();
node.action = this.action;
node.costSoFar = this.costSoFar;
node.depth = this.depth;
node.parent = this.parent;
node.parentWorldState = this.parentWorldState;
node.heuristicCost = this.heuristicCost;
node.worldState = this.worldState;
return node;
};
AStarNode.prototype.toString = function () {
return "[cost: " + this.costSoFar + " | heuristic: " + this.heuristicCost + "]: " + this.action;
};
return AStarNode;
}());
es.AStarNode = AStarNode;
var AStar = (function () {
function AStar() {
}
AStar.plan = function (ap, start, goal, selectedNodes) {
if (selectedNodes === void 0) { selectedNodes = null; }
this.storage.clear();
var currentNode = es.Pool.obtain(AStarNode);
currentNode.worldState = start;
currentNode.parentWorldState = start;
currentNode.costSoFar = 0;
currentNode.heuristicCost = this.calculateHeuristic(start, goal);
currentNode.costSoFarAndHeuristicCost = currentNode.costSoFar + currentNode.heuristicCost;
currentNode.depth = 1;
this.storage.addToOpenList(currentNode);
while (true) {
if (!this.storage.hasOpened()) {
this.storage.clear();
return null;
}
currentNode = this.storage.removeCheapestOpenNode();
this.storage.addToClosedList(currentNode);
if (goal.equals(currentNode.worldState)) {
var plan = this.reconstructPlan(currentNode, selectedNodes);
this.storage.clear();
return plan;
}
var neighbors = ap.getPossibleTransitions(currentNode.worldState);
for (var i = 0; i < neighbors.length; i++) {
var cur = neighbors[i];
var opened = this.storage.findOpened(cur);
var closed_1 = this.storage.findClosed(cur);
var cost = currentNode.costSoFar + cur.costSoFar;
if (opened != null && cost < opened.costSoFar) {
this.storage.removeOpened(opened);
opened = null;
}
if (closed_1 != null && cost < closed_1.costSoFar) {
this.storage.removeClosed(closed_1);
}
if (opened == null && closed_1 == null) {
var nb = es.Pool.obtain(AStarNode);
nb.worldState = cur.worldState;
nb.costSoFar = cost;
nb.heuristicCost = this.calculateHeuristic(cur.worldState, goal);
nb.costSoFarAndHeuristicCost = nb.costSoFar + nb.heuristicCost;
nb.action = cur.action;
nb.parentWorldState = currentNode.worldState;
nb.parent = currentNode;
nb.depth = currentNode.depth + 1;
this.storage.addToOpenList(nb);
}
}
es.ListPool.free(neighbors);
}
};
AStar.reconstructPlan = function (goalNode, selectedNodes) {
var totalActionsInPlan = goalNode.depth - 1;
var plan = new Array(totalActionsInPlan);
var curnode = goalNode;
for (var i = 0; i <= totalActionsInPlan - 1; i++) {
if (selectedNodes != null)
selectedNodes.push(curnode.clone());
plan.push(curnode.action);
curnode = curnode.parent;
}
if (selectedNodes != null)
selectedNodes.reverse();
return plan;
};
AStar.calculateHeuristic = function (fr, to) {
var care = (to.dontCare ^ -1);
var diff = (fr.values & care) ^ (to.values & care);
var dist = 0;
for (var i = 0; i < es.ActionPlanner.MAX_CONDITIONS; ++i)
if ((diff & (1 << i)) != 0)
dist++;
return dist;
};
AStar.storage = new es.AStarStorage();
return AStar;
}());
es.AStar = AStar;
})(es || (es = {}));
var es;
(function (es) {
var Action = (function () {
function Action(name, cost) {
if (cost === void 0) { cost = 1; }
this.cost = 1;
this._preConditions = new Set();
this._postConditions = new Set();
this.name = name;
this.cost = cost;
}
Action.prototype.setPrecondition = function (conditionName, value) {
this._preConditions.add([conditionName, value]);
};
Action.prototype.setPostcondition = function (conditionName, value) {
this._preConditions.add([conditionName, value]);
};
Action.prototype.validate = function () {
return true;
};
Action.prototype.toString = function () {
return "[Action] " + this.name + " - cost: " + this.cost;
};
return Action;
}());
es.Action = Action;
})(es || (es = {}));
var es;
(function (es) {
var ActionPlanner = (function () {
function ActionPlanner() {
this.conditionNames = new Array(ActionPlanner.MAX_CONDITIONS);
this._actions = [];
this._viableActions = [];
this._preConditions = new Array(ActionPlanner.MAX_CONDITIONS);
this._postConditions = new Array(ActionPlanner.MAX_CONDITIONS);
this._numConditionNames = 0;
for (var i = 0; i < ActionPlanner.MAX_CONDITIONS; ++i) {
this.conditionNames[i] = null;
this._preConditions[i] = es.WorldState.create(this);
this._postConditions[i] = es.WorldState.create(this);
}
}
ActionPlanner.prototype.createWorldState = function () {
return es.WorldState.create(this);
};
ActionPlanner.prototype.addAction = function (action) {
var _this = this;
var actionId = this.findActionIndex(action);
if (actionId == -1)
throw new Error("无法找到或创建行动");
action._preConditions.forEach(function (preCondition) {
var conditionId = _this.findConditionNameIndex(preCondition[0]);
if (conditionId == -1)
throw new Error("无法找到或创建条件名称");
_this._preConditions[actionId].set(conditionId, preCondition[1]);
});
action._postConditions.forEach(function (postCondition) {
var conditionId = _this.findConditionNameIndex(postCondition[0]);
if (conditionId == -1)
throw new Error("找不到条件名称");
_this._postConditions[actionId].set(conditionId, postCondition[1]);
});
};
ActionPlanner.prototype.plan = function (startState, goalState, selectedNode) {
if (selectedNode === void 0) { selectedNode = null; }
this._viableActions.length = 0;
for (var i = 0; i < this._actions.length; i++) {
if (this._actions[i].validate())
this._viableActions.push(this._actions[i]);
}
return es.AStar.plan(this, startState, goalState, selectedNode);
};
ActionPlanner.prototype.getPossibleTransitions = function (fr) {
var result = es.ListPool.obtain();
for (var i = 0; i < this._viableActions.length; ++i) {
var pre = this._preConditions[i];
var care = (pre.dontCare ^ -1);
var met = ((pre.values & care) == (fr.values & care));
if (met) {
var node = es.Pool.obtain(es.AStarNode);
node.action = this._viableActions[i];
node.costSoFar = this._viableActions[i].cost;
node.worldState = this.applyPostConditions(this, i, fr);
result.push(node);
}
}
return result;
};
ActionPlanner.prototype.applyPostConditions = function (ap, actionnr, fr) {
var pst = ap._postConditions[actionnr];
var unaffected = pst.dontCare;
var affected = (unaffected ^ -1);
fr.values = (fr.values & unaffected) | (pst.values & affected);
fr.dontCare &= pst.dontCare;
return fr;
};
ActionPlanner.prototype.findConditionNameIndex = function (conditionName) {
var idx;
for (idx = 0; idx < this._numConditionNames; ++idx) {
if (this.conditionNames[idx] == conditionName)
return idx;
}
if (idx < ActionPlanner.MAX_CONDITIONS - 1) {
this.conditionNames[idx] = conditionName;
this._numConditionNames++;
return idx;
}
return -1;
};
ActionPlanner.prototype.findActionIndex = function (action) {
var idx = this._actions.indexOf(action);
if (idx > -1)
return idx;
this._actions.push(action);
return this._actions.length - 1;
};
ActionPlanner.MAX_CONDITIONS = 64;
return ActionPlanner;
}());
es.ActionPlanner = ActionPlanner;
})(es || (es = {}));
var es;
(function (es) {
var WorldState = (function () {
function WorldState(planner, values, dontcare) {
this.planner = planner;
this.values = values;
this.dontCare = dontcare;
}
WorldState.create = function (planner) {
return new WorldState(planner, 0, -1);
};
WorldState.prototype.set = function (conditionId, value) {
this.values = value ? (this.values | (1 << conditionId)) : (this.values & ~(1 << conditionId));
this.dontCare ^= (1 << conditionId);
return true;
};
WorldState.prototype.equals = function (other) {
var care = this.dontCare ^ -1;
return (this.values & care) == (other.values & care);
};
WorldState.prototype.describe = function (planner) {
var s = "";
for (var i = 0; i < es.ActionPlanner.MAX_CONDITIONS; i++) {
if ((this.dontCare & (1 << i)) == 0) {
var val = planner.conditionNames[i];
if (val == null)
continue;
var set = ((this.values & (1 << i)) != 0);
if (s.length > 0)
s += ", ";
s += (set ? val.toUpperCase() : val);
}
}
return s;
};
return WorldState;
}());
es.WorldState = WorldState;
})(es || (es = {}));
var es;
(function (es) {
var Core = (function (_super) {
__extends(Core, _super);
@@ -5008,6 +5366,222 @@ var es;
es.EntityProcessorList = EntityProcessorList;
})(es || (es = {}));
var es;
(function (es) {
var FasterDictionary = (function () {
function FasterDictionary(size) {
if (size === void 0) { size = 1; }
this._freeValueCellIndex = 0;
this._collisions = 0;
this._valuesInfo = new Array(size);
this._values = new Array(size);
this._buckets = new Array(es.HashHelpers.getPrime(size));
}
FasterDictionary.prototype.getValuesArray = function (count) {
count.value = this._freeValueCellIndex;
return this._values;
};
Object.defineProperty(FasterDictionary.prototype, "valuesArray", {
get: function () {
return this._values;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FasterDictionary.prototype, "count", {
get: function () {
return this._freeValueCellIndex;
},
enumerable: true,
configurable: true
});
FasterDictionary.prototype.add = function (key, value) {
if (!this.addValue(key, value, { value: 0 }))
throw new Error("key 已经存在");
};
FasterDictionary.prototype.addValue = function (key, value, indexSet) {
var hash = es.HashHelpers.getHashCode(key);
var bucketIndex = FasterDictionary.reduce(hash, this._buckets.length);
if (this._freeValueCellIndex == this._values.length) {
var expandPrime = es.HashHelpers.expandPrime(this._freeValueCellIndex);
this._values.length = expandPrime;
this._valuesInfo.length = expandPrime;
}
var valueIndex = es.NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
if (valueIndex == -1) {
this._valuesInfo[this._freeValueCellIndex] = new FastNode(key, hash);
}
else {
{
var currentValueIndex = valueIndex;
do {
if (this._valuesInfo[currentValueIndex].hashcode == hash &&
this._valuesInfo[currentValueIndex].key == key) {
this._values[currentValueIndex] = value;
indexSet.value = currentValueIndex;
return false;
}
currentValueIndex = this._valuesInfo[currentValueIndex].previous;
} while (currentValueIndex != -1);
}
this._collisions++;
this._valuesInfo[this._freeValueCellIndex] = new FastNode(key, hash, valueIndex);
this._valuesInfo[valueIndex].next = this._freeValueCellIndex;
}
this._buckets[bucketIndex] = (this._freeValueCellIndex + 1);
this._values[this._freeValueCellIndex] = value;
indexSet.value = this._freeValueCellIndex;
this._freeValueCellIndex++;
if (this._collisions > this._buckets.length) {
this._buckets = new Array(es.HashHelpers.expandPrime(this._collisions));
this._collisions = 0;
for (var newValueIndex = 0; newValueIndex < this._freeValueCellIndex; newValueIndex++) {
bucketIndex = FasterDictionary.reduce(this._valuesInfo[newValueIndex].hashcode, this._buckets.length);
var existingValueIndex = es.NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
this._buckets[bucketIndex] = newValueIndex + 1;
if (existingValueIndex != -1) {
this._collisions++;
this._valuesInfo[newValueIndex].previous = existingValueIndex;
this._valuesInfo[newValueIndex].next = -1;
this._valuesInfo[existingValueIndex].next = newValueIndex;
}
else {
this._valuesInfo[newValueIndex].next = -1;
this._valuesInfo[newValueIndex].previous = -1;
}
}
}
return true;
};
FasterDictionary.prototype.remove = function (key) {
var hash = FasterDictionary.hash(key);
var bucketIndex = FasterDictionary.reduce(hash, this._buckets.length);
var indexToValueToRemove = es.NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
while (indexToValueToRemove != -1) {
if (this._valuesInfo[indexToValueToRemove].hashcode == hash &&
this._valuesInfo[indexToValueToRemove].key == key) {
if (this._buckets[bucketIndex] - 1 == indexToValueToRemove) {
if (this._valuesInfo[indexToValueToRemove].next != -1)
throw new Error("如果 bucket 指向单元格,那么 next 必须不存在。");
var value = this._valuesInfo[indexToValueToRemove].previous;
this._buckets[bucketIndex] = value + 1;
}
else {
if (this._valuesInfo[indexToValueToRemove].next == -1)
throw new Error("如果 bucket 指向另一个单元格,则 NEXT 必须存在");
}
FasterDictionary.updateLinkedList(indexToValueToRemove, this._valuesInfo);
break;
}
indexToValueToRemove = this._valuesInfo[indexToValueToRemove].previous;
}
if (indexToValueToRemove == -1)
return false;
this._freeValueCellIndex--;
if (indexToValueToRemove != this._freeValueCellIndex) {
var movingBucketIndex = FasterDictionary.reduce(this._valuesInfo[this._freeValueCellIndex].hashcode, this._buckets.length);
if (this._buckets[movingBucketIndex] - 1 == this._freeValueCellIndex)
this._buckets[movingBucketIndex] = (indexToValueToRemove + 1);
var next = this._valuesInfo[this._freeValueCellIndex].next;
var previous = this._valuesInfo[this._freeValueCellIndex].previous;
if (next != -1)
this._valuesInfo[next].previous = indexToValueToRemove;
if (previous != -1)
this._valuesInfo[previous].next = indexToValueToRemove;
this._valuesInfo[indexToValueToRemove] = this._valuesInfo[this._freeValueCellIndex];
this._values[indexToValueToRemove] = this._values[this._freeValueCellIndex];
}
return true;
};
FasterDictionary.prototype.trim = function () {
var expandPrime = es.HashHelpers.expandPrime(this._freeValueCellIndex);
if (expandPrime < this._valuesInfo.length) {
this._values.length = expandPrime;
this._valuesInfo.length = expandPrime;
}
};
FasterDictionary.prototype.clear = function () {
if (this._freeValueCellIndex == 0)
return;
this._freeValueCellIndex = 0;
this._buckets.length = 0;
this._values.length = 0;
this._valuesInfo.length = 0;
};
FasterDictionary.prototype.fastClear = function () {
if (this._freeValueCellIndex == 0)
return;
this._freeValueCellIndex = 0;
this._buckets.length = 0;
this._valuesInfo.length = 0;
};
FasterDictionary.prototype.containsKey = function (key) {
if (this.tryFindIndex(key, { value: 0 })) {
return true;
}
return false;
};
FasterDictionary.prototype.tryGetValue = function (key) {
var findIndex = { value: 0 };
if (this.tryFindIndex(key, findIndex)) {
return this._values[findIndex.value];
}
return null;
};
FasterDictionary.prototype.tryFindIndex = function (key, findIndex) {
var hash = FasterDictionary.hash(key);
var bucketIndex = FasterDictionary.reduce(hash, this._buckets.length);
var valueIndex = es.NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
while (valueIndex != -1) {
if (this._valuesInfo[valueIndex].hashcode == hash && this._valuesInfo[valueIndex].key == key) {
findIndex.value = valueIndex;
return true;
}
valueIndex = this._valuesInfo[valueIndex].previous;
}
findIndex.value = 0;
return false;
};
FasterDictionary.prototype.getDirectValue = function (index) {
return this._values[index];
};
FasterDictionary.prototype.getIndex = function (key) {
var findIndex = { value: 0 };
if (this.tryFindIndex(key, findIndex))
return findIndex.value;
throw new Error("未找到key");
};
FasterDictionary.updateLinkedList = function (index, valuesInfo) {
var next = valuesInfo[index].next;
var previous = valuesInfo[index].previous;
if (next != -1)
valuesInfo[next].previous = previous;
if (previous != -1)
valuesInfo[previous].next = next;
};
FasterDictionary.hash = function (key) {
return es.HashHelpers.getHashCode(key);
};
FasterDictionary.reduce = function (x, n) {
if (x >= n)
return x % n;
return x;
};
return FasterDictionary;
}());
es.FasterDictionary = FasterDictionary;
var FastNode = (function () {
function FastNode(key, hash, previousNode) {
if (previousNode === void 0) { previousNode = -1; }
this.key = key;
this.hashcode = hash;
this.previous = previousNode;
this.next = -1;
}
return FastNode;
}());
es.FastNode = FastNode;
})(es || (es = {}));
var es;
(function (es) {
var FastList = (function () {
function FastList(size) {
@@ -5069,6 +5643,73 @@ var es;
es.FastList = FastList;
})(es || (es = {}));
var es;
(function (es) {
var HashHelpers = (function () {
function HashHelpers() {
}
HashHelpers.isPrime = function (candidate) {
if ((candidate & 1) != 0) {
var limit = Math.sqrt(candidate);
for (var divisor = 3; divisor <= limit; divisor += 2) {
if ((candidate & divisor) == 0)
return false;
}
return true;
}
return (candidate == 2);
};
HashHelpers.getPrime = function (min) {
if (min < 0)
throw new Error("参数错误 min不能小于0");
for (var i = 0; i < this.primes.length; i++) {
var prime = this.primes[i];
if (prime >= min)
return prime;
}
for (var i = (min | 1); i < Number.MAX_VALUE; i += 2) {
if (this.isPrime(i) && ((i - 1) % this.hashPrime != 0))
return i;
}
return min;
};
HashHelpers.expandPrime = function (oldSize) {
var newSize = 2 * oldSize;
if (newSize > this.maxPrimeArrayLength && this.maxPrimeArrayLength > oldSize) {
return this.maxPrimeArrayLength;
}
return this.getPrime(newSize);
};
HashHelpers.getHashCode = function (str) {
var s;
if (typeof str == 'object') {
s = JSON.stringify(str);
}
else {
s = str.toString();
}
var hash = 0;
if (s.length == 0)
return hash;
for (var i = 0; i < s.length; i++) {
var char = s.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return hash;
};
HashHelpers.hashCollisionThreshold = 100;
HashHelpers.hashPrime = 101;
HashHelpers.primes = [3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369];
HashHelpers.maxPrimeArrayLength = 0x7FEFFFFD;
return HashHelpers;
}());
es.HashHelpers = HashHelpers;
})(es || (es = {}));
var es;
(function (es) {
var Matcher = (function () {
function Matcher() {
@@ -6205,6 +6846,124 @@ var es;
es.PolyLight = PolyLight;
})(es || (es = {}));
var es;
(function (es) {
var GaussianBlur = (function () {
function GaussianBlur() {
}
GaussianBlur.createBlurredTexture = function (image, deviation) {
if (deviation === void 0) { deviation = 1; }
var pixelData = image.getPixels(0, 0, image.textureWidth, image.textureHeight);
var srcData = new Array(image.textureWidth * image.textureHeight);
for (var i = 0; i < image.textureWidth; i++) {
for (var j = 0; j < image.textureHeight; j++) {
var width = image.textureWidth;
var r = pixelData[i * 4 + j * width];
var g = pixelData[i * 4 + j * width + 1];
var b = pixelData[i * 4 + j * width + 2];
var a = pixelData[i * 4 + j * width + 3];
srcData[i + j * width] = new es.Color(r, g, b, a);
}
}
var destData = this.createBlurredTextureData(srcData, image.textureWidth, image.textureHeight, deviation);
var arrayBuffer = new ArrayBuffer(destData.length);
destData.forEach(function (value, index) {
arrayBuffer[index] = value.packedValue;
});
egret.BitmapData.create("arraybuffer", arrayBuffer, function (bitmapData) {
});
};
GaussianBlur.createBlurredTextureData = function (srcData, width, height, deviation) {
if (deviation === void 0) { deviation = 1; }
var matrixR = new es.FasterDictionary();
var matrixG = new es.FasterDictionary();
var matrixB = new es.FasterDictionary();
var matrixA = new es.FasterDictionary();
var destData = new Array(width * height);
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++) {
matrixR.add({ x: i, y: j }, srcData[i + j * width].r);
matrixG.add({ x: i, y: j }, srcData[i + j * width].g);
matrixB.add({ x: i, y: j }, srcData[i + j * width].b);
matrixA.add({ x: i, y: j }, srcData[i + j * width].a);
}
}
matrixR = this.gaussianConvolution(matrixR, deviation);
matrixG = this.gaussianConvolution(matrixG, deviation);
matrixB = this.gaussianConvolution(matrixB, deviation);
matrixA = this.gaussianConvolution(matrixA, deviation);
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++) {
var r = Math.min(255, matrixR.tryGetValue({ x: i, y: j }));
var g = Math.min(255, matrixG.tryGetValue({ x: i, y: j }));
var b = Math.min(255, matrixB.tryGetValue({ x: i, y: j }));
var a = Math.min(255, matrixA.tryGetValue({ x: i, y: j }));
destData[i + j * width] = new es.Color(r, g, b, a);
}
}
return destData;
};
GaussianBlur.gaussianConvolution = function (matrix, deviation) {
var kernel = this.calculateNormalized1DSampleKernel(deviation);
var res1 = new es.FasterDictionary();
var res2 = new es.FasterDictionary();
for (var i = 0; i < matrix._valuesInfo.length; i++) {
for (var j = 0; j < matrix.valuesArray.length; j++)
res1.add({ x: i, y: j }, this.processPoint(matrix, i, j, kernel, 0));
}
for (var i = 0; i < matrix._valuesInfo.length; i++) {
for (var j = 0; j < matrix.valuesArray.length; j++)
res2.add({ x: i, y: j }, this.processPoint(res1, i, j, kernel, 1));
}
return res2;
};
GaussianBlur.processPoint = function (matrix, x, y, kernel, direction) {
var res = 0;
var half = kernel._valuesInfo.length / 2;
for (var i = 0; i < kernel._valuesInfo.length; i++) {
var cox = direction == 0 ? x + i - half : x;
var coy = direction == 1 ? y + i - half : y;
if (cox >= 0 && cox < matrix._valuesInfo.length && coy >= 0 && coy < matrix.valuesArray.length)
res += matrix.tryGetValue({ x: cox, y: coy }) * kernel.tryGetValue({ x: i, y: 0 });
}
return res;
};
GaussianBlur.calculate1DSampleKernel = function (deviation) {
var size = Math.ceil(deviation * 3) * 3 + 1;
return this.calculate1DSampleKernelOfSize(deviation, size);
};
GaussianBlur.calculate1DSampleKernelOfSize = function (deviation, size) {
var ret = new es.FasterDictionary();
var half = (size - 1) / 2;
for (var i = 0; i < size; i++) {
ret.add({ x: i, y: 0 }, 1 / (Math.sqrt(2 * Math.PI) * deviation) * Math.exp(-(i - half) * (i - half) / (2 * deviation * deviation)));
}
return ret;
};
GaussianBlur.calculateNormalized1DSampleKernel = function (deviation) {
return this.normalizeMatrix(this.calculate1DSampleKernel(deviation));
};
GaussianBlur.normalizeMatrix = function (matrix) {
var ret = new es.FasterDictionary();
var sum = 0;
for (var i = 0; i < ret._valuesInfo.length; i++) {
for (var j = 0; j < ret.valuesArray.length; j++) {
sum += matrix.tryGetValue({ x: i, y: j });
}
}
if (sum != 0) {
for (var i = 0; i < ret._valuesInfo.length; i++) {
for (var j = 0; j < ret.valuesArray.length; j++) {
ret.add({ x: i, y: j }, matrix.tryGetValue({ x: i, y: j }) / sum);
}
}
}
return ret;
};
return GaussianBlur;
}());
es.GaussianBlur = GaussianBlur;
})(es || (es = {}));
var es;
(function (es) {
var SceneTransition = (function () {
function SceneTransition(sceneLoadAction) {
@@ -10468,6 +11227,20 @@ var es;
es.ListPool = ListPool;
})(es || (es = {}));
var es;
(function (es) {
var NumberExtension = (function () {
function NumberExtension() {
}
NumberExtension.toNumber = function (value) {
if (value == undefined)
return 0;
return Number(value);
};
return NumberExtension;
}());
es.NumberExtension = NumberExtension;
})(es || (es = {}));
var es;
(function (es) {
var Pair = (function () {
function Pair(first, second) {
File diff suppressed because one or more lines are too long
+6 -6
View File
@@ -11,17 +11,17 @@ module samples {
this.camera.entity.addComponent(new es.FollowCamera(moonEntity));
this.entities.frameAllocate = true;
this.entities.maxAllocate = 10;
for (let i = 0; i < 10000; i ++){
this.createEntity("");
}
// this.entities.frameAllocate = true;
// this.entities.maxAllocate = 10;
// for (let i = 0; i < 10000; i ++){
// this.createEntity("");
// }
});
}
public update(){
super.update();
console.log(this.entities.buffer.length);
// console.log(this.entities.buffer.length);
}
}
}
+186 -4
View File
@@ -31,10 +31,6 @@ declare module es {
private static hasKey;
private static getKey;
}
class AStarNode<T> extends PriorityQueueNode {
data: T;
constructor(data: T);
}
}
declare module es {
class AstarGridGraph implements IAstarGraph<Vector2> {
@@ -188,6 +184,96 @@ declare module es {
private static getKey;
}
}
declare module es {
class AStarStorage {
static readonly MAX_NODES: number;
_opened: AStarNode[];
_closed: AStarNode[];
_numOpened: number;
_numClosed: number;
_lastFoundOpened: number;
_lastFoundClosed: number;
constructor();
clear(): void;
findOpened(node: AStarNode): AStarNode;
findClosed(node: AStarNode): AStarNode;
hasOpened(): boolean;
removeOpened(node: AStarNode): void;
removeClosed(node: AStarNode): void;
isOpen(node: AStarNode): boolean;
isClosed(node: AStarNode): boolean;
addToOpenList(node: AStarNode): void;
addToClosedList(node: AStarNode): void;
removeCheapestOpenNode(): AStarNode;
}
}
declare module es {
class AStarNode implements IEquatable<AStarNode>, IPoolable {
worldState: WorldState;
costSoFar: number;
heuristicCost: number;
costSoFarAndHeuristicCost: number;
action: Action;
parent: AStarNode;
parentWorldState: WorldState;
depth: number;
equals(other: AStarNode): boolean;
compareTo(other: AStarNode): number;
reset(): void;
clone(): AStarNode;
toString(): string;
}
class AStar {
static storage: AStarStorage;
static plan(ap: ActionPlanner, start: WorldState, goal: WorldState, selectedNodes?: AStarNode[]): Action[];
static reconstructPlan(goalNode: AStarNode, selectedNodes: AStarNode[]): Action[];
static calculateHeuristic(fr: WorldState, to: WorldState): number;
}
}
declare module es {
class Action {
name: string;
cost: number;
_preConditions: Set<[string, boolean]>;
_postConditions: Set<[string, boolean]>;
constructor(name?: string, cost?: number);
setPrecondition(conditionName: string, value: boolean): void;
setPostcondition(conditionName: string, value: boolean): void;
validate(): boolean;
toString(): string;
}
}
declare module es {
class ActionPlanner {
static readonly MAX_CONDITIONS: number;
conditionNames: string[];
_actions: Action[];
_viableActions: Action[];
_preConditions: WorldState[];
_postConditions: WorldState[];
_numConditionNames: number;
constructor();
createWorldState(): WorldState;
addAction(action: Action): void;
plan(startState: WorldState, goalState: WorldState, selectedNode?: any): Action[];
getPossibleTransitions(fr: WorldState): AStarNode[];
applyPostConditions(ap: ActionPlanner, actionnr: number, fr: WorldState): WorldState;
findConditionNameIndex(conditionName: string): any;
findActionIndex(action: Action): number;
}
}
declare module es {
class WorldState implements IEquatable<WorldState> {
values: number;
dontCare: number;
planner: ActionPlanner;
static create(planner: ActionPlanner): WorldState;
constructor(planner: ActionPlanner, values: number, dontcare: number);
set(conditionId: number, value: boolean): boolean;
equals(other: WorldState): boolean;
describe(planner: ActionPlanner): string;
}
}
declare module es {
class Core extends egret.DisplayObjectContainer {
static emitter: Emitter<CoreEvents>;
@@ -1071,6 +1157,46 @@ declare module es {
protected removeFromProcessors(entity: Entity): void;
}
}
declare module es {
class FasterDictionary<TKey, TValue> {
_values: TValue[];
_valuesInfo: FastNode[];
_buckets: number[];
_freeValueCellIndex: number;
_collisions: number;
constructor(size?: number);
getValuesArray(count: {
value: number;
}): TValue[];
readonly valuesArray: TValue[];
readonly count: number;
add(key: TKey, value: TValue): void;
addValue(key: TKey, value: TValue, indexSet: {
value: number;
}): boolean;
remove(key: TKey): boolean;
trim(): void;
clear(): void;
fastClear(): void;
containsKey(key: TKey): boolean;
tryGetValue(key: TKey): TValue;
tryFindIndex(key: TKey, findIndex: {
value: number;
}): boolean;
getDirectValue(index: number): TValue;
getIndex(key: TKey): number;
static updateLinkedList(index: number, valuesInfo: FastNode[]): void;
static hash(key: any): number;
static reduce(x: number, n: number): number;
}
class FastNode {
readonly key: any;
readonly hashcode: number;
previous: number;
next: number;
constructor(key: any, hash: number, previousNode?: number);
}
}
declare module es {
class FastList<T> {
buffer: T[];
@@ -1087,6 +1213,18 @@ declare module es {
sort(comparer: IComparer<T>): void;
}
}
declare module es {
class HashHelpers {
static readonly hashCollisionThreshold: number;
static readonly hashPrime: number;
static readonly primes: number[];
static readonly maxPrimeArrayLength: number;
static isPrime(candidate: number): boolean;
static getPrime(min: number): number;
static expandPrime(oldSize: number): number;
static getHashCode(str: any): number;
}
}
declare module es {
class Matcher {
protected allSet: BitSet;
@@ -1317,6 +1455,45 @@ declare module es {
private computeTriangleIndices;
}
}
declare module es {
class GaussianBlur {
static createBlurredTexture(image: egret.Texture, deviation?: number): void;
static createBlurredTextureData(srcData: Color[], width: number, height: number, deviation?: number): Color[];
static gaussianConvolution(matrix: FasterDictionary<{
x: number;
y: number;
}, number>, deviation: number): FasterDictionary<{
x: number;
y: number;
}, number>;
static processPoint(matrix: FasterDictionary<{
x: number;
y: number;
}, number>, x: number, y: number, kernel: FasterDictionary<{
x: number;
y: number;
}, number>, direction: number): number;
static calculate1DSampleKernel(deviation: number): FasterDictionary<{
x: number;
y: number;
}, number>;
static calculate1DSampleKernelOfSize(deviation: number, size: number): FasterDictionary<{
x: number;
y: number;
}, number>;
static calculateNormalized1DSampleKernel(deviation: number): FasterDictionary<{
x: number;
y: number;
}, number>;
static normalizeMatrix(matrix: FasterDictionary<{
x: number;
y: number;
}, number>): FasterDictionary<{
x: number;
y: number;
}, number>;
}
}
declare module es {
abstract class SceneTransition {
loadsNewScene: boolean;
@@ -2212,6 +2389,11 @@ declare module es {
static free<T>(obj: Array<T>): void;
}
}
declare module es {
class NumberExtension {
static toNumber(value: any): number;
}
}
declare module es {
class Pair<T> implements IEquatable<Pair<T>> {
first: T;
+774 -1
View File
@@ -381,7 +381,6 @@ var es;
}
return AStarNode;
}(es.PriorityQueueNode));
es.AStarNode = AStarNode;
})(es || (es = {}));
var es;
(function (es) {
@@ -970,6 +969,365 @@ var es;
es.WeightedPathfinder = WeightedPathfinder;
})(es || (es = {}));
var es;
(function (es) {
var AStarStorage = (function () {
function AStarStorage() {
this._opened = new Array(AStarStorage.MAX_NODES);
this._closed = new Array(AStarStorage.MAX_NODES);
}
AStarStorage.prototype.clear = function () {
for (var i = 0; i < this._numOpened; i++) {
es.Pool.free(this._opened[i]);
this._opened[i] = null;
}
for (var i = 0; i < this._numClosed; i++) {
es.Pool.free(this._closed[i]);
this._closed[i] = null;
}
this._numOpened = this._numClosed = 0;
this._lastFoundClosed = this._lastFoundOpened = 0;
};
AStarStorage.prototype.findOpened = function (node) {
for (var i = 0; i < this._numOpened; i++) {
var care = node.worldState.dontCare ^ -1;
if ((node.worldState.values & care) == (this._opened[i].worldState.values & care)) {
this._lastFoundClosed = i;
return this._closed[i];
}
}
return null;
};
AStarStorage.prototype.findClosed = function (node) {
for (var i = 0; i < this._numClosed; i++) {
var care = node.worldState.dontCare ^ -1;
if ((node.worldState.values & care) == (this._closed[i].worldState.values & care)) {
this._lastFoundClosed = i;
return this._closed[i];
}
}
return null;
};
AStarStorage.prototype.hasOpened = function () {
return this._numClosed > 0;
};
AStarStorage.prototype.removeOpened = function (node) {
if (this._numOpened > 0)
this._opened[this._lastFoundOpened] = this._opened[this._numOpened - 1];
this._numOpened--;
};
AStarStorage.prototype.removeClosed = function (node) {
if (this._numClosed > 0)
this._closed[this._lastFoundClosed] = this._closed[this._numClosed - 1];
this._numClosed--;
};
AStarStorage.prototype.isOpen = function (node) {
return this._opened.indexOf(node) > -1;
};
AStarStorage.prototype.isClosed = function (node) {
return this._closed.indexOf(node) > -1;
};
AStarStorage.prototype.addToOpenList = function (node) {
this._opened[this._numOpened++] = node;
};
AStarStorage.prototype.addToClosedList = function (node) {
this._closed[this._numClosed++] = node;
};
AStarStorage.prototype.removeCheapestOpenNode = function () {
var lowestVal = Number.MAX_VALUE;
this._lastFoundOpened = -1;
for (var i = 0; i < this._numOpened; i++) {
if (this._opened[i].costSoFarAndHeuristicCost < lowestVal) {
lowestVal = this._opened[i].costSoFarAndHeuristicCost;
this._lastFoundOpened = i;
}
}
var val = this._opened[this._lastFoundOpened];
this.removeOpened(val);
return val;
};
AStarStorage.MAX_NODES = 128;
return AStarStorage;
}());
es.AStarStorage = AStarStorage;
})(es || (es = {}));
var es;
(function (es) {
var AStarNode = (function () {
function AStarNode() {
}
AStarNode.prototype.equals = function (other) {
var care = this.worldState.dontCare ^ -1;
return (this.worldState.values & care) == (other.worldState.values & care);
};
AStarNode.prototype.compareTo = function (other) {
return this.costSoFarAndHeuristicCost - other.costSoFarAndHeuristicCost;
};
AStarNode.prototype.reset = function () {
this.action = null;
this.parent = null;
};
AStarNode.prototype.clone = function () {
var node = new AStarNode();
node.action = this.action;
node.costSoFar = this.costSoFar;
node.depth = this.depth;
node.parent = this.parent;
node.parentWorldState = this.parentWorldState;
node.heuristicCost = this.heuristicCost;
node.worldState = this.worldState;
return node;
};
AStarNode.prototype.toString = function () {
return "[cost: " + this.costSoFar + " | heuristic: " + this.heuristicCost + "]: " + this.action;
};
return AStarNode;
}());
es.AStarNode = AStarNode;
var AStar = (function () {
function AStar() {
}
AStar.plan = function (ap, start, goal, selectedNodes) {
if (selectedNodes === void 0) { selectedNodes = null; }
this.storage.clear();
var currentNode = es.Pool.obtain(AStarNode);
currentNode.worldState = start;
currentNode.parentWorldState = start;
currentNode.costSoFar = 0;
currentNode.heuristicCost = this.calculateHeuristic(start, goal);
currentNode.costSoFarAndHeuristicCost = currentNode.costSoFar + currentNode.heuristicCost;
currentNode.depth = 1;
this.storage.addToOpenList(currentNode);
while (true) {
if (!this.storage.hasOpened()) {
this.storage.clear();
return null;
}
currentNode = this.storage.removeCheapestOpenNode();
this.storage.addToClosedList(currentNode);
if (goal.equals(currentNode.worldState)) {
var plan = this.reconstructPlan(currentNode, selectedNodes);
this.storage.clear();
return plan;
}
var neighbors = ap.getPossibleTransitions(currentNode.worldState);
for (var i = 0; i < neighbors.length; i++) {
var cur = neighbors[i];
var opened = this.storage.findOpened(cur);
var closed_1 = this.storage.findClosed(cur);
var cost = currentNode.costSoFar + cur.costSoFar;
if (opened != null && cost < opened.costSoFar) {
this.storage.removeOpened(opened);
opened = null;
}
if (closed_1 != null && cost < closed_1.costSoFar) {
this.storage.removeClosed(closed_1);
}
if (opened == null && closed_1 == null) {
var nb = es.Pool.obtain(AStarNode);
nb.worldState = cur.worldState;
nb.costSoFar = cost;
nb.heuristicCost = this.calculateHeuristic(cur.worldState, goal);
nb.costSoFarAndHeuristicCost = nb.costSoFar + nb.heuristicCost;
nb.action = cur.action;
nb.parentWorldState = currentNode.worldState;
nb.parent = currentNode;
nb.depth = currentNode.depth + 1;
this.storage.addToOpenList(nb);
}
}
es.ListPool.free(neighbors);
}
};
AStar.reconstructPlan = function (goalNode, selectedNodes) {
var totalActionsInPlan = goalNode.depth - 1;
var plan = new Array(totalActionsInPlan);
var curnode = goalNode;
for (var i = 0; i <= totalActionsInPlan - 1; i++) {
if (selectedNodes != null)
selectedNodes.push(curnode.clone());
plan.push(curnode.action);
curnode = curnode.parent;
}
if (selectedNodes != null)
selectedNodes.reverse();
return plan;
};
AStar.calculateHeuristic = function (fr, to) {
var care = (to.dontCare ^ -1);
var diff = (fr.values & care) ^ (to.values & care);
var dist = 0;
for (var i = 0; i < es.ActionPlanner.MAX_CONDITIONS; ++i)
if ((diff & (1 << i)) != 0)
dist++;
return dist;
};
AStar.storage = new es.AStarStorage();
return AStar;
}());
es.AStar = AStar;
})(es || (es = {}));
var es;
(function (es) {
var Action = (function () {
function Action(name, cost) {
if (cost === void 0) { cost = 1; }
this.cost = 1;
this._preConditions = new Set();
this._postConditions = new Set();
this.name = name;
this.cost = cost;
}
Action.prototype.setPrecondition = function (conditionName, value) {
this._preConditions.add([conditionName, value]);
};
Action.prototype.setPostcondition = function (conditionName, value) {
this._preConditions.add([conditionName, value]);
};
Action.prototype.validate = function () {
return true;
};
Action.prototype.toString = function () {
return "[Action] " + this.name + " - cost: " + this.cost;
};
return Action;
}());
es.Action = Action;
})(es || (es = {}));
var es;
(function (es) {
var ActionPlanner = (function () {
function ActionPlanner() {
this.conditionNames = new Array(ActionPlanner.MAX_CONDITIONS);
this._actions = [];
this._viableActions = [];
this._preConditions = new Array(ActionPlanner.MAX_CONDITIONS);
this._postConditions = new Array(ActionPlanner.MAX_CONDITIONS);
this._numConditionNames = 0;
for (var i = 0; i < ActionPlanner.MAX_CONDITIONS; ++i) {
this.conditionNames[i] = null;
this._preConditions[i] = es.WorldState.create(this);
this._postConditions[i] = es.WorldState.create(this);
}
}
ActionPlanner.prototype.createWorldState = function () {
return es.WorldState.create(this);
};
ActionPlanner.prototype.addAction = function (action) {
var _this = this;
var actionId = this.findActionIndex(action);
if (actionId == -1)
throw new Error("无法找到或创建行动");
action._preConditions.forEach(function (preCondition) {
var conditionId = _this.findConditionNameIndex(preCondition[0]);
if (conditionId == -1)
throw new Error("无法找到或创建条件名称");
_this._preConditions[actionId].set(conditionId, preCondition[1]);
});
action._postConditions.forEach(function (postCondition) {
var conditionId = _this.findConditionNameIndex(postCondition[0]);
if (conditionId == -1)
throw new Error("找不到条件名称");
_this._postConditions[actionId].set(conditionId, postCondition[1]);
});
};
ActionPlanner.prototype.plan = function (startState, goalState, selectedNode) {
if (selectedNode === void 0) { selectedNode = null; }
this._viableActions.length = 0;
for (var i = 0; i < this._actions.length; i++) {
if (this._actions[i].validate())
this._viableActions.push(this._actions[i]);
}
return es.AStar.plan(this, startState, goalState, selectedNode);
};
ActionPlanner.prototype.getPossibleTransitions = function (fr) {
var result = es.ListPool.obtain();
for (var i = 0; i < this._viableActions.length; ++i) {
var pre = this._preConditions[i];
var care = (pre.dontCare ^ -1);
var met = ((pre.values & care) == (fr.values & care));
if (met) {
var node = es.Pool.obtain(es.AStarNode);
node.action = this._viableActions[i];
node.costSoFar = this._viableActions[i].cost;
node.worldState = this.applyPostConditions(this, i, fr);
result.push(node);
}
}
return result;
};
ActionPlanner.prototype.applyPostConditions = function (ap, actionnr, fr) {
var pst = ap._postConditions[actionnr];
var unaffected = pst.dontCare;
var affected = (unaffected ^ -1);
fr.values = (fr.values & unaffected) | (pst.values & affected);
fr.dontCare &= pst.dontCare;
return fr;
};
ActionPlanner.prototype.findConditionNameIndex = function (conditionName) {
var idx;
for (idx = 0; idx < this._numConditionNames; ++idx) {
if (this.conditionNames[idx] == conditionName)
return idx;
}
if (idx < ActionPlanner.MAX_CONDITIONS - 1) {
this.conditionNames[idx] = conditionName;
this._numConditionNames++;
return idx;
}
return -1;
};
ActionPlanner.prototype.findActionIndex = function (action) {
var idx = this._actions.indexOf(action);
if (idx > -1)
return idx;
this._actions.push(action);
return this._actions.length - 1;
};
ActionPlanner.MAX_CONDITIONS = 64;
return ActionPlanner;
}());
es.ActionPlanner = ActionPlanner;
})(es || (es = {}));
var es;
(function (es) {
var WorldState = (function () {
function WorldState(planner, values, dontcare) {
this.planner = planner;
this.values = values;
this.dontCare = dontcare;
}
WorldState.create = function (planner) {
return new WorldState(planner, 0, -1);
};
WorldState.prototype.set = function (conditionId, value) {
this.values = value ? (this.values | (1 << conditionId)) : (this.values & ~(1 << conditionId));
this.dontCare ^= (1 << conditionId);
return true;
};
WorldState.prototype.equals = function (other) {
var care = this.dontCare ^ -1;
return (this.values & care) == (other.values & care);
};
WorldState.prototype.describe = function (planner) {
var s = "";
for (var i = 0; i < es.ActionPlanner.MAX_CONDITIONS; i++) {
if ((this.dontCare & (1 << i)) == 0) {
var val = planner.conditionNames[i];
if (val == null)
continue;
var set = ((this.values & (1 << i)) != 0);
if (s.length > 0)
s += ", ";
s += (set ? val.toUpperCase() : val);
}
}
return s;
};
return WorldState;
}());
es.WorldState = WorldState;
})(es || (es = {}));
var es;
(function (es) {
var Core = (function (_super) {
__extends(Core, _super);
@@ -5008,6 +5366,222 @@ var es;
es.EntityProcessorList = EntityProcessorList;
})(es || (es = {}));
var es;
(function (es) {
var FasterDictionary = (function () {
function FasterDictionary(size) {
if (size === void 0) { size = 1; }
this._freeValueCellIndex = 0;
this._collisions = 0;
this._valuesInfo = new Array(size);
this._values = new Array(size);
this._buckets = new Array(es.HashHelpers.getPrime(size));
}
FasterDictionary.prototype.getValuesArray = function (count) {
count.value = this._freeValueCellIndex;
return this._values;
};
Object.defineProperty(FasterDictionary.prototype, "valuesArray", {
get: function () {
return this._values;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FasterDictionary.prototype, "count", {
get: function () {
return this._freeValueCellIndex;
},
enumerable: true,
configurable: true
});
FasterDictionary.prototype.add = function (key, value) {
if (!this.addValue(key, value, { value: 0 }))
throw new Error("key 已经存在");
};
FasterDictionary.prototype.addValue = function (key, value, indexSet) {
var hash = es.HashHelpers.getHashCode(key);
var bucketIndex = FasterDictionary.reduce(hash, this._buckets.length);
if (this._freeValueCellIndex == this._values.length) {
var expandPrime = es.HashHelpers.expandPrime(this._freeValueCellIndex);
this._values.length = expandPrime;
this._valuesInfo.length = expandPrime;
}
var valueIndex = es.NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
if (valueIndex == -1) {
this._valuesInfo[this._freeValueCellIndex] = new FastNode(key, hash);
}
else {
{
var currentValueIndex = valueIndex;
do {
if (this._valuesInfo[currentValueIndex].hashcode == hash &&
this._valuesInfo[currentValueIndex].key == key) {
this._values[currentValueIndex] = value;
indexSet.value = currentValueIndex;
return false;
}
currentValueIndex = this._valuesInfo[currentValueIndex].previous;
} while (currentValueIndex != -1);
}
this._collisions++;
this._valuesInfo[this._freeValueCellIndex] = new FastNode(key, hash, valueIndex);
this._valuesInfo[valueIndex].next = this._freeValueCellIndex;
}
this._buckets[bucketIndex] = (this._freeValueCellIndex + 1);
this._values[this._freeValueCellIndex] = value;
indexSet.value = this._freeValueCellIndex;
this._freeValueCellIndex++;
if (this._collisions > this._buckets.length) {
this._buckets = new Array(es.HashHelpers.expandPrime(this._collisions));
this._collisions = 0;
for (var newValueIndex = 0; newValueIndex < this._freeValueCellIndex; newValueIndex++) {
bucketIndex = FasterDictionary.reduce(this._valuesInfo[newValueIndex].hashcode, this._buckets.length);
var existingValueIndex = es.NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
this._buckets[bucketIndex] = newValueIndex + 1;
if (existingValueIndex != -1) {
this._collisions++;
this._valuesInfo[newValueIndex].previous = existingValueIndex;
this._valuesInfo[newValueIndex].next = -1;
this._valuesInfo[existingValueIndex].next = newValueIndex;
}
else {
this._valuesInfo[newValueIndex].next = -1;
this._valuesInfo[newValueIndex].previous = -1;
}
}
}
return true;
};
FasterDictionary.prototype.remove = function (key) {
var hash = FasterDictionary.hash(key);
var bucketIndex = FasterDictionary.reduce(hash, this._buckets.length);
var indexToValueToRemove = es.NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
while (indexToValueToRemove != -1) {
if (this._valuesInfo[indexToValueToRemove].hashcode == hash &&
this._valuesInfo[indexToValueToRemove].key == key) {
if (this._buckets[bucketIndex] - 1 == indexToValueToRemove) {
if (this._valuesInfo[indexToValueToRemove].next != -1)
throw new Error("如果 bucket 指向单元格,那么 next 必须不存在。");
var value = this._valuesInfo[indexToValueToRemove].previous;
this._buckets[bucketIndex] = value + 1;
}
else {
if (this._valuesInfo[indexToValueToRemove].next == -1)
throw new Error("如果 bucket 指向另一个单元格,则 NEXT 必须存在");
}
FasterDictionary.updateLinkedList(indexToValueToRemove, this._valuesInfo);
break;
}
indexToValueToRemove = this._valuesInfo[indexToValueToRemove].previous;
}
if (indexToValueToRemove == -1)
return false;
this._freeValueCellIndex--;
if (indexToValueToRemove != this._freeValueCellIndex) {
var movingBucketIndex = FasterDictionary.reduce(this._valuesInfo[this._freeValueCellIndex].hashcode, this._buckets.length);
if (this._buckets[movingBucketIndex] - 1 == this._freeValueCellIndex)
this._buckets[movingBucketIndex] = (indexToValueToRemove + 1);
var next = this._valuesInfo[this._freeValueCellIndex].next;
var previous = this._valuesInfo[this._freeValueCellIndex].previous;
if (next != -1)
this._valuesInfo[next].previous = indexToValueToRemove;
if (previous != -1)
this._valuesInfo[previous].next = indexToValueToRemove;
this._valuesInfo[indexToValueToRemove] = this._valuesInfo[this._freeValueCellIndex];
this._values[indexToValueToRemove] = this._values[this._freeValueCellIndex];
}
return true;
};
FasterDictionary.prototype.trim = function () {
var expandPrime = es.HashHelpers.expandPrime(this._freeValueCellIndex);
if (expandPrime < this._valuesInfo.length) {
this._values.length = expandPrime;
this._valuesInfo.length = expandPrime;
}
};
FasterDictionary.prototype.clear = function () {
if (this._freeValueCellIndex == 0)
return;
this._freeValueCellIndex = 0;
this._buckets.length = 0;
this._values.length = 0;
this._valuesInfo.length = 0;
};
FasterDictionary.prototype.fastClear = function () {
if (this._freeValueCellIndex == 0)
return;
this._freeValueCellIndex = 0;
this._buckets.length = 0;
this._valuesInfo.length = 0;
};
FasterDictionary.prototype.containsKey = function (key) {
if (this.tryFindIndex(key, { value: 0 })) {
return true;
}
return false;
};
FasterDictionary.prototype.tryGetValue = function (key) {
var findIndex = { value: 0 };
if (this.tryFindIndex(key, findIndex)) {
return this._values[findIndex.value];
}
return null;
};
FasterDictionary.prototype.tryFindIndex = function (key, findIndex) {
var hash = FasterDictionary.hash(key);
var bucketIndex = FasterDictionary.reduce(hash, this._buckets.length);
var valueIndex = es.NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
while (valueIndex != -1) {
if (this._valuesInfo[valueIndex].hashcode == hash && this._valuesInfo[valueIndex].key == key) {
findIndex.value = valueIndex;
return true;
}
valueIndex = this._valuesInfo[valueIndex].previous;
}
findIndex.value = 0;
return false;
};
FasterDictionary.prototype.getDirectValue = function (index) {
return this._values[index];
};
FasterDictionary.prototype.getIndex = function (key) {
var findIndex = { value: 0 };
if (this.tryFindIndex(key, findIndex))
return findIndex.value;
throw new Error("未找到key");
};
FasterDictionary.updateLinkedList = function (index, valuesInfo) {
var next = valuesInfo[index].next;
var previous = valuesInfo[index].previous;
if (next != -1)
valuesInfo[next].previous = previous;
if (previous != -1)
valuesInfo[previous].next = next;
};
FasterDictionary.hash = function (key) {
return es.HashHelpers.getHashCode(key);
};
FasterDictionary.reduce = function (x, n) {
if (x >= n)
return x % n;
return x;
};
return FasterDictionary;
}());
es.FasterDictionary = FasterDictionary;
var FastNode = (function () {
function FastNode(key, hash, previousNode) {
if (previousNode === void 0) { previousNode = -1; }
this.key = key;
this.hashcode = hash;
this.previous = previousNode;
this.next = -1;
}
return FastNode;
}());
es.FastNode = FastNode;
})(es || (es = {}));
var es;
(function (es) {
var FastList = (function () {
function FastList(size) {
@@ -5069,6 +5643,73 @@ var es;
es.FastList = FastList;
})(es || (es = {}));
var es;
(function (es) {
var HashHelpers = (function () {
function HashHelpers() {
}
HashHelpers.isPrime = function (candidate) {
if ((candidate & 1) != 0) {
var limit = Math.sqrt(candidate);
for (var divisor = 3; divisor <= limit; divisor += 2) {
if ((candidate & divisor) == 0)
return false;
}
return true;
}
return (candidate == 2);
};
HashHelpers.getPrime = function (min) {
if (min < 0)
throw new Error("参数错误 min不能小于0");
for (var i = 0; i < this.primes.length; i++) {
var prime = this.primes[i];
if (prime >= min)
return prime;
}
for (var i = (min | 1); i < Number.MAX_VALUE; i += 2) {
if (this.isPrime(i) && ((i - 1) % this.hashPrime != 0))
return i;
}
return min;
};
HashHelpers.expandPrime = function (oldSize) {
var newSize = 2 * oldSize;
if (newSize > this.maxPrimeArrayLength && this.maxPrimeArrayLength > oldSize) {
return this.maxPrimeArrayLength;
}
return this.getPrime(newSize);
};
HashHelpers.getHashCode = function (str) {
var s;
if (typeof str == 'object') {
s = JSON.stringify(str);
}
else {
s = str.toString();
}
var hash = 0;
if (s.length == 0)
return hash;
for (var i = 0; i < s.length; i++) {
var char = s.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return hash;
};
HashHelpers.hashCollisionThreshold = 100;
HashHelpers.hashPrime = 101;
HashHelpers.primes = [3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369];
HashHelpers.maxPrimeArrayLength = 0x7FEFFFFD;
return HashHelpers;
}());
es.HashHelpers = HashHelpers;
})(es || (es = {}));
var es;
(function (es) {
var Matcher = (function () {
function Matcher() {
@@ -6205,6 +6846,124 @@ var es;
es.PolyLight = PolyLight;
})(es || (es = {}));
var es;
(function (es) {
var GaussianBlur = (function () {
function GaussianBlur() {
}
GaussianBlur.createBlurredTexture = function (image, deviation) {
if (deviation === void 0) { deviation = 1; }
var pixelData = image.getPixels(0, 0, image.textureWidth, image.textureHeight);
var srcData = new Array(image.textureWidth * image.textureHeight);
for (var i = 0; i < image.textureWidth; i++) {
for (var j = 0; j < image.textureHeight; j++) {
var width = image.textureWidth;
var r = pixelData[i * 4 + j * width];
var g = pixelData[i * 4 + j * width + 1];
var b = pixelData[i * 4 + j * width + 2];
var a = pixelData[i * 4 + j * width + 3];
srcData[i + j * width] = new es.Color(r, g, b, a);
}
}
var destData = this.createBlurredTextureData(srcData, image.textureWidth, image.textureHeight, deviation);
var arrayBuffer = new ArrayBuffer(destData.length);
destData.forEach(function (value, index) {
arrayBuffer[index] = value.packedValue;
});
egret.BitmapData.create("arraybuffer", arrayBuffer, function (bitmapData) {
});
};
GaussianBlur.createBlurredTextureData = function (srcData, width, height, deviation) {
if (deviation === void 0) { deviation = 1; }
var matrixR = new es.FasterDictionary();
var matrixG = new es.FasterDictionary();
var matrixB = new es.FasterDictionary();
var matrixA = new es.FasterDictionary();
var destData = new Array(width * height);
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++) {
matrixR.add({ x: i, y: j }, srcData[i + j * width].r);
matrixG.add({ x: i, y: j }, srcData[i + j * width].g);
matrixB.add({ x: i, y: j }, srcData[i + j * width].b);
matrixA.add({ x: i, y: j }, srcData[i + j * width].a);
}
}
matrixR = this.gaussianConvolution(matrixR, deviation);
matrixG = this.gaussianConvolution(matrixG, deviation);
matrixB = this.gaussianConvolution(matrixB, deviation);
matrixA = this.gaussianConvolution(matrixA, deviation);
for (var i = 0; i < width; i++) {
for (var j = 0; j < height; j++) {
var r = Math.min(255, matrixR.tryGetValue({ x: i, y: j }));
var g = Math.min(255, matrixG.tryGetValue({ x: i, y: j }));
var b = Math.min(255, matrixB.tryGetValue({ x: i, y: j }));
var a = Math.min(255, matrixA.tryGetValue({ x: i, y: j }));
destData[i + j * width] = new es.Color(r, g, b, a);
}
}
return destData;
};
GaussianBlur.gaussianConvolution = function (matrix, deviation) {
var kernel = this.calculateNormalized1DSampleKernel(deviation);
var res1 = new es.FasterDictionary();
var res2 = new es.FasterDictionary();
for (var i = 0; i < matrix._valuesInfo.length; i++) {
for (var j = 0; j < matrix.valuesArray.length; j++)
res1.add({ x: i, y: j }, this.processPoint(matrix, i, j, kernel, 0));
}
for (var i = 0; i < matrix._valuesInfo.length; i++) {
for (var j = 0; j < matrix.valuesArray.length; j++)
res2.add({ x: i, y: j }, this.processPoint(res1, i, j, kernel, 1));
}
return res2;
};
GaussianBlur.processPoint = function (matrix, x, y, kernel, direction) {
var res = 0;
var half = kernel._valuesInfo.length / 2;
for (var i = 0; i < kernel._valuesInfo.length; i++) {
var cox = direction == 0 ? x + i - half : x;
var coy = direction == 1 ? y + i - half : y;
if (cox >= 0 && cox < matrix._valuesInfo.length && coy >= 0 && coy < matrix.valuesArray.length)
res += matrix.tryGetValue({ x: cox, y: coy }) * kernel.tryGetValue({ x: i, y: 0 });
}
return res;
};
GaussianBlur.calculate1DSampleKernel = function (deviation) {
var size = Math.ceil(deviation * 3) * 3 + 1;
return this.calculate1DSampleKernelOfSize(deviation, size);
};
GaussianBlur.calculate1DSampleKernelOfSize = function (deviation, size) {
var ret = new es.FasterDictionary();
var half = (size - 1) / 2;
for (var i = 0; i < size; i++) {
ret.add({ x: i, y: 0 }, 1 / (Math.sqrt(2 * Math.PI) * deviation) * Math.exp(-(i - half) * (i - half) / (2 * deviation * deviation)));
}
return ret;
};
GaussianBlur.calculateNormalized1DSampleKernel = function (deviation) {
return this.normalizeMatrix(this.calculate1DSampleKernel(deviation));
};
GaussianBlur.normalizeMatrix = function (matrix) {
var ret = new es.FasterDictionary();
var sum = 0;
for (var i = 0; i < ret._valuesInfo.length; i++) {
for (var j = 0; j < ret.valuesArray.length; j++) {
sum += matrix.tryGetValue({ x: i, y: j });
}
}
if (sum != 0) {
for (var i = 0; i < ret._valuesInfo.length; i++) {
for (var j = 0; j < ret.valuesArray.length; j++) {
ret.add({ x: i, y: j }, matrix.tryGetValue({ x: i, y: j }) / sum);
}
}
}
return ret;
};
return GaussianBlur;
}());
es.GaussianBlur = GaussianBlur;
})(es || (es = {}));
var es;
(function (es) {
var SceneTransition = (function () {
function SceneTransition(sceneLoadAction) {
@@ -10468,6 +11227,20 @@ var es;
es.ListPool = ListPool;
})(es || (es = {}));
var es;
(function (es) {
var NumberExtension = (function () {
function NumberExtension() {
}
NumberExtension.toNumber = function (value) {
if (value == undefined)
return 0;
return Number(value);
};
return NumberExtension;
}());
es.NumberExtension = NumberExtension;
})(es || (es = {}));
var es;
(function (es) {
var Pair = (function () {
function Pair(first, second) {
+1 -1
View File
File diff suppressed because one or more lines are too long
@@ -99,7 +99,7 @@ module es {
/**
* 使PriorityQueue需要的额外字段将原始数据封装在一个小类中
*/
export class AStarNode<T> extends PriorityQueueNode {
class AStarNode<T> extends PriorityQueueNode {
public data: T;
constructor(data: T) {
+200
View File
@@ -0,0 +1,200 @@
///<reference path="./AStarStorage.ts" />
module es {
export class AStarNode implements IEquatable<AStarNode>, IPoolable {
/**
*
*/
public worldState: WorldState;
/**
*
*/
public costSoFar: number;
/**
*
*/
public heuristicCost: number;
/**
* costSoFar+heuristicCost(g+h)
*/
public costSoFarAndHeuristicCost: number;
/**
*
*/
public action: Action;
/**
*
*/
public parent: AStarNode;
/**
*
*/
public parentWorldState: WorldState;
/**
*
*/
public depth: number;
/**
*
* @param other
*/
public equals(other: AStarNode): boolean {
let care = this.worldState.dontCare ^ -1;
return (this.worldState.values & care) == (other.worldState.values & care);
}
public compareTo(other: AStarNode){
return this.costSoFarAndHeuristicCost - other.costSoFarAndHeuristicCost;
}
public reset(){
this.action = null;
this.parent = null;
}
public clone(): AStarNode{
let node = new AStarNode();
node.action = this.action;
node.costSoFar = this.costSoFar;
node.depth = this.depth;
node.parent = this.parent;
node.parentWorldState = this.parentWorldState;
node.heuristicCost = this.heuristicCost;
node.worldState = this.worldState;
return node;
}
public toString(): string{
return `[cost: ${this.costSoFar} | heuristic: ${this.heuristicCost}]: ${this.action}`;
}
}
export class AStar {
public static storage: AStarStorage = new AStarStorage();
/**
*
* @param ap
* @param start
* @param goal
* @param selectedNodes
*/
public static plan(ap: ActionPlanner, start: WorldState, goal: WorldState, selectedNodes: AStarNode[] = null){
this.storage.clear();
let currentNode = Pool.obtain<AStarNode>(AStarNode);
currentNode.worldState = start;
currentNode.parentWorldState = start;
currentNode.costSoFar = 0;
currentNode.heuristicCost = this.calculateHeuristic(start, goal);
currentNode.costSoFarAndHeuristicCost = currentNode.costSoFar + currentNode.heuristicCost;
currentNode.depth = 1;
this.storage.addToOpenList(currentNode);
while(true){
// 无路可走,无路可寻
if (!this.storage.hasOpened()){
this.storage.clear();
return null;
}
currentNode = this.storage.removeCheapestOpenNode();
this.storage.addToClosedList(currentNode);
// 全部完成。 我们达到了我们的目标
if (goal.equals(currentNode.worldState)){
let plan = this.reconstructPlan(currentNode, selectedNodes);
this.storage.clear();
return plan;
}
let neighbors = ap.getPossibleTransitions(currentNode.worldState);
for (let i = 0; i < neighbors.length; i++){
let cur = neighbors[i];
let opened = this.storage.findOpened(cur);
let closed = this.storage.findClosed(cur);
let cost = currentNode.costSoFar + cur.costSoFar;
// 如果neighbors处于open状态,且成本小于g(neighbors)。
if (opened != null && cost < opened.costSoFar){
// 将neighbors从OPEN中移除,因为新的路径更好。
this.storage.removeOpened(opened);
opened = null;
}
// 如果neighbors在CLOSED,且成本小于g(neighbors)
if (closed != null && cost < closed.costSoFar){
// 从CLOSED中删除neighbors
this.storage.removeClosed(closed);
}
// 如果neighbors不在OPENneighbors不在CLOSED。
if (opened == null && closed == null){
let nb = Pool.obtain<AStarNode>(AStarNode);
nb.worldState = cur.worldState;
nb.costSoFar = cost;
nb.heuristicCost = this.calculateHeuristic(cur.worldState, goal);
nb.costSoFarAndHeuristicCost = nb.costSoFar + nb.heuristicCost;
nb.action = cur.action;
nb.parentWorldState = currentNode.worldState;
nb.parent = currentNode;
nb.depth = currentNode.depth + 1;
this.storage.addToOpenList(nb);
}
}
ListPool.free<AStarNode>(neighbors);
}
}
/**
*
* @param goalNode
* @param selectedNodes
*/
public static reconstructPlan(goalNode: AStarNode, selectedNodes: AStarNode[]){
let totalActionsInPlan = goalNode.depth - 1;
let plan: Action[] = new Array(totalActionsInPlan);
let curnode = goalNode;
for (let i = 0; i <= totalActionsInPlan - 1; i ++){
// 如果我们被传递了一个节点,可以选择将该节点添加到列表中
if (selectedNodes != null)
selectedNodes.push(curnode.clone());
plan.push(curnode.action);
curnode = curnode.parent;
}
// 我们的节点从目标回到了起点,所以把它们反过来。
if (selectedNodes != null)
selectedNodes.reverse();
return plan;
}
/**
*
* @param fr
* @param to
*/
public static calculateHeuristic(fr: WorldState, to: WorldState){
let care = (to.dontCare ^ -1);
let diff = (fr.values & care) ^ (to.values & care);
let dist = 0;
for (let i = 0; i < ActionPlanner.MAX_CONDITIONS; ++i)
if ((diff & (1 << i)) != 0)
dist ++;
return dist;
}
}
}
@@ -0,0 +1,107 @@
module es {
export class AStarStorage {
/**
*
*/
public static readonly MAX_NODES = 128;
public _opened: AStarNode[] = new Array(AStarStorage.MAX_NODES);
public _closed: AStarNode[] = new Array(AStarStorage.MAX_NODES);
public _numOpened: number;
public _numClosed: number;
public _lastFoundOpened: number;
public _lastFoundClosed: number;
constructor(){}
public clear(){
for (let i = 0; i < this._numOpened; i ++){
Pool.free<AStarNode>(this._opened[i]);
this._opened[i] = null;
}
for (let i = 0; i < this._numClosed; i ++){
Pool.free<AStarNode>(this._closed[i]);
this._closed[i] = null;
}
this._numOpened = this._numClosed = 0;
this._lastFoundClosed = this._lastFoundOpened = 0;
}
public findOpened(node: AStarNode): AStarNode {
for (let i = 0; i < this._numOpened; i ++){
let care = node.worldState.dontCare ^ -1;
if ((node.worldState.values & care) == (this._opened[i].worldState.values & care)){
this._lastFoundClosed = i;
return this._closed[i];
}
}
return null;
}
public findClosed(node: AStarNode): AStarNode {
for (let i = 0; i < this._numClosed; i ++){
let care = node.worldState.dontCare ^ -1;
if ((node.worldState.values & care) == (this._closed[i].worldState.values & care)){
this._lastFoundClosed = i;
return this._closed[i];
}
}
return null;
}
public hasOpened(): boolean {
return this._numClosed > 0;
}
public removeOpened(node: AStarNode){
if (this._numOpened > 0)
this._opened[this._lastFoundOpened] = this._opened[this._numOpened - 1];
this._numOpened --;
}
public removeClosed(node: AStarNode) {
if (this._numClosed > 0)
this._closed[this._lastFoundClosed] = this._closed[this._numClosed - 1];
this._numClosed--;
}
public isOpen(node: AStarNode): boolean{
return this._opened.indexOf(node) > -1;
}
public isClosed(node: AStarNode): boolean {
return this._closed.indexOf(node) > -1;
}
public addToOpenList(node: AStarNode){
this._opened[this._numOpened++] = node;
}
public addToClosedList(node: AStarNode){
this._closed[this._numClosed++] = node;
}
/**
*
*/
public removeCheapestOpenNode(): AStarNode {
let lowestVal = Number.MAX_VALUE;
this._lastFoundOpened = -1;
for (let i = 0; i < this._numOpened; i ++){
if (this._opened[i].costSoFarAndHeuristicCost < lowestVal){
lowestVal = this._opened[i].costSoFarAndHeuristicCost;
this._lastFoundOpened = i;
}
}
var val = this._opened[this._lastFoundOpened];
this.removeOpened(val);
return val;
}
}
}
+41
View File
@@ -0,0 +1,41 @@
module es {
export class Action {
/**
* Action的可选名称
*/
public name: string;
/**
* /
*/
public cost: number = 1;
public _preConditions: Set<[string, boolean]> = new Set<[string, boolean]>();
public _postConditions: Set<[string, boolean]> = new Set<[string, boolean]>();
constructor(name?: string, cost: number = 1){
this.name = name;
this.cost = cost;
}
public setPrecondition(conditionName: string, value: boolean){
this._preConditions.add([conditionName, value]);
}
public setPostcondition(conditionName: string, value: boolean){
this._preConditions.add([conditionName, value]);
}
/**
* ActionPlanner进行plan之前调用Action有机会设置它的分数退
* Action是要拿起一把枪false将使Action不被ActionPlanner考虑
*/
public validate(): boolean{
return true;
}
public toString(): string{
return `[Action] ${this.name} - cost: ${this.cost}`;
}
}
}
@@ -0,0 +1,129 @@
module es {
export class ActionPlanner {
public static readonly MAX_CONDITIONS: number = 64;
/**
*
*/
public conditionNames: string[] = new Array(ActionPlanner.MAX_CONDITIONS);
public _actions: Action[] = [];
public _viableActions: Action[] = [];
/**
*
*/
public _preConditions: WorldState[] = new Array(ActionPlanner.MAX_CONDITIONS);
/**
*
*/
public _postConditions: WorldState[] = new Array(ActionPlanner.MAX_CONDITIONS);
/**
*
*/
public _numConditionNames: number;
constructor(){
this._numConditionNames = 0;
for (let i = 0; i < ActionPlanner.MAX_CONDITIONS; ++i){
this.conditionNames[i] = null;
this._preConditions[i] = WorldState.create(this);
this._postConditions[i] = WorldState.create(this);
}
}
/**
* 便
*/
public createWorldState(): WorldState {
return WorldState.create(this);
}
public addAction(action: Action){
let actionId = this.findActionIndex(action);
if (actionId == -1)
throw new Error("无法找到或创建行动");
action._preConditions.forEach((preCondition)=>{
let conditionId = this.findConditionNameIndex(preCondition[0]);
if (conditionId == -1)
throw new Error("无法找到或创建条件名称");
this._preConditions[actionId].set(conditionId, preCondition[1]);
});
action._postConditions.forEach((postCondition)=>{
let conditionId = this.findConditionNameIndex(postCondition[0]);
if (conditionId == -1)
throw new Error("找不到条件名称");
this._postConditions[actionId].set(conditionId, postCondition[1]);
});
}
public plan(startState: WorldState, goalState: WorldState, selectedNode = null){
this._viableActions.length = 0;
for (let i = 0; i < this._actions.length; i++){
if (this._actions[i].validate())
this._viableActions.push(this._actions[i]);
}
return AStar.plan(this, startState, goalState, selectedNode);
}
public getPossibleTransitions(fr: WorldState){
let result = ListPool.obtain<AStarNode>();
for (let i = 0; i < this._viableActions.length; ++i){
let pre = this._preConditions[i];
let care = (pre.dontCare ^ -1);
let met = ((pre.values & care) == (fr.values & care));
if (met){
let node = Pool.obtain<AStarNode>(AStarNode);
node.action = this._viableActions[i];
node.costSoFar = this._viableActions[i].cost;
node.worldState = this.applyPostConditions(this, i, fr);
result.push(node);
}
}
return result;
}
public applyPostConditions(ap: ActionPlanner, actionnr: number, fr: WorldState){
let pst = ap._postConditions[actionnr];
let unaffected = pst.dontCare;
let affected = (unaffected ^ -1);
fr.values = (fr.values & unaffected) | (pst.values & affected);
fr.dontCare &= pst.dontCare;
return fr;
}
public findConditionNameIndex(conditionName: string){
let idx;
for (idx = 0; idx < this._numConditionNames; ++idx){
if (this.conditionNames[idx] == conditionName)
return idx;
}
if (idx < ActionPlanner.MAX_CONDITIONS - 1){
this.conditionNames[idx] = conditionName;
this._numConditionNames ++;
return idx;
}
return -1;
}
public findActionIndex(action: Action): number{
let idx = this._actions.indexOf(action);
if (idx > -1)
return idx;
this._actions.push(action);
return this._actions.length - 1;
}
}
}
@@ -0,0 +1,76 @@
module es {
export class WorldState implements IEquatable<WorldState> {
/**
* 使
*/
public values: number;
/**
* false
*
*/
public dontCare: number;
/**
*
*/
public planner: ActionPlanner;
/**
*
* @param planner
*/
public static create(planner: ActionPlanner): WorldState {
return new WorldState(planner, 0, -1);
}
/**
*
* @param planner
* @param values
* @param dontcare
*/
constructor(planner: ActionPlanner, values: number, dontcare: number){
this.planner = planner;
this.values = values;
this.dontCare = dontcare;
}
public set(conditionId: number, value: boolean): boolean {
this.values = value ? (this.values | (1 << conditionId)) : (this.values & ~(1 << conditionId));
this.dontCare ^= (1 << conditionId);
return true;
}
/**
*
* @param other
*/
public equals(other: WorldState): boolean {
let care = this.dontCare ^ -1;
return (this.values & care) == (other.values & care);
}
/**
*
* @param planner
*/
public describe(planner: ActionPlanner): string {
let s = "";
for (let i = 0; i < ActionPlanner.MAX_CONDITIONS; i ++){
if ((this.dontCare & (1 << i)) == 0){
let val = planner.conditionNames[i];
if (val == null)
continue;
let set = ((this.values & (1 << i)) != 0);
if (s.length > 0)
s += ", ";
s += (set ? val.toUpperCase() : val);
}
}
return s;
}
}
}
+317
View File
@@ -0,0 +1,317 @@
module es {
/**
*
* 使
* N倍
* Faster dictionary在大部分操作上也比标准字典快
* 使
*/
export class FasterDictionary<TKey, TValue> {
public _values: TValue[];
public _valuesInfo: FastNode[];
public _buckets: number[];
public _freeValueCellIndex: number = 0;
public _collisions: number = 0;
constructor(size: number = 1) {
this._valuesInfo = new Array(size);
this._values = new Array(size);
this._buckets = new Array(HashHelpers.getPrime(size));
}
public getValuesArray(count: {value: number}): TValue[] {
count.value = this._freeValueCellIndex;
return this._values;
}
public get valuesArray(): TValue[] {
return this._values;
}
public get count(): number {
return this._freeValueCellIndex;
}
public add(key: TKey, value: TValue) {
if (!this.addValue(key, value, {value: 0}))
throw new Error("key 已经存在")
}
public addValue(key: TKey, value: TValue, indexSet: {value: number}) {
let hash = HashHelpers.getHashCode(key);
let bucketIndex = FasterDictionary.reduce(hash, this._buckets.length);
if (this._freeValueCellIndex == this._values.length) {
let expandPrime = HashHelpers.expandPrime(this._freeValueCellIndex);
this._values.length = expandPrime;
this._valuesInfo.length = expandPrime;
}
// buckets值-1表示它是空的
let valueIndex = NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
if (valueIndex == -1) {
// 在最后一个位置创建信息节点,并填入相关信息
this._valuesInfo[this._freeValueCellIndex] = new FastNode(key, hash);
} else {
{
let currentValueIndex = valueIndex;
do {
// 必须检查键是否已经存在于字典中
if (this._valuesInfo[currentValueIndex].hashcode == hash &&
this._valuesInfo[currentValueIndex].key == key) {
// 键已经存在,只需将其值替换掉即可
this._values[currentValueIndex] = value;
indexSet.value = currentValueIndex;
return false;
}
currentValueIndex = this._valuesInfo[currentValueIndex].previous;
}
while (currentValueIndex != -1); // -1表示没有更多的值与相同的哈希值的键
}
this._collisions++;
// 创建一个新的节点,该节点之前的索引指向当前指向桶的节点
this._valuesInfo[this._freeValueCellIndex] = new FastNode(key, hash, valueIndex);
// 更新现有单元格的下一个单元格指向新的单元格,旧的单元格 -> 新的单元格 -> 旧的单元格 <- 下一个单元格
this._valuesInfo[valueIndex].next = this._freeValueCellIndex;
}
// 重要的是:新的节点总是被桶单元格指向的那个节点,所以我可以假设被桶指向的那个节点总是最后添加的值(next = -1)
// item与这个bucketIndex将指向最后创建的值
// TODO: 如果相反,我假设原来的那个是bucket中的那个,我就不需要在这里更新bucket了
this._buckets[bucketIndex] = (this._freeValueCellIndex + 1);
this._values[this._freeValueCellIndex] = value;
indexSet.value = this._freeValueCellIndex;
this._freeValueCellIndex++;
if (this._collisions > this._buckets.length) {
// 我们需要更多的空间和更少的碰撞
this._buckets = new Array(HashHelpers.expandPrime(this._collisions));
this._collisions = 0;
// 我们需要得到目前存储的所有值的哈希码,并将它们分布在新的桶长上
for (let newValueIndex = 0; newValueIndex < this._freeValueCellIndex; newValueIndex++) {
// 获取原始哈希码,并根据新的长度找到新的bucketIndex
bucketIndex = FasterDictionary.reduce(this._valuesInfo[newValueIndex].hashcode, this._buckets.length);
// bucketsIndex可以是-1或下一个值。
// 如果是-1意味着没有碰撞。
// 如果有碰撞,我们创建一个新节点,它的上一个指向旧节点。
// 旧节点指向新节点,新节点指向旧节点,旧节点指向新节点,现在bucket指向新节点,这样我们就可以重建linkedlist.
// 获取当前值Index,如果没有碰撞,则为-1。
let existingValueIndex = NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
// 将bucket索引更新为共享bucketIndex的当前项目的索引(最后找到的总是bucket中的那个)
this._buckets[bucketIndex] = newValueIndex + 1;
if (existingValueIndex != -1) {
// 这个单元格已经指向了新的bucket list中的一个值,这意味着有一个碰撞,出了问题
this._collisions++;
// bucket将指向这个值,所以新的值将使用以前的索引
this._valuesInfo[newValueIndex].previous = existingValueIndex;
this._valuesInfo[newValueIndex].next = -1;
// 并将之前的下一个索引更新为新的索引
this._valuesInfo[existingValueIndex].next = newValueIndex;
} else {
// 什么都没有被索引,桶是空的。我们需要更新之前的 next 和 previous 的值。
this._valuesInfo[newValueIndex].next = -1;
this._valuesInfo[newValueIndex].previous = -1;
}
}
}
return true;
}
public remove(key: TKey): boolean {
let hash = FasterDictionary.hash(key);
let bucketIndex = FasterDictionary.reduce(hash, this._buckets.length);
// 找桶
let indexToValueToRemove = NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
// 第一部分:在bucket list中寻找实际的键,如果找到了,我就更新bucket list,使它不再指向要删除的单元格。
while (indexToValueToRemove != -1) {
if (this._valuesInfo[indexToValueToRemove].hashcode == hash &&
this._valuesInfo[indexToValueToRemove].key == key) {
// 如果找到了密钥,并且桶直接指向了要删除的节点
if (this._buckets[bucketIndex] - 1 == indexToValueToRemove){
if (this._valuesInfo[indexToValueToRemove].next != -1)
throw new Error("如果 bucket 指向单元格,那么 next 必须不存在。");
// 如果前一个单元格存在,它的下一个指针必须被更新!
//<---迭代顺序
// B(ucket总是指向最后一个)
// ------- ------- -------
// 1 | | | | 2 | | | 3 | //bucket不能有下一个,只能有上一个。
// ------- ------- -------
//--> 插入
let value = this._valuesInfo[indexToValueToRemove].previous;
this._buckets[bucketIndex] = value + 1;
}else{
if (this._valuesInfo[indexToValueToRemove].next == -1)
throw new Error("如果 bucket 指向另一个单元格,则 NEXT 必须存在");
}
FasterDictionary.updateLinkedList(indexToValueToRemove, this._valuesInfo);
break;
}
indexToValueToRemove = this._valuesInfo[indexToValueToRemove].previous;
}
if (indexToValueToRemove == -1)
return false; // 未找到
this._freeValueCellIndex --; // 少了一个需要反复计算的值
// 第二部分
// 这时节点指针和水桶会被更新,但_values数组会被更新仍然有要删除的值
// 这个字典的目标是能够做到像数组一样对数值进行迭代,所以数值数组必须始终是最新的
// 如果要删除的单元格是列表中的最后一个,我们可以执行较少的操作(不需要交换),否则我们要将最后一个值的单元格移到要删除的值上。
if (indexToValueToRemove != this._freeValueCellIndex){
// 我们可以将两个数组的最后一个值移到要删除的数组中。
// 为了做到这一点,我们需要确保 bucket 指针已经更新了
// 首先我们在桶列表中找到指向要移动的单元格的指针的索引
let movingBucketIndex = FasterDictionary.reduce(this._valuesInfo[this._freeValueCellIndex].hashcode, this._buckets.length);
// 如果找到了键,并且桶直接指向要删除的节点,现在必须指向要移动的单元格。
if (this._buckets[movingBucketIndex] - 1 == this._freeValueCellIndex)
this._buckets[movingBucketIndex] = (indexToValueToRemove + 1);
// 否则意味着有多个键具有相同的哈希值(碰撞),所以我们需要更新链接列表和它的指针
let next = this._valuesInfo[this._freeValueCellIndex].next;
let previous = this._valuesInfo[this._freeValueCellIndex].previous;
// 现在它们指向最后一个值被移入的单元格
if (next != -1)
this._valuesInfo[next].previous = indexToValueToRemove;
if (previous != -1)
this._valuesInfo[previous].next = indexToValueToRemove;
// 最后,实际上是移动值
this._valuesInfo[indexToValueToRemove] = this._valuesInfo[this._freeValueCellIndex];
this._values[indexToValueToRemove] = this._values[this._freeValueCellIndex];
}
return true;
}
public trim(){
let expandPrime = HashHelpers.expandPrime(this._freeValueCellIndex);
if (expandPrime < this._valuesInfo.length){
this._values.length = expandPrime;
this._valuesInfo.length = expandPrime;
}
}
public clear(){
if (this._freeValueCellIndex == 0) return;
this._freeValueCellIndex = 0;
this._buckets.length = 0;
this._values.length = 0;
this._valuesInfo.length = 0;
}
public fastClear(){
if (this._freeValueCellIndex == 0) return;
this._freeValueCellIndex = 0;
this._buckets.length = 0;
this._valuesInfo.length = 0;
}
public containsKey(key: TKey){
if (this.tryFindIndex(key, {value: 0})){
return true;
}
return false;
}
public tryGetValue(key: TKey): TValue {
let findIndex = {value: 0};
if (this.tryFindIndex(key, findIndex)){
return this._values[findIndex.value];
}
return null;
}
public tryFindIndex(key: TKey, findIndex: {value: number}){
// 我把所有的索引都用偏移量+1来存储,这样在bucket list中0就意味着实际上不存在
// 当读取时,偏移量必须再偏移-1才是真实的
// 这样我就避免了将数组初始化为-1
let hash = FasterDictionary.hash(key);
let bucketIndex = FasterDictionary.reduce(hash, this._buckets.length);
let valueIndex = NumberExtension.toNumber(this._buckets[bucketIndex]) - 1;
// 即使我们找到了一个现有的值,我们也需要确定它是我们所要求的值
while (valueIndex != -1){
if (this._valuesInfo[valueIndex].hashcode == hash && this._valuesInfo[valueIndex].key == key){
findIndex.value = valueIndex;
return true;
}
valueIndex = this._valuesInfo[valueIndex].previous;
}
findIndex.value = 0;
return false;
}
public getDirectValue(index: number): TValue {
return this._values[index];
}
public getIndex(key: TKey): number {
let findIndex = {value: 0};
if (this.tryFindIndex(key, findIndex))
return findIndex.value;
throw new Error("未找到key");
}
public static updateLinkedList(index: number, valuesInfo: FastNode[]){
let next = valuesInfo[index].next;
let previous = valuesInfo[index].previous;
if (next != -1)
valuesInfo[next].previous = previous;
if (previous != -1)
valuesInfo[previous].next = next;
}
public static hash(key) {
return HashHelpers.getHashCode(key);
}
public static reduce(x: number, n: number) {
if (x >= n)
return x % n;
return x;
}
}
export class FastNode {
readonly key;
readonly hashcode: number;
previous: number;
next: number;
constructor(key, hash: number, previousNode: number = -1) {
this.key = key;
this.hashcode = hash;
this.previous = previousNode;
this.next = -1;
}
}
}
+90
View File
@@ -0,0 +1,90 @@
module es {
export class HashHelpers {
public static readonly hashCollisionThreshold: number = 100;
public static readonly hashPrime: number = 101;
/**
*
*
* Hashtable当前的容量为x
* 2x2x的质数p_1p_2...p_i...p_n使p_n-1 < 2x < p_n
*
* IEh1(key)+i*h2(key)0 <= i < size.h2和size必须是相对质数
*/
public static readonly primes = [3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369];
/**
* Array.MaxArrayLength小的最大质数
*/
public static readonly maxPrimeArrayLength = 0x7FEFFFFD;
public static isPrime(candidate: number): boolean {
if ((candidate & 1) != 0){
let limit = Math.sqrt(candidate);
for (let divisor = 3; divisor <= limit; divisor += 2){
if ((candidate & divisor) == 0)
return false;
}
return true;
}
return (candidate == 2);
}
public static getPrime(min: number): number{
if (min < 0)
throw new Error("参数错误 min不能小于0");
for (let i = 0; i < this.primes.length; i ++){
let prime = this.primes[i];
if (prime >= min) return prime;
}
// 在我们预定义的表之外,计算的方式稍复杂。
for (let i = (min | 1); i < Number.MAX_VALUE; i += 2){
if (this.isPrime(i) && ((i - 1) % this.hashPrime != 0))
return i;
}
return min;
}
/**
*
* @param oldSize
* @returns
*/
public static expandPrime(oldSize: number): number {
let newSize = 2 * oldSize;
// 在遇到容量溢出之前,允许哈希特表增长到最大可能的大小
// 请注意,即使当_items.Length溢出时,这项检查也会起作用
if (newSize > this.maxPrimeArrayLength && this.maxPrimeArrayLength > oldSize){
return this.maxPrimeArrayLength;
}
return this.getPrime(newSize);
}
public static getHashCode(str){
let s;
if (typeof str == 'object'){
s = JSON.stringify(str);
} else {
s = str.toString();
}
let hash = 0;
if (s.length == 0) return hash;
for (let i = 0; i < s.length; i ++){
let char = s.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return hash;
}
}
}
@@ -0,0 +1,147 @@
module es {
export class GaussianBlur {
/**
*
* @param image
* @param deviation
* @returns
*/
public static createBlurredTexture(image: egret.Texture, deviation: number = 1) {
let pixelData = image.getPixels(0, 0, image.textureWidth, image.textureHeight);
let srcData: Color[] = new Array(image.textureWidth * image.textureHeight);
for (let i = 0; i < image.textureWidth; i++) {
for (let j = 0; j < image.textureHeight; j++) {
let width = image.textureWidth;
let r = pixelData[i * 4 + j * width];
let g = pixelData[i * 4 + j * width + 1];
let b = pixelData[i * 4 + j * width + 2];
let a = pixelData[i * 4 + j * width + 3];
srcData[i + j * width] = new Color(r, g, b, a);
}
}
// TODO: 计算方式有问题 后面再研究研究
let destData = this.createBlurredTextureData(srcData, image.textureWidth, image.textureHeight, deviation);
let arrayBuffer = new ArrayBuffer(destData.length);
destData.forEach((value, index) => {
arrayBuffer[index] = value.packedValue;
});
egret.BitmapData.create("arraybuffer", arrayBuffer, (bitmapData) => {
// TODO: 生成bitmapdata
});
}
public static createBlurredTextureData(srcData: Color[], width: number, height: number, deviation: number = 1) {
let matrixR = new FasterDictionary<{ x: number, y: number }, number>();
let matrixG = new FasterDictionary<{ x: number, y: number }, number>();
let matrixB = new FasterDictionary<{ x: number, y: number }, number>();
let matrixA = new FasterDictionary<{ x: number, y: number }, number>();
let destData: Color[] = new Array(width * height);
// 首先,我们计算出灰度,并将其存储在矩阵中
for (let i = 0; i < width; i++) {
for (let j = 0; j < height; j++) {
matrixR.add({ x: i, y: j }, srcData[i + j * width].r);
matrixG.add({ x: i, y: j }, srcData[i + j * width].g);
matrixB.add({ x: i, y: j }, srcData[i + j * width].b);
matrixA.add({ x: i, y: j }, srcData[i + j * width].a);
}
}
matrixR = this.gaussianConvolution(matrixR, deviation);
matrixG = this.gaussianConvolution(matrixG, deviation);
matrixB = this.gaussianConvolution(matrixB, deviation);
matrixA = this.gaussianConvolution(matrixA, deviation);
for (let i = 0; i < width; i++) {
for (let j = 0; j < height; j++) {
let r = Math.min(255, matrixR.tryGetValue({x: i, y: j}));
let g = Math.min(255, matrixG.tryGetValue({x: i, y: j}));
let b = Math.min(255, matrixB.tryGetValue({x: i, y: j}));
let a = Math.min(255, matrixA.tryGetValue({x: i, y: j}));
destData[i + j * width] = new Color(r, g, b, a);
}
}
return destData;
}
public static gaussianConvolution(matrix: FasterDictionary<{ x: number, y: number }, number>, deviation: number) {
let kernel = this.calculateNormalized1DSampleKernel(deviation);
let res1 = new FasterDictionary<{ x: number, y: number }, number>();
let res2 = new FasterDictionary<{ x: number, y: number }, number>();
for (let i = 0; i < matrix._valuesInfo.length; i++) {
for (let j = 0; j < matrix.valuesArray.length; j++)
res1.add({ x: i, y: j }, this.processPoint(matrix, i, j, kernel, 0));
}
for (let i = 0; i < matrix._valuesInfo.length; i++) {
for (let j = 0; j < matrix.valuesArray.length; j++)
res2.add({ x: i, y: j }, this.processPoint(res1, i, j, kernel, 1));
}
return res2;
}
public static processPoint(matrix: FasterDictionary<{ x: number, y: number }, number>,
x: number,
y: number,
kernel: FasterDictionary<{ x: number, y: number }, number>,
direction: number) {
let res = 0;
let half = kernel._valuesInfo.length / 2;
for (let i = 0; i < kernel._valuesInfo.length; i++) {
let cox = direction == 0 ? x + i - half : x;
let coy = direction == 1 ? y + i - half : y;
if (cox >= 0 && cox < matrix._valuesInfo.length && coy >= 0 && coy < matrix.valuesArray.length)
res += matrix.tryGetValue({ x: cox, y: coy }) * kernel.tryGetValue({x: i, y: 0});
}
return res;
}
public static calculate1DSampleKernel(deviation: number) {
let size = Math.ceil(deviation * 3) * 3 + 1;
return this.calculate1DSampleKernelOfSize(deviation, size);
}
public static calculate1DSampleKernelOfSize(deviation: number, size: number) {
let ret = new FasterDictionary<{ x: number, y: number }, number>();
// let sum = 0;
let half = (size - 1) / 2;
for (let i = 0; i < size; i++) {
ret.add({x: i, y: 0}, 1 / (Math.sqrt(2 * Math.PI) * deviation) * Math.exp(-(i - half) * (i - half) / (2 * deviation * deviation)));
// sum += ret.tryGetValue({x: i, y: 0});
}
return ret;
}
public static calculateNormalized1DSampleKernel(deviation: number) {
return this.normalizeMatrix(this.calculate1DSampleKernel(deviation));
}
public static normalizeMatrix(matrix: FasterDictionary<{ x: number, y: number }, number>) {
let ret = new FasterDictionary<{ x: number, y: number }, number>();
let sum = 0;
for (let i = 0; i < ret._valuesInfo.length; i++) {
for (let j = 0; j < ret.valuesArray.length; j++) {
sum += matrix.tryGetValue({x: i, y: j});
}
}
if (sum != 0) {
for (let i = 0; i < ret._valuesInfo.length; i++) {
for (let j = 0; j < ret.valuesArray.length; j++) {
ret.add({x: i, y: j}, matrix.tryGetValue({x: i, y: j}) / sum);
}
}
}
return ret;
}
}
}
+9
View File
@@ -0,0 +1,9 @@
module es {
export class NumberExtension {
public static toNumber(value){
if (value == undefined) return 0;
return Number(value);
}
}
}