算法找到网格上所有单元格的最短路径

时间:2014-06-07 00:10:53

标签: algorithm actionscript-3 search shortest-path

我有一个格子[40 x 15],上面有2到16个单位,以及未知数量的障碍物 如何从我的单位位置找到所有单位的最短路径。

我有两个辅助方法,我们可以考虑为O(1)

  • getMyLocation() - 返回我在网格上的位置的(x,y)坐标
  • investigCell(x,y) - 返回有关(x,y)坐标处的单元格的信息

我实施了A* search算法,可同时搜索所有路线。最后,它输出一个网格,其中每个单元格都有一个数字,表示距离我的位置的距离,以及网格上所有单元的集合。它用O(N)执行,其中N是单元格的数量 - 在我的情况下是600。

我使用AS3实现这一点,不幸的是,我的机器需要30-50毫秒来计算。

这是我的源代码。你能建议我一个更好的方法吗?

package com.gazman.strategy_of_battle_package.map
{
    import flash.geom.Point;

    /**
     * Implementing a path finding algorithm(Similar to A* search only there is no known target) to calculate the shortest path to each cell on the map.
     * Once calculation is complete the information will be available at cellsMap. Each cell is a number representing the
     * number of steps required to get to that location. Enemies and Allies will be represented with negative distance. Also the enemy and Allys
     * coordinations collections are provided. Blocked cells will have the value 0.<br><br>
     * Worth case and best case efficiency is O(N) where N is the number of cells.
     */
    public class MapFilter
    {
        private static const PULL:Vector.<MapFilter> = new Vector.<MapFilter>();
        public var cellsMap:Vector.<Vector.<int>>;
        public var allys:Vector.<Point>;
        public var enemies:Vector.<Point>;
        private var stack:Vector.<MapFilter>;
        private var map:Map;
        private var x:int;
        private var y:int;
        private var count:int;
        private var commander:String;
        private var hash:Object;
        private var filtered:Boolean;

        public function filter(map:Map, myLocation:Point, commander:String):void{
            filtered = true;
            this.commander = commander;
            this.map = map;
            this.x = myLocation.x;
            this.y = myLocation.y;
            init();
            cellsMap[x][y] = 1;
            excecute();
            while(stack.length > 0){
                var length:int = stack.length;
                for(var i:int = 0; i < length; i++){
                    var mapFilter:MapFilter = stack.shift();
                    mapFilter.excecute();
                    PULL.push(mapFilter);
                }
            }
        }

        public function navigateTo(location:Point):Point{
            if(!filtered){
                throw new Error("Must filter before navigating");
            }
            var position:int = Math.abs(cellsMap[location.x][location.y]);
            if(position == 0){
                throw new Error("Target unreachable");
            }
            while(position > 2){
                if(canNavigateTo(position, location.x + 1, location.y)){
                    location.x++;
                }
                else if(canNavigateTo(position, location.x - 1, location.y)){
                    location.x--;
                }
                else if(canNavigateTo(position, location.x, location.y + 1)){
                    location.y++;
                }
                else if(canNavigateTo(position, location.x, location.y - 1)){
                    location.y--;
                }
                position = cellsMap[location.x][location.y];
            }

            return location;
            throw new Error("Unexpected filtering error");
        }

        private function canNavigateTo(position:int, targetX:int, targetY:int):Boolean
        {
            return isInMapRange(targetX, targetY) && cellsMap[targetX][targetY] < position && cellsMap[targetX][targetY] > 0;
        }

        private function excecute():void
        {
            papulate(x + 1, y);
            papulate(x - 1, y);
            papulate(x, y + 1);
            papulate(x, y - 1);
        }

        private function isInMapRange(x:int, y:int):Boolean{
            return x < cellsMap.length && 
                x >= 0 &&
                y < cellsMap[0].length && 
                y >= 0;
        }

        private function papulate(x:int, y:int):void
        {
            if(!isInMapRange(x,y) ||
                cellsMap[x][y] != 0 ||
                hash[x + "," + y] != null || 
                map.isBlocked(x,y)){
                return;
            }

            // we already checked that is not block
            // checking if there units
            if(map.isEmpty(x,y)){
                cellsMap[x][y] = count;
                addTask(x,y);
            }
            else{
                cellsMap[x][y] = -count;
                if(map.isAlly(x,y, commander)){
                    hash[x + "," + y] = true;
                    allys.push(new Point(x,y));
                }
                else {
                    hash[x + "," + y] = true;
                    enemies.push(new Point(x,y));
                }
            }
        }

        private function addTask(x:int, y:int):void
        {
            var mapFilter:MapFilter = PULL.pop();
            if(mapFilter == null){
                mapFilter = new MapFilter();
            }

            mapFilter.commander = commander;
            mapFilter.hash = hash;
            mapFilter.map = map;
            mapFilter.cellsMap = cellsMap;
            mapFilter.allys = allys;
            mapFilter..enemies = enemies;
            mapFilter.stack = stack;
            mapFilter.count = count + 1;
            mapFilter.x = x;
            mapFilter.y = y;
            stack.push(mapFilter);
        }

        private function init():void
        {
            hash = new Object();
            cellsMap = new Vector.<Vector.<int>>();
            for(var i:int = 0; i < map.width;i++){
                cellsMap.push(new Vector.<int>);
                for(var j:int = 0; j < map.height;j++){
                    cellsMap[i].push(0);
                }
            }   
            allys = new Vector.<Point>();
            enemies = new Vector.<Point>();
            stack = new Vector.<MapFilter>();
            count = 2;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您可以使用Floyd Warshall查找每对点之间的最短路径。这将是O(|V|^3),您不必为每个单元运行它,每次转弯只需运行一次。这是一个如此简单的算法我怀疑它在实践中可能比为每个单元运行BFS / Bellman Ford之类的东西更快。