六角形グリッド(JS内)に A *パスファインディングアルゴリズム を実装する簡単な例を誰かに教えてもらえますか?正方形のグリッドで機能するようにしましたが、六角形のグリッドで機能させる試みはすべて失敗しました。
これは私のグリッドがどのように見えるかです:
これに見られるように、グリッドの描画と座標の生成の両方に同じ手法を使用しています トピック 。
グリッド座標データと開始座標、終了座標は次のとおりです。
[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;
私はこの結果を得る:
また、最短経路を計算する方法:
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;
}
};
インターネット上でいくつかの良い例やドキュメントを探してみましたが、実際には何も役に立ちませんでした。
問題はneighbors
メソッドにあります。六角形には6つの近傍(6)がありますが、ret
にプッシュするのは4つだけです。次の図は、この問題を示しています。薄い灰色の16進数は、現在のノード(つまり、neighbor
)を表します。緑の六角形はret
に追加されますが、赤の六角形は追加されません。
これを修正するには、次の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つの動きです。等々。
次のパターンに気付くかもしれません。x座標とy座標が同じ符号を共有している場合、距離は最大座標の大きさに等しくなります。それ以外の場合、距離はそれらの絶対値の合計です。これは、updatedmanhattan
メソッドで距離を計算した方法とまったく同じです。だからあなたはそこに良いです。
ヒューリスティック検索全般について:最適ではないソリューションがヒューリスティック実装のバグの結果であるか、それともバグが原因であるかを確認する簡単な方法は次のとおりです。アルゴリズムの実装で。すべての値にヒューリスティック値ゼロ(0)を使用するだけです。つまり、些細なヒューリスティックを使用します。些細なヒューリスティックを使用しているときにパスが最適でない場合は、ヒューリスティックの問題ではないことがわかります---アルゴリズムの問題です。
ここで誰かがすでに述べたように、私がグリッドを生成する方法と座標も正しくありませんでした。
Amit Patelの実装をもう一度読んだ guide そして彼の方法を使ってグリッドと座標を含む座標系を生成しました。変換。
generate: function(){
var n_hex = null;
var row = 0, col = 0;
for (var q = -this.grid_r; q <= this.grid_r; q++) {
var r1 = Math.max(-this.grid_r, -q - this.grid_r);
var r2 = Math.min(this.grid_r, -q + this.grid_r);
col = q + this.grid_r;
this.hexes[ col ] = [];
for (var r = r1; r <= r2; r++) {
row = r - r1;
n_hex = new Hex( [q, r], [col, row], this.layout );
this.hexes[ col ][ row ] = n_hex;
}
}
},
キューブ座標を使い始めたとき、a *パスファインディングアルゴリズムで変更する必要があるのは、距離の計算だけでした。
return Math.max(Math.abs(a.x - b.x), Math.abs(a.y - b.y), Math.abs(a.z - b.z))
現在、経路探索は「先のとがった」レイアウトと「平らな」レイアウトの両方で機能しています。
「古典的な」経路探索アルゴリズムは次のように機能します。
出口が見つかった場合:
記憶されているすべてのセルは、結果パスを(逆の順序で)構築します。
Cheerz
ヘンネス
これは解決された問題であり、それを裏付ける多くの文献があります。私が知っている最高のリソースはRedBlob Gamesです: https://www.redblobgames.com/grids/hexagons/ 。
簡単に言うと、最も可能性の高い理由は、間違った座標系を選択したことです。 A *アルゴリズムを実装するキューブ座標系の使用は非常に簡単です。上記のリンクのライブデモをご覧ください。
本当に他のシステムを使用したい場合は、必要に応じて変換します。