天神降临,大家过来膜拜吧!
oh yeah!
转载请声明出处,例子代码可以免费随意使用,但请保留或注明作者信息.
这里的算法说是终极优化, 我挑战了一下,
http://eidiot.net/2007/04/17/a-star-pathfinding/
最终结果比较他快三倍, 我站在高高处,藐视了 一下作者.
优化思路:
a.开包(open list)算法优化:
线性查找-->
二叉堆(binary heap 容器:Array->Vector)->
二分排序插入/删除(容器:Array)
b. 障碍点容器优化:
dictionary(1维) ->dictionary(2维)-- array(1维)->array(2维)->bitmapdata->bytearray(8位对齐)->byteArrayarray(32位对齐)->vector.
c. 闭包(close list)容器优化:
dictionary(1维) -> array(1维)->bitmapdata->vector.
d. 过程生成的路点对象内存管理优化:
AS动态对象(Object)->非动态对象(自定义PathNode对象)->使用bytearray自己管理内存分配对象-->使用Vector自已管理内存分配对象.
e. 评估函数:
标准(F = G+H, G=Parent.G+DIR_G, H = (ABS(X1-X)+ABS(Y1-Y) )*10 )
上述优化基本上是 左->右 == 慢->快
测试结果部分
单位:毫秒
地图大小:500x500地图:
从41条测试线路的平均值结果, 足足快3倍, 比较未优化但是快了25倍以上
未优化 10886 ms
所谓终极优化 1361.414634 ms
二分插入排序 ByteArray做内存管理 (32bit对齐 ) 479.195122 ms
二分插入排序Vector做内存管理 447.2439024 ms
startX |
startY |
endX |
endY |
距离 |
未优化 |
所谓 终极 优化 |
二分插入排序ByteArray做内存管理(32bit对齐) |
二分插入排序 Vector做内存管理 |
36 |
32 |
113 |
125 |
120.7394 |
17 |
8 |
10 |
11 |
113 |
125 |
34 |
29 |
124.3262 |
16 |
7 |
11 |
11 |
34 |
29 |
469 |
463 |
614.4762 |
9133 |
1338 |
544 |
493 |
469 |
463 |
152 |
155 |
441.9876 |
超时 |
8536 |
2810 |
2560 |
152 |
155 |
169 |
165 |
19.72308 |
17763 |
2743 |
957 |
894 |
169 |
165 |
465 |
463 |
420.0238 |
1159 |
219 |
101 |
97 |
465 |
463 |
165 |
143 |
438.6342 |
超时 |
8385 |
2594 |
2470 |
165 |
143 |
220 |
146 |
55.08176 |
19685 |
2958 |
1031 |
965 |
220 |
146 |
229 |
139 |
11.40175 |
725 |
234 |
124 |
116 |
229 |
139 |
111 |
477 |
358.0056 |
827 |
168 |
72 |
70 |
111 |
477 |
327 |
350 |
250.5694 |
1705 |
364 |
164 |
158 |
327 |
350 |
319 |
340 |
12.80625 |
210 |
71 |
38 |
38 |
319 |
340 |
464 |
477 |
199.4843 |
51 |
20 |
18 |
17 |
464 |
477 |
71 |
26 |
598.2057 |
20912 |
2370 |
801 |
774 |
71 |
26 |
465 |
468 |
592.1149 |
6158 |
922 |
362 |
348 |
465 |
468 |
119 |
188 |
445.1022 |
超时 |
7749 |
2499 |
2372 |
119 |
188 |
219 |
314 |
160.8602 |
3625 |
804 |
309 |
286 |
219 |
314 |
79 |
401 |
164.8302 |
28 |
11 |
10 |
12 |
79 |
401 |
229 |
309 |
175.9659 |
141 |
35 |
24 |
23 |
229 |
309 |
91 |
432 |
184.8594 |
41 |
13 |
13 |
12 |
91 |
432 |
65 |
446 |
29.52965 |
2 |
1 |
7 |
6 |
65 |
446 |
227 |
310 |
211.5183 |
100 |
21 |
16 |
14 |
227 |
310 |
62 |
444 |
212.5582 |
78 |
15 |
13 |
14 |
62 |
444 |
354 |
26 |
509.8902 |
644 |
89 |
38 |
36 |
354 |
26 |
479 |
27 |
125.004 |
32 |
14 |
14 |
13 |
479 |
27 |
27 |
469 |
632.193 |
352 |
48 |
29 |
29 |
27 |
469 |
10 |
18 |
451.3203 |
3733 |
936 |
384 |
354 |
10 |
18 |
473 |
463 |
642.1791 |
9152 |
1331 |
534 |
493 |
473 |
463 |
100 |
260 |
424.6622 |
5947 |
782 |
268 |
255 |
100 |
260 |
234 |
152 |
172.1046 |
2182 |
531 |
241 |
226 |
234 |
152 |
248 |
135 |
22.02272 |
超时 |
0 |
113 |
0 |
234 |
152 |
249 |
137 |
21.2132 |
598 |
193 |
113 |
104 |
249 |
137 |
120 |
234 |
161.4001 |
5200 |
951 |
401 |
377 |
120 |
234 |
154 |
203 |
46.01087 |
1557 |
418 |
214 |
201 |
154 |
203 |
404 |
237 |
252.3014 |
4173 |
882 |
357 |
335 |
404 |
237 |
11 |
15 |
451.3679 |
8876 |
1331 |
572 |
543 |
11 |
15 |
230 |
409 |
450.7738 |
55030 |
7070 |
2308 |
2179 |
230 |
409 |
240 |
97 |
312.1602 |
1541 |
325 |
161 |
152 |
240 |
97 |
25 |
19 |
228.7116 |
1819 |
375 |
181 |
167 |
25 |
19 |
148 |
156 |
184.1141 |
29 |
10 |
12 |
9 |
148 |
156 |
169 |
188 |
38.27532 |
23085 |
3540 |
1179 |
1103 |
平均ms |
10886 |
1361.415 |
479.2 |
447 |
代码:FindPathImplVetorMem.as
/**
@author aerror
*/
package
{
import flash.utils.ByteArray;
import flash.utils.Endian;
public class FindPathImplVetorMem
{
public static const BLOCK_TYPE_NULL:int = 0;
public static const BLOCK_TYPE_STATIC:int = 1;
public static const BLOCK_TYPE_ENTRY:int = 2;
public static const BLOCK_TYPE_ITEM:int = 4;
private var obstacles:Vector.;
private var iwidth:uint;
private var iheight:uint;
private var nearby:Vector.;
private var nearbyStraight:Vector.;
private var nearbyCross:Vector.;
private static const STATE_NULL:uint = 0;
private static const STATE_CLOSE:uint = 1;
/**
*
*
* */
public function FindPathImplVetorMem()
{
nearbyStraight = new Vector.();
nearbyStraight.push(
-1,-1,14,
0,-1,10,
1,-1,14,
1,0,10,
1,1,14,
0,1,10,
-1,1,14,
-1,0,10
);
nearbyCross = new Vector.();
nearbyCross.push(
-1,-1,10,
0,-1,14,
1,-1,10,
1,0,14,
1,1,10,
0,1,14,
-1,1,10,
-1,0,14
);
nearby = nearbyStraight;
}
public function initSys():void
{
}
public function clearBlock():void
{
if(obstacles!=null)
{
//obstacles.dispose();
obstacles = null;
}
}
public function initMap(_mapCol:int, _mapRow:int, bytes:ByteArray):void
{
clearBlock();
this.iwidth = _mapCol;
this.iheight = _mapRow;
obstacles = new Vector.(iwidth*iheight);
var num:int = bytes.length/6;
for(var i:int=0;i= new Vector.(width * height);
var startPoint:uint = nodelist.createNode(startX,startY,0,0,PathNodeFactoryVector.NULL);
key = x + width * y;
opneListSortedArr.push(startPoint);
stateMap[key]=startPoint;
opneNum = 1;
minIndex = 0;
var found_end_point:uint = PathNodeFactoryVector.NULL;
var x:int;
var y:int;
var g:int;
var h:Number;
var f:int;
var i:int;
var min:uint = PathNodeFactoryVector.NULL;
while(true)
{
var min_key:uint;
var min_x:uint;
var min_y:uint;
var min_f:uint;
var min_g:uint;
//find the min g+h point
//
if(opneNum >0)
{
//remove from openlist;
min = opneListSortedArr.shift();
min_x = nodelist.getNodeX(min);
min_y = nodelist.getNodeY(min);
min_g = nodelist.getNodeG(min);
min_key = min_x + width * min_y;
opneNum--;
}
else
{
trace("FIND PATH FAILED");
break;
}
//add to close list;
stateMap[min_key] = STATE_CLOSE;// = min;
//add nearby point to openlist
for( i = 0;i<8;i++)
{
x = min_x + nearby[i*3];
y = min_y + nearby[i*3+1];
key = x + width * y;
//calc h
//
h = ((endX= width || x < 0 //out of bounds ?
|| y >= height || y < 0//out of bounds ?
|| obstacles[key]!=BLOCK_TYPE_NULL //is obstacle ?
)
{
continue;
}
// if in close list?
var state:uint = stateMap[key];
if(state==STATE_CLOSE)
{
continue;
}
//calc g
//
g = (nearby[i*3+2]+min_g);
f = g+h;
//check if new point or old
//
var newPt:uint;
//the old point
//key key its g value,update if new g is less
//
if(state==STATE_NULL)
{
//the new point
//
newPt = nodelist.createNode(x,y,g,f,min);
stateMap[key] = newPt;
nodelist.sortInsert(opneListSortedArr,newPt,0,opneNum);
opneNum++;
}
else if(g
/**
@author aerror
*/
package
{
public class PathNodeFactoryVector
{
public static const NULL:uint = 0;
private var mem:Vector.;
private var writePosition:uint =0;
public function PathNodeFactoryVector(max:uint)
{
mem = new Vector.(max*4+4);
writePosition = 4;
}
public function getNodeX(id:uint):uint
{
return mem[id]&0xffff;
}
public function getNodeY(id:uint):uint
{
return mem[id]>>16 &0xffff;
}
public function getNodeG(id:uint):uint
{
return mem[id+1];
}
public function getNodeF(id:uint):uint
{
return mem[id+2];
}
public function getNodeParent(id:uint):uint
{
return mem[id+3];
}
public function createNode(_x:uint,_y:uint,_g:uint, _f:uint,_linkParent:uint):uint
{
mem[writePosition + 0] = (_x | _y<<16 );
mem[writePosition + 1]= _g;
mem[writePosition + 2]= _f;
mem[writePosition + 3]= _linkParent;
writePosition += 4;
return writePosition-4;
}
public function checkOK(arr:Array):Boolean
{
for(var i:int=0;i < arr.length-1;i++)
{
if(getNodeF(arr[i]) >getNodeF(arr[i+1]))
{
return false;
}
}
return true;
}
public function sortInsert(arr:Array, newPt:uint, begin:int, end:int):void
{
//optimize for empty array
if(arr.length==0)
{
arr.push(newPt);
return;
}
var new_F:uint = getNodeF(newPt);
var cur_F:uint = getNodeF(arr[begin]);
//optimize for sorted inserting with less
if(new_F <= cur_F )
{
arr.splice(0,0,newPt);
return;
}
//optimize for sorted inserting with larger
cur_F = getNodeF(arr[end-1]);
if(new_F >cur_F)
{
arr.splice(end,0,newPt);
return;
}
else if(new_F == cur_F)
{
arr.splice(end-1,0,newPt);
return;
}
while(true)
{
if(begin==end)
{
cur_F = getNodeF(arr[begin]);
if(new_F > cur_F)
arr.splice(begin+1,0,newPt);
else
arr.splice(begin,0,newPt);
return ;
}
//find a place
var mid:int = begin+(end-begin)/2;
cur_F =getNodeF(arr[mid]);
if(new_F < cur_F)
{
end = mid;
}
else if(new_F > cur_F)
{
begin = mid +1;
}
else
{
arr.splice(mid,0,newPt);
return;
}
}
}
public function sortRemove(arr:Array, oldPt:uint, begin:int, end:int):void
{
var old_f:uint = getNodeF(oldPt);
var i:int;
while(true)
{
//find a place
var mid:int = begin+(end-begin)/2;
var cur_f:uint = getNodeF(arr[mid]);
if(old_f < cur_f)
{
end = mid;
}
else if(old_f > cur_f)
{
begin = mid +1;
}
else
{
for(i =mid; i=0 ; i--)
{
if(oldPt==arr[i])
{
arr.splice(i,1);
return ;
}
}
return ;
}
}
}
public function clear():void
{
this.mem.length = 0;
}
public function getUsedLength():uint
{
return this.writePosition;
}
public function dumpArray(opneListSortedArr:Array):void
{
for(var j:int =0;j