Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   Не сайты (http://www.flasher.ru/forum/forumdisplay.php?f=82)
-   -   Поиск пути (http://www.flasher.ru/forum/showthread.php?t=113645)

Волгоградец 04.07.2008 16:09

Поиск пути
 
Вложений: 1
Вот придумал алгоритм поиска пути - чистая математика. Координаты препятствий берутся из XML. Просьба посмотреть на предмет глюков и недочетов (может я чего не увидел). Когда отполирую код - выложу, может кому пригодится...

Punk T-34 04.07.2008 17:21

Пригодится! Уже пригодится! :)
По-мучал его изрядно. С виду никаких багов. Только при первом клике ролик обращается к локалхосту. Это так надо? Что это?

Psycho Tiger 04.07.2008 17:39

Уряяя, я сделаю свою рпгшку :D
Зачет, продолжай работать.)

VovkaMorkovka 05.07.2008 22:49

То, что ты сделал, напоминает метод потенциалов попробуй сделать вогнутое препятствие, например в форме буквы П и тебя ждут сюрпризы.
Короче, зачет, но работать есть над чем

Badim 07.07.2008 15:56

метод, реализация А*.
Код:

/*
===============================================================================
= PATHFINDING FUNCTION
=------------------------------------------------------------------------------
= Version: 1.1.4
= Last changes: jul 15 (1.0.0) - first version
=              aug 09 (1.0.1) - several speed improvements, thanks tonypa
=              aug 10 (1.0.2) - even more speed improvements by tonypa (again)
=              aug 31 (1.0.3) - return NULL if error (instead of error string)
=              aug 31 (1.1.3) - added cornering option. thanks for LAlex for
=                                his suggestions
=          2004 may 28 (1.1.4) - fixed "undefined != 0" error on MX 2004 when
=                                compiling as flash 7. Thanks Inkog for finding
=                                the error and the solution
=------------------------------------------------------------------------------
= This function finds the path between two points (the START and the END point)
= on a given map, taken into account walls/obstacles and terrain costs.
=
= It uses an A* ("a star") algorithm with heuristic approximation for a faster
= result. Much of this function is basic on theory learnt from this language
= independent tutorial:
= http://www.policyalmanac.org/games/aStarTutorial.htm
=------------------------------------------------------------------------------
= How to use:
=
= my_path_array = findPath (map, start_y, start_x, end_y, end_x)
=
= Parameters:
=  map = bidimensional array with rows and columns. Each cell contains a value
=        of 0 (wall) or 1+ (terrain - the higher, the more expensive to ride)
===============================================================================
*/
findPath = function(map, startY, startX, endY, endX) {
        if (startY == undefined || startX == undefined) return null; // Error: no starting point
        if (endY == undefined || endX == undefined) return null; // Error: no ending point

        // Caches dimensions
          var mapH = map.length;
          var mapW = map[0].length;
       
        // New status arrays
        var mapStatus = [];
        for (var i=0; i<mapH; i++){
                mapStatus[i] = [];
                for (var j=0; j<mapW; j++){
                        mapStatus[i][j]={};
                }
        }
        // Finds the way given a certain path

  // Constants/configuration - change here as needed! --------------------------------
  var HV_COST = 10; // "Movement cost" for horizontal/vertical moves
  var D_COST = 14; // "Movement cost" for diagonal moves
  var ALLOW_DIAGONAL = false; // If diagonal movements are allowed at all
  var ALLOW_DIAGONAL_CORNERING = false; // If diagonal movements over corners are allowed

  // Complimentary functions =========================================================
   
  isOpen = function (y, x) {
    // Return TRUE if the point is on the open list, false if otherwise
    return mapStatus[y][x].open;
  };
  isClosed = function (y, x) {
    // Return TRUE if the point is on the closed list, false if otherwise
    return mapStatus[y][x].closed;
  };
  nearerSquare = function() {
    // Returns the square with a lower movementCost + heuristic distance
    // from the open list
    var minimum = 999999;
    var indexFound = 0;
    var thisF = undefined;
    var thisSquare = undefined;
    var i = openList.length;
    // Finds lowest
    while (i-->0) {
      thisSquare = mapStatus[openList[i][0]][openList[i][1]];
      thisF = thisSquare.heuristic + thisSquare.movementCost;
      if (thisF <= minimum) {
        minimum = thisF;
        indexFound = i;
      }
    }
    // Returns lowest
    return indexFound;
  };
  closeSquare = function(y, x) {
    // Drop from the open list
    var len = openList.length;
    for (var i=0; i < len; i++) {
      if (openList[i][0] == y) {
        if (openList[i][1] == x) {
          openList.splice(i, 1);
          break;
        }
      }
    }
    // Closes an open square
    mapStatus[y][x].open = false;
    mapStatus[y][x].closed = true;
  };
  openSquare = function(y, x, parent, movementCost, heuristic, replacing) {
    // Opens a square
    if (!replacing) {
      openList.push([y,x]);
      mapStatus[y][x] = {heuristic:heuristic, open:true, closed:false};
    }
    mapStatus[y][x].parent = parent;
    mapStatus[y][x].movementCost = movementCost;
  };

          // Ok, now go back to our regular schedule. Find the path! -------------------------



        // Now really starts
        var openList = new Array();
        openSquare (startY, startX, undefined, 0);
 
        // Loops until there's no other way to go OR found the exit
        while (openList.length > 0 && !isClosed(endY, endX)) {
                // Browse through open squares
                var i = nearerSquare();
               
                var nowY = openList[i][0]/1;
                var nowX = openList[i][1]/1;
               
                // Closes current square as it has done its purpose...
                closeSquare (nowY, nowX);
                // Opens all nearby squares, ONLY if:
                //trace('__now:['+nowX+","+nowY+"]");
                for (var j=nowY-1; j<(nowY+2); j++) {
                for (var k=nowX-1; k<(nowX+2); k++) {
                        if (j >= 0 && j < mapH && k >= 0 && k < mapW && map[j][k] != 0) {
                        //if (j >= 0 && j < mapH && k >= 0 && k < mapW && !(j==nowY && k==nowX) && (ALLOW_DIAGONAL || j==nowY || k==nowX) && (ALLOW_DIAGONAL_CORNERING || j==nowY || k==nowX || (map[j][nowX] != 0 && map[nowY][k] != 0))) {
                        // If not outside the boundaries or at the same point or a diagonal (if disabled) or a diagonal (with a wall next to it)...
                        // And if not a wall...
                                        if (!isClosed(j,k)) {
                                                // And if not closed... THEN open.
                                                //var py=mapStatus[nowY][nowX].parent[0];
                                                //var px=mapStatus[nowY][nowX].parent[1];
                                                //var pcost=mapStatus[nowY][nowX].movementCost;
                                                //if(py!=undefined){pcost=mapStatus[py][px].movementCost;};
                                                var movementCost = mapStatus[nowY][nowX].movementCost + ((j==nowY || k==nowX ? HV_COST : D_COST) * map[j][k]);
                                                //trace("___map("+k+","+j+")="+map[j][k]+","+movementCost+'['+mapStatus[nowY][nowX].movementCost+',('+nowX+','+nowY+')]');
                                                //gfx_mc.sur_map[k][j]=movementCost;
                                                //trace('('+k+','+j+') from ['+nowX+","+nowY+"]");
                                                //gfx_mc.sur_map_type[k][j]=100;
                                                        if (isOpen(j,k)) {
                                                                // Already opened: check if it's ok to re-open (cheaper)
                                                                if (movementCost < mapStatus[j][k].movementCost) {
                                                                  // Cheaper: simply replaces with new cost and parent.
                                                                  //trace('__replace:('+k+','+j+') for ('+nowX+','+nowY+")");
                                                                  openSquare (j, k, [nowY, nowX], movementCost, undefined, true); // heuristic not passed: faster, not needed 'cause it's already set
                                                                }
                                                        } else {
                                                                // Empty: open.
                                                                var heuristic = (Math.abs (j - endY) + Math.abs (k - endX)) * 10;
                                                                openSquare (j, k, [nowY, nowX], movementCost, heuristic, false);
                                                        }
                                        } else {
                                                  // Already closed, ignore.
                                        }
                }
              }
        }
}
        //Ended
        var pFound = isClosed(endY, endX); // Was the path found?
        // Clean up temporary functions
        //delete isOpen;
        //delete isClosed;
        //delete nearerSquare;
        //delete closeSquare;
        //delete openSquare;
  if (pFound) {
    // Ended with path found; generates return path
    var returnPath = [];
    var nowY = endY;
    var nowX = endX;
        var movCost=mapStatus[nowY][nowX].movementCost;
    while ((nowY != startY || nowX != startX)) {
      returnPath.push([nowX,nowY,movCost]);
      var newY = mapStatus[nowY][nowX].parent[0];
      var newX = mapStatus[nowY][nowX].parent[1];
      nowY = newY;
      nowX = newX;
          movCost=mapStatus[nowY][nowX].movementCost;
    }
    returnPath.push([startX,startY,0]);
        var path_xy=[];
        for(var i=returnPath.length-1;i>-1;i--){
                path_xy.push(returnPath[i]);
        }
        //trace("____path:"+ path_xy.join('|'));
    return path_xy;
  } else {
    // Ended with 0 open squares; ran out of squares, path NOT found
    return null;
  }
};
//ASSetPropFlags(_global, "findPath", 1, 0);


TERRORist 07.07.2008 23:08

ммм

Напоминает волновой алгоритм, я баловался с ним как то, с вогнутостями проблем он не имеет.

Вобще, за идею 4, за реализацию 3, а за выбор технологии вобще 0. Потому что в данном случае рационален метод точек видимости, тогда путь занимал бы до 5 точек.

З.Ы сорри смотрел на скрипт выше когда писал))) за технологию - 5, спасибо ^_^

lexa2000lexa 08.07.2008 16:02

Вложений: 1
Не знаю как это у меня получилось . но после энной манипуляции с шариком шарик стал перемешаться только внутри фигур :)
картинку прикрепил.

TERRORist 09.07.2008 20:22

Вложений: 1
У меня только сегодня дошли руки ддописать, что в алгоритме серьезная ошибка - он не учитывает длину пути, а считает только по количеству пройденных узлов. Идти он должен (до квадратика) по красной линии (потому что это кратчайший путь) а идет он по фиолетовой. Баг :)

а еще, три тысячи строк кода - это ужасно.

И еще, хотелось бы увидеть то же самое но с 100 объектами :)

NoCD 09.07.2008 21:04

Есть хорошая статья по поиску пути http://www.delphigfx.narod.ru/doc/path.htm

Волгоградец 10.07.2008 15:24

TERRORist, ага, это баг - исправлю. Спасибо, что подсказал.
Насчет кода: с чего ты взял, что там 3000 строк? Я его, по-моему, не выкладывал... Там около 700 строчек (считая комментарии, отступы);

TERRORist 10.07.2008 23:54

догадался ^_^

Котяра 20.08.2008 13:02

Вложений: 1
во вложении Вложение 20229тестовая флэшка по Badim'овскому алгоритму - переделан в класс Astra
Собственно сам класс (AS2)
Код:

// Поиск кратчайшего пути по алгоритму A*

class Astar
{       

        var map:Array;
        var mapStatus:Array;
        var openList:Array;
               
        var mapH:Number;
        var mapW:Number;
       
        // подсчет времени выполнения
        var startFind:Number;
        var stopFind:Number;
       
        // Constants/configuration - change here as needed! --------------------------------
        var HV_COST = 10; // "Movement cost" for horizontal/vertical moves
        var D_COST = 14; // "Movement cost" for diagonal moves
       
        var log='';
       
        function Astar(_map)
        {
                map = _map;
        }
       
                 
                 
        function  isOpen(y, x) {
                        // Return TRUE if the point is on the open list, false if otherwise
                        return mapStatus[y][x].open;
                  }
       
        function isClosed(y, x) {
                        // Return TRUE if the point is on the closed list, false if otherwise
                        return mapStatus[y][x].closed;
                  }
                 
        function nearerSquare() {
                        // Returns the square with a lower movementCost + heuristic distance
                        // from the open list
                        var minimum = 999999;
                        var indexFound = 0;
                        var thisF = undefined;
                        var thisSquare = undefined;
                        var i = openList.length;
                        // Finds lowest
                        while (i-->0) {
                          thisSquare = mapStatus[openList[i][0]][openList[i][1]];
                          thisF = thisSquare.heuristic + thisSquare.movementCost;
                          if (thisF <= minimum) {
                                minimum = thisF;
                                indexFound = i;
                          }
                        }
                        // Returns lowest
                        return indexFound;
                  }
                 
                 
        function  closeSquare(y, x) {
                        // Drop from the open list
                        var len = openList.length;
                        for (var i=0; i < len; i++) {
                          if (openList[i][0] == y) {
                                if (openList[i][1] == x) {
                                  openList.splice(i, 1);
                                  break;
                                }
                          }
                        }
                        // Closes an open square
                        mapStatus[y][x].open = false;
                        mapStatus[y][x].closed = true;
                  }
                 
                 
        function  openSquare(y, x, parent, movementCost, heuristic, replacing) {
                        // Opens a square
                        if (!replacing) {
                          openList.push([y,x]);
                          mapStatus[y][x] = {heuristic:heuristic, open:true, closed:false};
                        }
                        mapStatus[y][x].parent = parent;
                        mapStatus[y][x].movementCost = movementCost;
                  }
                 
                 
                 
       
        function findPath( startX, startY, endX, endY) {
                startFind = new Date().getTime().valueOf();
                       
                if (startY == undefined || startX == undefined) return null; // Error: no starting point
                if (endY == undefined || endX == undefined) return null; // Error: no ending point
               
                        // Error: Closed start/end point
               
                if (map[startY][startX]==0 || map[endY][endX]==0)
                {
                        log = "Closed start/end point: " + map[startY][startX] + "," + map[endY][endX];
                        trace(log);
                        return null;
               
                }
               
       

               
               
                        // Caches dimensions
                        mapH = map.length;
                        mapW = map[0].length;
                       
                        //trace (map);
                        // New status arrays
                        mapStatus = [];
                        for (var i=0; i<mapH; i++){
                                mapStatus[i] = [];
                                for (var j=0; j<mapW; j++){
                                        mapStatus[i][j]={};
                                }
                        }
                        // Finds the way given a certain path
                        // Ok, now go back to our regular schedule. Find the path!
                       
                        // Now really starts
                        openList = new Array();
                        openSquare (startY, startX, undefined, 0);
                 
                        // Loops until there's no other way to go OR found the exit
                        while (openList.length > 0 && !isClosed(endY, endX)) {
                                // Browse through open squares
                                var i = nearerSquare();
                               
                                var nowY = openList[i][0]/1;
                                var nowX = openList[i][1]/1;
                               
                                // Closes current square as it has done its purpose...
                                closeSquare (nowY, nowX);
                                // Opens all nearby squares, ONLY if:
                                //trace('__now:['+nowX+","+nowY+"]");
                                for (var j=nowY-1; j<(nowY+2); j++) {
                                for (var k=nowX-1; k<(nowX+2); k++) {
                                        if (j >= 0 && j < mapH && k >= 0 && k < mapW && map[j][k] != 0)
                                        {

                                        // If not outside the boundaries or at the same point or a diagonal (if disabled) or a diagonal (with a wall next to it)...
                                        // And if not a wall...
                                                        if (!isClosed(j,k)) {
                                                                // And if not closed... THEN open.

                                                                var movementCost = mapStatus[nowY][nowX].movementCost + ((j==nowY || k==nowX ? HV_COST : D_COST) * map[j][k]);
                                                                        if (isOpen(j,k)) {
                                                                                // Already opened: check if it's ok to re-open (cheaper)
                                                                                if (movementCost < mapStatus[j][k].movementCost) {
                                                                                  // Cheaper: simply replaces with new cost and parent.
                                                                                  //trace('__replace:('+k+','+j+') for ('+nowX+','+nowY+")");
                                                                                  openSquare (j, k, [nowY, nowX], movementCost, undefined, true); // heuristic not passed: faster, not needed 'cause it's already set
                                                                                }
                                                                        }
                                                                        else
                                                                        {
                                                                                // Empty: open.
                                                                                var heuristic = (Math.abs (j - endY) + Math.abs (k - endX)) * 10;
                                                                                openSquare (j, k, [nowY, nowX], movementCost, heuristic, false);
                                                                        }
                                                        } else {
                                                                // Already closed, ignore.
                                                        }
                                        }
                                }
                        }
                }
                        //Ended
                        var pFound = isClosed(endY, endX); // Was the path found?
                  if (pFound) {
                        // Ended with path found; generates return path
                        var returnPath = [];
                        var nowY = endY;
                        var nowX = endX;
                        var movCost=mapStatus[nowY][nowX].movementCost;
                        while ((nowY != startY || nowX != startX)) {
                          returnPath.push([nowX,nowY,movCost]);
                          var newY = mapStatus[nowY][nowX].parent[0];
                          var newX = mapStatus[nowY][nowX].parent[1];
                          nowY = newY;
                          nowX = newX;
                          movCost=mapStatus[nowY][nowX].movementCost;
                        }
                        returnPath.push([startX,startY,0]);
                        var path_xy=[];
                        for(var i=returnPath.length-1;i>-1;i--){
                                path_xy.push(returnPath[i]);
                        }
                        stopFind = new Date().getTime().valueOf();
                        log="finding time:" + (stopFind - startFind)+"\npath:" + path_xy.join('|');
                        trace (log);
                        return path_xy;
                  }
                  else
                  {
                        log="Ended with 0 open squares; ran out of squares, path NOT found";
                        trace (log);
                        return null;
                  }
                }

}


