Finding the shortest path between two points in 2D Array

落爺英雄遲暮 提交于 2019-12-24 06:47:21

问题


I have a simple game, I'm trying to get the shortest route between 2 points

The map consists of 2d array matrix: Node[][],

class Node{
   index: {
     x: number,
     y: number
   },
   isAvailable: boolean
}

The algorithm should return the shortest path with respect to node availability.

e.g. Trees are marked as unavailable node.isAvailable = false

I'm stuck on implementing the algorithm for this matrix

I tried to use Dijkstras algorithm from here, but I couldn't figure out how to apply it, I did

const graph = new Dijkstra();

//convert the matrix (2d array) to graph
matrix.map((row) => {
  row.map((node: Node) => {
    let x = node.index.x;
    let y = node.index.y;
    graph.addVertex(x + ":" + y, {x: x, y: y});

  });
});

console.log(graph.shortestPath('0:0', '5:5'));
//the output was ['0:0'] (definitly not the answer)

How can I apply the algorithm on this matrix?

P.S here is my full code


回答1:


I used a method best described as spilling paint at the target:

You mark the target square with 0, then traverse the neighbours and mark them as 1, which represents distance to target, then traverse neighbours of neighbours, etc. Repeat the process until the paint reaches your troll. All that is left for troll to do is just start moving to the squares with lowest potential.

It becomes more fun once you have multiple characters that need to path around each other while everyone is moving.




回答2:


I had to implement the A* algorithm

export class PathFinder {

  grid: Tile[][];
  gridHeight: number;
  gridWidth: number;
  startTile: Tile;
  endTile: Tile;

  /** Array of the already checked tiles. */
  closedList: List<Tile> = new List<Tile>();
  openList: List<Tile> = new List<Tile>();

  constructor(grid: Tile[][], gridHeight: number, gridWidth: number) {

    this.grid = grid;
    this.gridHeight = gridHeight;
    this.gridWidth = gridWidth;
  }

  searchPath(start: Tile, end: Tile): Tile[] {
    this.startTile = start;
    this.endTile = end;

    /** Path validation */
    if (!start.walkable) {
      console.log('The start tile in not walkable, choose different tile than', start.index);
      return [];
    }
    if (!end.walkable) {
      console.log('The end tile in not walkable, choose different tile than', end.index);
      return [];
    }
    /** Start A* Algorithm */

    /** Add the starting tile to the openList */
    this.openList.push(start);
    let currentTile;

    /** While openList is not empty */
    while (this.openList.length) {
      //current node = node for open list with the lowest cost.
      currentTile = this.getTileWithLowestTotal(this.openList);

      //if the currentTile is the endTile, then we can stop searching
      if(JSON.stringify(currentTile.index) === JSON.stringify(end.index)){

        this.startTile.setBackgroundColor("rgba(255, 45, 45, .8)");
        this.endTile.setBackgroundColor("rgba(255, 45, 45, .8)");
        return this.shortestPath();
      }
      else {
        //move the current tile to the closed list and remove it from the open list.
        this.openList.remove(currentTile);
        this.closedList.push(currentTile);

        // //Get all adjacent Tiles
        let adjacentTiles = this.getAdjacentTiles(currentTile);

        for (let adjacentTile of adjacentTiles) {
          //Get tile is not in the open list
          if (!this.openList.contains(adjacentTile)) {
            //Get tile is not in the closed list
            if (!this.closedList.contains(adjacentTile)) {
              //move it to the open list and calculate cost
              this.openList.push(adjacentTile);

              //calculate the cost
              adjacentTile.cost = currentTile.cost + 1;

              //calculate the manhattan distance
              adjacentTile.heuristic = this.manhattanDistance(adjacentTile);

              // calculate the total amount
              adjacentTile.total = adjacentTile.cost + adjacentTile.heuristic;

              currentTile.setBackgroundColor('rgba(0, 181, 93, 0.8)');
            }
          }
        }
      }
    }
  }

  getTileWithLowestTotal(openList: Tile[]): Tile {
    let tileWithLowestTotal = new Tile();
    let lowestTotal: number = 999999999;
    /** Search open tiles and get the tile with the lowest total cost */
    for (let openTile of openList) {
      if (openTile.total <= lowestTotal) {
        //clone lowestTotal
        lowestTotal = openTile.total;
        tileWithLowestTotal = openTile;
      }
    }
    return tileWithLowestTotal;
  }

  getAdjacentTiles(current: Tile): Tile[] {
    let adjacentTiles: Tile[] = [];
    let adjacentTile: Tile;

    //Tile to left
    if (current.index.x - 1 >= 0) {
      adjacentTile = this.grid[current.index.x - 1][current.index.y];
      if (adjacentTile && adjacentTile.walkable) {
        adjacentTiles.push(adjacentTile);
      }
    }

    //Tile to right
    if (current.index.x + 1 < this.gridWidth) {
      adjacentTile = this.grid[current.index.x + 1][current.index.y];
      if (adjacentTile && adjacentTile.walkable) {
        adjacentTiles.push(adjacentTile);
      }
    }

    //Tile to Under
    if (current.index.y + 1 < this.gridHeight) {
      adjacentTile = this.grid[current.index.x][current.index.y + 1];
      if (adjacentTile && adjacentTile.walkable) {
        adjacentTiles.push(adjacentTile);
      }
    }

    //Tile to Above
    if (current.index.y - 1 >= 0) {
      adjacentTile = this.grid[current.index.x][current.index.y - 1];
      if (adjacentTile && adjacentTile.walkable) {
        adjacentTiles.push(adjacentTile);
      }
    }
    /** TODO: Diagonal moves  */
    return adjacentTiles;
  }

  /** Calculate the manhattan distance */
  manhattanDistance(adjacentTile: Tile): number {
    return Math.abs((this.endTile.index.x - adjacentTile.index.x) +
      (this.endTile.index.y - adjacentTile.index.y));
  }

  shortestPath() {
    let startFound: boolean = false;
    let currentTile = this.endTile;
    let pathTiles = [];

    //includes the end tile in the path
    pathTiles.push(this.endTile);
    this.endTile.ball = true;

    while (!startFound) {
      let adjacentTiles = this.getAdjacentTiles(currentTile);

      //check to see what newest current tile.
      for (let adjacentTile of adjacentTiles) {
        //check if it is the start tile
        if (JSON.stringify(adjacentTile.index) === JSON.stringify(this.startTile.index)){
          return pathTiles;
        }

        //it has to be inside the closedList or openList
        if (this.closedList.contains(adjacentTile) || this.openList.contains(adjacentTile)) {
          if (adjacentTile.cost <= currentTile.cost && adjacentTile.cost > 0) {
            //change the current tile.
            currentTile = adjacentTile;
            //Add this adjacentTile to the path list
            pathTiles.push(adjacentTile);
            //highlight way with yellow balls
            adjacentTile.ball = true;
            break;
          }
        }
      }
    }
  }
}


来源:https://stackoverflow.com/questions/40857466/finding-the-shortest-path-between-two-points-in-2d-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!