简体   繁体   English

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

[英]Algorithms find shortest path to all cells on grid

I have a grid [40 x 15] with 2 to 16 units on it, and unknown amount of obstacles. 我有一个网格[40 x 15],上面有2到16个单位,以及未知数量的障碍物。
How to find the shortest path to all the units from my unit location. 如何从我的单位位置找到所有单位的最短路径。

I have two helper methods that we can consider as O(1) 我有两个辅助方法,我们可以考虑为O(1)

  • getMyLocation() - return the (x, y) coordinates of my location on the grid getMyLocation() - 返回网格上我的位置的(x,y)坐标
  • investigateCell(x, y) - return information about cell at (x,y) coordinates investigCell(x,y) - 返回有关(x,y)坐标处的单元格的信息

I implemented A* search algorithm, that search simultaneously to all the directions. 我实现了A *搜索算法,同时搜索所有方向。 At the end it output a grid where each cell have a number representing the distance from my location, and collection of all the units on the grid. 最后,它输出一个网格,其中每个单元格都有一个数字,表示距离我的位置的距离,以及网格上所有单元的集合。 It performs with O(N) where N is the number of cells - 600 in my case. 它用O(N)执行,其中N是单元格数 - 在我的情况下是600。

I implement this using AS3, unfortunately it takes my machine 30 - 50 milliseconds to calculate. 我使用AS3实现这一点,不幸的是,我的机器需要30-50毫秒来计算。

Here is my source code. 这是我的源代码。 Can you suggest me a better way? 你能建议我一个更好的方法吗?

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;
        }
    }
}

You can use Floyd Warshall to find the shortest path between every pair of points. 您可以使用Floyd Warshall找到每对点之间的最短路径。 This would be O(|V|^3) and you would not have to run it for each unit, just once on each turn. 这将是O(|V|^3) ,你不必为每个单位运行它,每回合只运行一次。 It's such a simple algorithm I suspect it might be faster in practice than running something like BFS / Bellman Ford for each unit. 这是一个如此简单的算法,我怀疑它在实践中可能比为每个单元运行像BFS / Bellman Ford这样的东西更快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM