javascript - A* 六边形网格中的寻路

标签 javascript html canvas path-finding a-star

谁能给我指出一个实现 A* path-finding algorithm 的简单示例在六边形 网格上(在 JS 中)。我已经让它在方形网格上工作,但是我所有让它在六边形网格上工作的尝试都失败了。

这是我的网格的样子:

enter image description here

我使用相同的技术来绘制网格和生成坐标,如 topic 中所示.

这是网格坐标数据以及开始、结束坐标:

        [0, 0] , [0, 1],  [0, 2],
    [1, 0],  [1, 1],  [1, 2],  [1, 3],
 [2, 0],  [2, 1],  [2, 2],  [2, 3],  [2, 4],
    [3, 0],  [3, 1], [3, 2],  [3, 3], 
        [4, 0], [4, 1],  [4, 2]


start_point: [0,2]
end_point: [4.0]

将曼哈顿距离计算更新为:

var dx = pos1[0] - pos0[0];
    var dy = pos1[1] - pos0[1];

    var dist;
    if ( Math.sign(dx) == Math.sign(dy) ){
        dist = Math.abs (dx + dy);
    }else{
        dist = Math.max(Math.abs(dx), Math.abs(dy))
    }

return dist;

我得到这个结果:

enter image description here

还有我计算最短路径的方式:

if (!Array.prototype.remove) {
    Array.prototype.remove = function(from, to) {
        var rest = this.slice((to || from) + 1 || this.length);
        this.length = from < 0 ? this.length + from : from;
        return this.push.apply(this, rest);
    };
}

var astar = {
    init: function(grid) {
        for(var x = 0; x < grid.length; x++) {
            for(var y = 0; y < grid[x].length; y++) {
                grid[x][y].f = 0;
                grid[x][y].g = 0;
                grid[x][y].h = 0;
				//grid[x][y].content = false;
                grid[x][y].visited = false;
                grid[x][y].closed = false;
                grid[x][y].debug = "";
                grid[x][y].parent = null;
				console.log([grid[x][y].coords[0],grid[x][y].coords[1]])
            }
        }
    },
    search: function(grid, start, end, heuristic) {
        this.init(grid);
        heuristic = heuristic || this.manhattan;

        var openList = [];
		
		//// find the start and end points in the grid ////
		start = grid[start.pos[0]][start.pos[1]];
		end =  grid[end.pos[0]][end.pos[1]];
		
		console.log( start, end )
		
        openList.push(start);
		
        while(openList.length > 0) {
			
            // Grab the lowest f(x) to process next
            var lowInd = 0;
            for(var i=0; i<openList.length; i++) {
                if(openList[i].f < openList[lowInd].f) { lowInd = i; }
            }
            var currentNode = openList[lowInd];

            // End case -- result has been found, return the traced path
            if( currentNode == end ) {
                var curr = currentNode;
                var ret = [];
                while(curr.parent) {
                    ret.push(curr);
                    curr = curr.parent;
                }
                return ret.reverse();
            }

            // Normal case -- move currentNode from open to closed, process each of its neighbors
            openList.remove( lowInd );
            currentNode.closed = true;

            var neighbors = this.neighbors(grid, currentNode);
            for(var i=0; i<neighbors.length;i++) {
                var neighbor = neighbors[i];

                if( neighbor.closed || neighbor.content == 2 ) { // not a valid node to process, skip to next neighbor
                    continue;
                }

                // g score is the shortest distance from start to current node, we need to check if
                //   the path we have arrived at this neighbor is the shortest one we have seen yet
                var gScore = currentNode.g + 1; // 1 is the distance from a node to it's neighbor
                var gScoreIsBest = false;

                if(!neighbor.visited) {
                    // This the the first time we have arrived at this node, it must be the best
                    // Also, we need to take the h (heuristic) score since we haven't done so yet
                    gScoreIsBest = true;
                    neighbor.h = heuristic(neighbor.coords, end.coords);
                    neighbor.visited = true;
                    openList.push(neighbor);
                }
                else if(gScore < neighbor.g) {
                    // We have already seen the node, but last time it had a worse g (distance from start)
                    gScoreIsBest = true;
                }

                if(gScoreIsBest) {
                    // Found an optimal (so far) path to this node.  Store info on how we got here and just how good it really is. ////
                    neighbor.parent = currentNode;
                    neighbor.g = gScore;
                    neighbor.f = neighbor.g + neighbor.h;
                    neighbor.debug = "F: " + neighbor.f + "<br />G: " + neighbor.g + "<br />H: " + neighbor.h;
                }
            }
        }

        // No result was found -- empty array signifies failure to find path
        return [];
    },
    manhattan: function(pos0, pos1) { //// heuristics : use manhattan distances  ////
        var dx = pos1[0] - pos0[0];
        var dy = pos1[1] - pos0[1];
		
        return  Math.abs (dx + dy);
    },
    neighbors: function(grid, node) {
        var ret = [];
        var x = node.coords[0];
        var y = node.coords[1];
		
        if(grid[x-1] && grid[x-1][y] ) {
            ret.push(grid[x-1][y]);
        }
        if( grid[x+1] && grid[x+1][y] ) {
            ret.push(grid[x+1][y]);
        }
        if( grid[x][y-1] && grid[x][y-1] ) {
            ret.push(grid[x][y-1]);
        }
        if( grid[x][y+1] && grid[x][y+1] ) {
            ret.push(grid[x][y+1]);
        }
        return ret;
    }
};

尝试在 Internet 上四处寻找一些好的示例或文档,但找不到真正有用的东西。

最佳答案

问题在于您的 neighbors 方法:虽然六边形有六个邻居 (6),但您只将四 (4) 个推到 ret 上。下图突出了这个问题。浅灰色的十六进制表示当前节点(即 neighbor)。绿色六边形被添加到 ret,但红色六边形没有。

IncludedOrNotIncluded

要解决此问题,请将以下两 (2) 个案例添加到您的 neighbors 方法中:

    if( grid[x+1][y-1] && grid[x+1][y-1] ) {
        ret.push(grid[x][y-1]);
    }
    if( grid[x-1][y+1] && grid[x-1][y+1] ) {
        ret.push(grid[x][y+1]);
    }

关于您更新的 manhattan 方法: 它是正确的。下图使用颜色来显示从当前中心十六进制(红色 [0:0] 处)到其他所有十六进制的距离。例如,橙色六边形瓷砖是红色的一 (1) 步。黄色距离红色两 (2) 步。等等。

Distance hex map

您可能会注意到这种模式:如果 x 坐标和 y 坐标具有相同的符号,则距离等于最大坐标的大小。否则,距离是它们的绝对值之和。这正是您在 updated manhattan 方法中计算距离的方式。所以你在那里很好。

关于一般的启发式搜索:这里有一个简单的方法来检查次优解决方案是启发式实现中的错误造成的,还是算法实现中的错误造成的。只需对所有值使用启发式值零 (0),即使用普通启发式。如果在使用普通启发式算法时路径不是最优的,那么您就知道这不是一个启发式问题——这是一个算法问题。

关于javascript - A* 六边形网格中的寻路,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38015645/

相关文章:

javascript - 如何在 HTML5 Canvas 下保存 iframe 的图像?

html - 未使用身份验证 header 发送脚本请求

HTML5 Canvas 和抗锯齿

javascript - 如何在纸上缩放

javascript - .load 在 IE8 中不工作

javascript - 当特定表单的 Ajax 完成时执行函数

javascript - 比较日期时无法使 getDate() 工作

php - 如何使用 PHPMailer 发送包含 CSS 的 HTML 邮件?

javascript - 如何使用 JayData 为 indexedDB 中的表创建索引

javascript - 使用 HTML 5 Canvas 自动滚动