MrPoma 20.08.2008 14:32

А че ему передавать надо?

Котяра 20.08.2008 17:00

при инициализации
Код:

astra = new Astra (map)
map[y][x] - двумерный массив 0,1 - 0 -стена, 1 и более проходимость
затем вызывается метод поиска пути возвращающий двумерный массив точек пути
Код:

function findPath( startX, startY, endX, endY)
в тестовом примере все расписано в инклудном файле

TERRORist 20.08.2008 20:28

Во первых таймер некорректно работает, выбирать new Date для нахождения времени глупо...

во вторых, он работает ужасно медленно, 250 мсек для маленького поля 100*100 при переходе наискосок...

Котяра 21.08.2008 12:09

Цитата:

Сообщение от TERRORist (Сообщение 759377)
Во первых таймер некорректно работает, выбирать new Date для нахождения времени глупо...

во вторых, он работает ужасно медленно, 250 мсек для маленького поля 100*100 при переходе наискосок...

А как по другому выбрать точное время работы скрипта? Подскажи - очень нужно.
Насчет медленности.. может быть - требуется оптимизация КОДА, но сам алгоритм один самых быстрых и точных для нахождения пути. можно поколдовать со значениями эвристики, и стоимости диагоналей (у меня в тесте диагональ=14 дороже прямых =10, поэтому алгоритм все равно выискивает пути по прямой, и лишь потом выдает вариант с диагональю, как самый дешевый)

TERRORist 21.08.2008 22:03

getTimer().. Для двойки)

Оптимизировать можно, но сначала лучше на тройке писать...

Яски 21.08.2008 22:22

getTimer() для тройки - быстрее new Date() в 10 раз.

Котяра 22.08.2008 11:51

Цитата:

Сообщение от TERRORist (Сообщение 759567)
getTimer().. Для двойки)

Ок) Я почему-то думал это Deprecated функция
Цитата:

Сообщение от TERRORist (Сообщение 759567)
Оптимизировать можно, но сначала лучше на тройке писать...

Дело в том что он написан для существующего и развивающегося AS2 проекта, переписывание на AS3 только предстоит.

KOHMAR 16.03.2009 22:36

Люди а у кого то есть реализация *А на AS3 ?

Котяра 17.03.2009 00:19

Вот от автора замечательной книги по созданию игр.

Avrilka 03.07.2010 18:26

Badim. Сяпы ОГРОООООООООООООМНОЕ! МЕНЯ СПАСЛО!

CrazyFlasher 05.07.2010 11:57

тема!


Часовой пояс GMT +4, время: 18:48.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.