A*寻路 -- 算法优化

本文介绍了一种使用AS3实现的寻路算法,通过优化数据结构和预计算步骤,显著提高了路径查找效率。算法包含二叉堆、版本替代、简化估算公式、预运算和代码优化等关键步骤,适用于复杂地图环境。实验证明,在大量测试案例中,该算法性能超越同类实现。

基本思路:

 

1二叉堆

2用version代替close open列表

3用精简的估计公式

4提前运算

5代码本身的优化。

 

这个寻路算法基本还没找到as3写的能超过他的。

 


 

Java代码 复制代码  收藏代码
  1. package {   
  2.     /**  
  3.      * ...  
  4.      * @author sliz http://game-develop.net/blog/  
  5.      */  
  6.     import flash.display.Bitmap;   
  7.     import flash.display.BitmapData;   
  8.     import flash.display.Sprite;   
  9.     import flash.display.StageAlign;   
  10.     import flash.display.StageScaleMode;   
  11.     import flash.events.Event;   
  12.     import flash.events.MouseEvent;   
  13.     import flash.geom.Rectangle;   
  14.     import flash.text.TextField;   
  15.     import flash.utils.getTimer;   
  16.     import sliz.miniui.Button;   
  17.     import sliz.miniui.Checkbox;   
  18.     import sliz.miniui.Label;   
  19.     import sliz.miniui.LabelInput;   
  20.     import sliz.miniui.layouts.BoxLayout;   
  21.     import sliz.miniui.Window;   
  22.   
  23.     public class Test extends Sprite {   
  24.         private var _cellSize:int = 5;   
  25.         private var _grid:Grid;   
  26.         private var _player:Sprite;   
  27.         private var _index:int;   
  28.         private var _path:Array;   
  29.   
  30.         private var tf:Label;   
  31.         private var astar:AStar;   
  32.   
  33.         private var path:Sprite = new Sprite();   
  34.         private var image:Bitmap = new Bitmap(new BitmapData(11));   
  35.         private var imageWrapper:Sprite = new Sprite();   
  36.   
  37.         public function Test(){   
  38.             stage.align = StageAlign.TOP_LEFT;   
  39.             stage.scaleMode = StageScaleMode.NO_SCALE;   
  40.             stage.frameRate = 100;   
  41.             addChild(imageWrapper);   
  42.             imageWrapper.addChild(image);   
  43.             makePlayer();   
  44.   
  45.             var w:Window = new Window(this2020"tool");   
  46.             numCols = new LabelInput("numCols ""numCols");   
  47.             numCols.setValue("115");   
  48.             w.add(numCols);   
  49.             numRows = new LabelInput("numRows ""numRows");   
  50.             w.add(numRows);   
  51.             numRows.setValue("115");   
  52.             cellSize = new LabelInput("cellSize""cellSize");   
  53.             cellSize.setValue("4");   
  54.             w.add(cellSize);   
  55.             density = new LabelInput("density ""density");   
  56.             density.setValue("0.1");   
  57.             w.add(density);   
  58.             isEight = new Checkbox("eight directions");   
  59.             isEight.setToggle(true);   
  60.             w.add(isEight);   
  61.             tf = new Label("info");   
  62.             w.add(tf);   
  63.             w.add(new sliz.miniui.Link("author sliz"));   
  64.             var btn:Button = new Button("new"00null, newMap);   
  65.             w.add(btn, null0.8);   
  66.             w.setLayout(new BoxLayout(w, 15));   
  67.             w.doLayout();   
  68.             imageWrapper.addEventListener(MouseEvent.CLICK, onGridClick);   
  69.             addEventListener(Event.ENTER_FRAME, onEnterFrame);   
  70.             imageWrapper.addChild(path);   
  71.             makeGrid();   
  72.         }   
  73.   
  74.         private function newMap(e:Event):void {   
  75.             makeGrid();   
  76.         }   
  77.   
  78.         private function makePlayer():void {   
  79.             _player = new Sprite();   
  80.             _player.graphics.beginFill(0xff00ff);   
  81.             _player.graphics.drawCircle(002);   
  82.             _player.graphics.endFill();   
  83.             imageWrapper.addChild(_player);   
  84.         }   
  85.   
  86.         private function makeGrid():void {   
  87.             var rows:int = int(numRows.getValue());   
  88.             var cols:int = int(numCols.getValue());   
  89.             _cellSize = int(cellSize.getValue());   
  90.             _grid = new Grid(cols, rows);   
  91.             for (var i:int = 0; i < rows * cols * Number(density.getValue()); i++){   
  92.                 _grid.setWalkable(Math.floor(Math.random() * cols), Math.floor(Math.random() * rows), false);   
  93.             }   
  94.             _grid.setWalkable(00true);   
  95.             _grid.setWalkable(cols / 2, rows / 2false);   
  96.             if (isEight.getToggle())   
  97.                 _grid.calculateLinks();   
  98.             else  
  99.                 _grid.calculateLinks(1);   
  100.             astar = new AStar(_grid);   
  101.             drawGrid();   
  102.             isClick = false;   
  103.             _player.x = 0;   
  104.             _player.y = 0;   
  105.             path.graphics.clear();   
  106.         }   
  107.   
  108.   
  109.         private function drawGrid():void {   
  110.             image.bitmapData = new BitmapData(_grid.numCols * _cellSize, _grid.numRows * _cellSize, false0xffffff);   
  111.             for (var i:int = 0; i < _grid.numCols; i++){   
  112.                 for (var j:int = 0; j < _grid.numRows; j++){   
  113.                     var node:Node = _grid.getNode(i, j);   
  114.                     if (!node.walkable){   
  115.                         image.bitmapData.fillRect(new Rectangle(i * _cellSize, j * _cellSize, _cellSize, _cellSize), getColor(node));   
  116.                     }   
  117.                 }   
  118.             }   
  119.         }   
  120.   
  121.         private function getColor(node:Node):uint {   
  122.             if (!node.walkable)   
  123.                 return 0;   
  124.             if (node == _grid.startNode)   
  125.                 return 0xcccccc;   
  126.             if (node == _grid.endNode)   
  127.                 return 0xcccccc;   
  128.             return 0xffffff;   
  129.         }   
  130.   
  131.         private function onGridClick(event:MouseEvent):void {   
  132.             var xpos:int = Math.floor(mouseX / _cellSize);   
  133.             var ypos:int = Math.floor(mouseY / _cellSize);   
  134.             xpos = Math.min(xpos, _grid.numCols - 1);   
  135.             ypos = Math.min(ypos, _grid.numRows - 1);   
  136.             _grid.setEndNode(xpos, ypos);   
  137.   
  138.             xpos = Math.floor(_player.x / _cellSize);   
  139.             ypos = Math.floor(_player.y / _cellSize);   
  140.             _grid.setStartNode(xpos, ypos);   
  141.             findPath();   
  142.             path.graphics.clear();   
  143.             path.graphics.lineStyle(00xff00000.5);   
  144.             path.graphics.moveTo(_player.x, _player.y);   
  145.         }   
  146.   
  147.         private function findPath():void {   
  148.             var time:int = getTimer();   
  149.             if (astar.findPath()){   
  150.                 time = getTimer() - time;   
  151.                 tf.text = time + "ms   length:" + astar.path.length;   
  152.                 _path = astar.path;   
  153.                 _index = 0;   
  154.                 isClick = true;   
  155.             } else {   
  156.                 time = getTimer() - time;   
  157.                 tf.text = time + "ms 找不到";   
  158.             }   
  159.         }   
  160.   
  161.         private var isClick:Boolean = false;   
  162.         private var numCols:LabelInput;   
  163.         private var numRows:LabelInput;   
  164.         private var cellSize:LabelInput;   
  165.         private var density:LabelInput;   
  166.         private var isEight:Checkbox;   
  167.   
  168.         private function onEnterFrame(event:Event):void {   
  169.             if (!isClick){   
  170.                 return;   
  171.             }   
  172.             var targetX:Number = _path[_index].x * _cellSize + _cellSize / 2;   
  173.             var targetY:Number = _path[_index].y * _cellSize + _cellSize / 2;   
  174.             var dx:Number = targetX - _player.x;   
  175.             var dy:Number = targetY - _player.y;   
  176.             var dist:Number = Math.sqrt(dx * dx + dy * dy);   
  177.             if (dist < 1){   
  178.                 _index++;   
  179.                 if (_index >= _path.length){   
  180.                     isClick = false;   
  181.                 }   
  182.             } else {   
  183.                 _player.x += dx * .5;   
  184.                 _player.y += dy * .5;   
  185.                 path.graphics.lineTo(_player.x, _player.y);   
  186.             }   
  187.         }   
  188.     }   
  189. }   
  190.   
  191.   
  192. /**  
  193.  * ...  
  194.  * @author sliz http://game-develop.net/blog/  
  195.  */  
  196. class AStar {   
  197.     //private var _open:Array;   
  198.     private var _open:BinaryHeap;   
  199.     private var _grid:Grid;   
  200.     private var _endNode:Node;   
  201.     private var _startNode:Node;   
  202.     private var _path:Array;   
  203.     public var heuristic:Function;   
  204.     private var _straightCost:Number = 1.0;   
  205.     private var _diagCost:Number = Math.SQRT2;   
  206.     private var nowversion:int = 1;   
  207.   
  208.     public function AStar(grid:Grid){   
  209.         this._grid = grid;   
  210.         heuristic = euclidian2;   
  211.   
  212.     }   
  213.   
  214.     private function justMin(x:Object, y:Object):Boolean {   
  215.         return x.f < y.f;   
  216.     }   
  217.   
  218.     public function findPath():Boolean {   
  219.         _endNode = _grid.endNode;   
  220.         nowversion++;   
  221.         _startNode = _grid.startNode;   
  222.         //_open = [];   
  223.         _open = new BinaryHeap(justMin);   
  224.         _startNode.g = 0;   
  225.         return search();   
  226.     }   
  227.   
  228.     public function search():Boolean {   
  229.         var node:Node = _startNode;   
  230.         node.version = nowversion;   
  231.         while (node != _endNode){   
  232.             var len:int = node.links.length;   
  233.             for (var i:int = 0; i < len; i++){   
  234.                 var test:Node = node.links[i].node;   
  235.                 var cost:Number = node.links[i].cost;   
  236.                 var g:Number = node.g + cost;   
  237.                 var h:Number = heuristic(test);   
  238.                 var f:Number = g + h;   
  239.                 if (test.version == nowversion){   
  240.                     if (test.f > f){   
  241.                         test.f = f;   
  242.                         test.g = g;   
  243.                         test.h = h;   
  244.                         test.parent = node;   
  245.                     }   
  246.                 } else {   
  247.                     test.f = f;   
  248.                     test.g = g;   
  249.                     test.h = h;   
  250.                     test.parent = node;   
  251.                     _open.ins(test);   
  252.                     test.version = nowversion;   
  253.                 }   
  254.   
  255.             }   
  256.             if (_open.a.length == 1){   
  257.                 return false;   
  258.             }   
  259.             node = _open.pop() as Node;   
  260.         }   
  261.         buildPath();   
  262.         return true;   
  263.     }   
  264.   
  265.     private function buildPath():void {   
  266.         _path = [];   
  267.         var node:Node = _endNode;   
  268.         _path.push(node);   
  269.         while (node != _startNode){   
  270.             node = node.parent;   
  271.             _path.unshift(node);   
  272.         }   
  273.     }   
  274.   
  275.     public function get path():Array {   
  276.         return _path;   
  277.     }   
  278.   
  279.     public function manhattan(node:Node):Number {   
  280.         return Math.abs(node.x - _endNode.x) + Math.abs(node.y - _endNode.y);   
  281.     }   
  282.   
  283.     public function manhattan2(node:Node):Number {   
  284.         var dx:Number = Math.abs(node.x - _endNode.x);   
  285.         var dy:Number = Math.abs(node.y - _endNode.y);   
  286.         return dx + dy + Math.abs(dx - dy) / 1000;   
  287.     }   
  288.   
  289.     public function euclidian(node:Node):Number {   
  290.         var dx:Number = node.x - _endNode.x;   
  291.         var dy:Number = node.y - _endNode.y;   
  292.         return Math.sqrt(dx * dx + dy * dy);   
  293.     }   
  294.   
  295.     private var TwoOneTwoZero:Number = 2 * Math.cos(Math.PI / 3);   
  296.   
  297.     public function chineseCheckersEuclidian2(node:Node):Number {   
  298.         var y:int = node.y / TwoOneTwoZero;   
  299.         var x:int = node.x + node.y / 2;   
  300.         var dx:Number = x - _endNode.x - _endNode.y / 2;   
  301.         var dy:Number = y - _endNode.y / TwoOneTwoZero;   
  302.         return sqrt(dx * dx + dy * dy);   
  303.     }   
  304.   
  305.     private function sqrt(x:Number):Number {   
  306.         return Math.sqrt(x);   
  307.     }   
  308.   
  309.     public function euclidian2(node:Node):Number {   
  310.         var dx:Number = node.x - _endNode.x;   
  311.         var dy:Number = node.y - _endNode.y;   
  312.         return dx * dx + dy * dy;   
  313.     }   
  314.   
  315.     public function diagonal(node:Node):Number {   
  316.         var dx:Number = Math.abs(node.x - _endNode.x);   
  317.         var dy:Number = Math.abs(node.y - _endNode.y);   
  318.         var diag:Number = Math.min(dx, dy);   
  319.         var straight:Number = dx + dy;   
  320.         return _diagCost * diag + _straightCost * (straight - 2 * diag);   
  321.     }   
  322. }   
  323.   
  324. class Grid {   
  325.   
  326.     private var _startNode:Node;   
  327.     private var _endNode:Node;   
  328.     private var _nodes:Array;   
  329.     private var _numCols:int;   
  330.     private var _numRows:int;   
  331.   
  332.     private var type:int;   
  333.   
  334.     private var _straightCost:Number = 1.0;   
  335.     private var _diagCost:Number = Math.SQRT2;   
  336.   
  337.     public function Grid(numCols:int, numRows:int){   
  338.         _numCols = numCols;   
  339.         _numRows = numRows;   
  340.         _nodes = new Array();   
  341.   
  342.         for (var i:int = 0; i < _numCols; i++){   
  343.             _nodes[i] = new Array();   
  344.             for (var j:int = 0; j < _numRows; j++){   
  345.                 _nodes[i][j] = new Node(i, j);   
  346.             }   
  347.         }   
  348.     }   
  349.   
  350.     /**  
  351.      *  
  352.      * @param    type    0四方向 1八方向 2跳棋  
  353.      */  
  354.     public function calculateLinks(type:int = 0):void {   
  355.         this.type = type;   
  356.         for (var i:int = 0; i < _numCols; i++){   
  357.             for (var j:int = 0; j < _numRows; j++){   
  358.                 initNodeLink(_nodes[i][j], type);   
  359.             }   
  360.         }   
  361.     }   
  362.   
  363.     public function getType():int {   
  364.         return type;   
  365.     }   
  366.   
  367.     /**  
  368.      *  
  369.      * @param    node  
  370.      * @param    type    0八方向 1四方向 2跳棋  
  371.      */  
  372.     private function initNodeLink(node:Node, type:int):void {   
  373.         var startX:int = Math.max(0, node.x - 1);   
  374.         var endX:int = Math.min(numCols - 1, node.x + 1);   
  375.         var startY:int = Math.max(0, node.y - 1);   
  376.         var endY:int = Math.min(numRows - 1, node.y + 1);   
  377.         node.links = [];   
  378.         for (var i:int = startX; i <= endX; i++){   
  379.             for (var j:int = startY; j <= endY; j++){   
  380.                 var test:Node = getNode(i, j);   
  381.                 if (test == node || !test.walkable){   
  382.                     continue;   
  383.                 }   
  384.                 if (type != 2 && i != node.x && j != node.y){   
  385.                     var test2:Node = getNode(node.x, j);   
  386.                     if (!test2.walkable){   
  387.                         continue;   
  388.                     }   
  389.                     test2 = getNode(i, node.y);   
  390.                     if (!test2.walkable){   
  391.                         continue;   
  392.                     }   
  393.                 }   
  394.                 var cost:Number = _straightCost;   
  395.                 if (!((node.x == test.x) || (node.y == test.y))){   
  396.                     if (type == 1){   
  397.                         continue;   
  398.                     }   
  399.                     if (type == 2 && (node.x - test.x) * (node.y - test.y) == 1){   
  400.                         continue;   
  401.                     }   
  402.                     if (type == 2){   
  403.                         cost = _straightCost;   
  404.                     } else {   
  405.                         cost = _diagCost;   
  406.                     }   
  407.                 }   
  408.                 node.links.push(new Link(test, cost));   
  409.             }   
  410.         }   
  411.     }   
  412.   
  413.     public function getNode(x:int, y:int):Node {   
  414.         return _nodes[x][y];   
  415.     }   
  416.   
  417.     public function setEndNode(x:int, y:int):void {   
  418.         _endNode = _nodes[x][y];   
  419.     }   
  420.   
  421.     public function setStartNode(x:int, y:int):void {   
  422.         _startNode = _nodes[x][y];   
  423.     }   
  424.   
  425.     public function setWalkable(x:int, y:int, value:Boolean):void {   
  426.         _nodes[x][y].walkable = value;   
  427.     }   
  428.   
  429.     public function get endNode():Node {   
  430.         return _endNode;   
  431.     }   
  432.   
  433.     public function get numCols():int {   
  434.         return _numCols;   
  435.     }   
  436.   
  437.     public function get numRows():int {   
  438.         return _numRows;   
  439.     }   
  440.   
  441.     public function get startNode():Node {   
  442.         return _startNode;   
  443.     }   
  444.   
  445. }   
  446.   
  447. class Link {   
  448.     public var node:Node;   
  449.     public var cost:Number;   
  450.   
  451.     public function Link(node:Node, cost:Number){   
  452.         this.node = node;   
  453.         this.cost = cost;   
  454.     }   
  455.   
  456. }   
  457.   
  458. class BinaryHeap {   
  459.     public var a:Array = [];   
  460.     public var justMinFun:Function = function(x:Object, y:Object):Boolean {   
  461.         return x < y;   
  462.     };   
  463.   
  464.     public function BinaryHeap(justMinFun:Function = null){   
  465.         a.push(-1);   
  466.         if (justMinFun != null)   
  467.             this.justMinFun = justMinFun;   
  468.     }   
  469.   
  470.     public function ins(value:Object):void {   
  471.         var p:int = a.length;   
  472.         a[p] = value;   
  473.         var pp:int = p >> 1;   
  474.         while (p > 1 && justMinFun(a[p], a[pp])){   
  475.             var temp:Object = a[p];   
  476.             a[p] = a[pp];   
  477.             a[pp] = temp;   
  478.             p = pp;   
  479.             pp = p >> 1;   
  480.         }   
  481.     }   
  482.   
  483.     public function pop():Object {   
  484.         var min:Object = a[1];   
  485.         a[1] = a[a.length - 1];   
  486.         a.pop();   
  487.         var p:int = 1;   
  488.         var l:int = a.length;   
  489.         var sp1:int = p << 1;   
  490.         var sp2:int = sp1 + 1;   
  491.         while (sp1 < l){   
  492.             if (sp2 < l){   
  493.                 var minp:int = justMinFun(a[sp2], a[sp1]) ? sp2 : sp1;   
  494.             } else {   
  495.                 minp = sp1;   
  496.             }   
  497.             if (justMinFun(a[minp], a[p])){   
  498.                 var temp:Object = a[p];   
  499.                 a[p] = a[minp];   
  500.                 a[minp] = temp;   
  501.                 p = minp;   
  502.                 sp1 = p << 1;   
  503.                 sp2 = sp1 + 1;   
  504.             } else {   
  505.                 break;   
  506.             }   
  507.         }   
  508.         return min;   
  509.     }   
  510. }   
  511.   
  512. class Node {   
  513.     public var x:int;   
  514.     public var y:int;   
  515.     public var f:Number;   
  516.     public var g:Number;   
  517.     public var h:Number;   
  518.     public var walkable:Boolean = true;   
  519.     public var parent:Node;   
  520.     //public var costMultiplier:Number = 1.0;   
  521.     public var version:int = 1;   
  522.     public var links:Array;   
  523.   
  524.     //public var index:int;   
  525.     public function Node(x:int, y:int){   
  526.         this.x = x;   
  527.         this.y = y;   
  528.     }   
word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1

登录后您可以享受以下权益:

×
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

举报

选择你想要举报的内容(必选)
  • 内容涉黄
  • 政治相关
  • 内容抄袭
  • 涉嫌广告
  • 内容侵权
  • 侮辱谩骂
  • 样式问题
  • 其他
点击体验
DeepSeekR1满血版
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服
新手引导
返回顶部