Подтвердить что ты не робот

A * Отслеживание в гексагональной сетке

Может ли кто-нибудь указать мне на простой пример, который реализует алгоритм поиска путей * в сетке гексагональной в JS). Я заставил его работать над квадратной сеткой, однако все мои попытки заставить его работать на шестиугольной сетке потерпели неудачу.

Вот как выглядит моя сетка:

введите описание изображения здесь

Я использую ту же технику, чтобы как рисовать сетку, так и генерировать координаты, как показано в этой теме.

Здесь данные сетчатых коордов вместе с начальными, конечными коордами:

        [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 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;
    }
};
4b9b3361

Ответ 1

Проблема заключается в вашем методе neighbors: хотя шестиугольник имеет шесть соседей (6), вы просто нажимаете четыре (4) на ret. Следующий вопрос освещает эту проблему. Светло-серый гекс представляет ток node (т.е. 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) движения от красного. И так далее.

Экранная карта расстояния

Вы можете заметить шаблон: если x- и y-координаты имеют один и тот же знак, расстояние равно величине самой большой координаты. В противном случае расстояние представляет собой сумму их абсолютных значений. Это точно так, как вы рассчитали расстояние в обновленном manhattan методе. Так что ты там хороший.

Что касается эвристического поиска в целом: Вот простой способ проверить, является ли субоптимальное решение результатом ошибки в эвристической реализации или из-за ошибки в реализации алгоритма. Просто используйте эвристическое значение ноль (0) для всех значений, т.е. Используйте тривиальную эвристику. Если при использовании тривиальной эвристики путь не является оптимальным, то вы знаете, что это не эвристическая проблема - это проблема алгоритма.

Ответ 2

Как уже упоминалось кем-то здесь, способ создания сетки, а также координаты были неправильными.

У меня есть еще один вариант реализации 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 * pathfinding, было вычисление расстояния:

return Math.max(Math.abs(a.x - b.x), Math.abs(a.y - b.y), Math.abs(a.z - b.z))

теперь поиск путей работает как на "заостренном", так и на "плоском" макете:

введите описание изображения здесь

Ответ 3

"Классический" алгоритм поиска пути работает следующим образом:

  • Инициализировать все ячейки с нулем.
  • Начните с начальной точки и отметьте ее точкой с номером 1.
  • Начало цикла с n = 1:
  • Возьмите все ячейки с номером n и отметьте все соседние ячейки, которые содержат нуль, с номером (n + 1). Если какой-либо из этих смежных ячеек является выходом, оставьте цикл. Если не найдена соседняя ячейка с нулевым нулем, нет пути для выхода.
  • Инкремент n и goto loop

Если выход найден, то:

  • Запустить цикл при выходе:
  • Найдите соседнюю ячейку с номером n и запомните эту ячейку.
  • Сокращение n и goto loop

Все запоминаемые ячейки формируют путь результата (в обратном порядке).

Cheerz

Hennes