A*寻路 -- 算法优化

时间:2022-12-04 04:24:53

基本思路:

 

1二叉堆

2用version代替close open列表

3用精简的估计公式

4提前运算

5代码本身的优化。

 

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

 


A*寻路 -- 算法优化

 

Java代码 A*寻路 -- 算法优化 A*寻路 -- 算法优化A*寻路 -- 算法优化
  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.     }