防止与新路径发生碰撞

Posted

技术标签:

【中文标题】防止与新路径发生碰撞【英文标题】:Prevent collisions with new paths 【发布时间】:2018-01-31 00:43:58 【问题描述】:

我正在构建一个通过矩阵 (nxn) 运行的程序,以避免与某些障碍物发生碰撞。我在实现适用于所有可能的碰撞情况的通用算法时遇到问题,最终目标是遍历矩阵的所有点。

我构建的算法是循环的,无法完成矩阵。

注意:红色方块可以向任意方向移动(水平、垂直和对角线移动),但一次只能移动一个单元格(正方形)。

var WALL = 0;
var started = false;
var gridSize = 20;

class Agent 
  constructor(x, y, charge, cap, distance) 
    this.x = x;
    this.y = y;
    this.charge = charge;
    this.cap = cap;
    this.distance = distance;
  


$(function() 
  var $grid = $("#search_grid");

  var opts = 
    gridSize: 20
  ;

  var grid = new GraphSearch($grid, opts);

  //Initializes the agent
  $("#btnInit").click(function() 
    if (!started) 
      var agent = new Agent(0, 0, 100, 50, 0);
      agent.initialize();
      started = true;
    

  );
);

//Initializes the matrix
function GraphSearch($graph, options) 
  this.$graph = $graph;
  this.opts = options;
  this.initialize();


//Initializes the matrix
GraphSearch.prototype.initialize = function() 
  this.grid = [];
  $graph = this.$graph;
  $graph.empty();

  var cellWidth = ($graph.width() / this.opts.gridSize) - 2,
    cellHeight = ($graph.height() / this.opts.gridSize) - 2,
    lineHeight = (this.opts.gridSize >= 30 ? "9.px" : ($graph.height() / this.opts.gridSize) - 10 + "px"),
    fontSize = (this.opts.gridSize >= 30 ? "10px" : "20px");
  $cellTemplate = $("<span />").addClass("grid_item").width(cellWidth).height(cellHeight).css("line-height", lineHeight).css("font-size", fontSize);

  for (var x = 0; x < this.opts.gridSize; x++) 
    var $row = $("<div class='row' />");
    for (var y = 0; y < this.opts.gridSize; y++) 
      var id = "cell_" + x + "_" + y,
        $cell = $cellTemplate.clone();
      $cell.attr("id", id).attr("x", x).attr("y", y);
      $row.append($cell);

      var isWall = addWall(x, y, this.opts.gridSize);
      if (isWall === 1) 
        $cell.addClass("wall");
       else 
        $cell.addClass('weight1');
      
    
    $graph.append($row);

    //Fix for *** snippet
    if ($(window).width() < 700) 
      $("#search_grid").css("width", "320px");
      $("#main").css("width", "38%");
     else 
      $("#search_grid").css("width", "300px");
      $("#main").css("width", "20%");
    

  
;

//Where will be wall in the matrix
addWall = function(x, y, size) 
  var limitPointLeftUp = [2, 3];
  var limitPointRightUp = [2, size - 4];

  var limitPointLeftDown = [size - 4, 2];
  var limitPointRightDown = [size - 4, size - 4];

  if ((x == 2 && y == 2) || (x == 2 && y == size - 3)) 
    return 1;
  

  if ((x == size - 3 && y == 2) || (x == size - 3 && y == size - 3)) 
    return 1;
  

  if (x >= 2 && (y == 3 && x >= limitPointLeftUp[0] && x <= limitPointLeftDown[0] + 1)) 
    return 1;
  

  if (x >= 2 && (y == size - 4 && x >= limitPointRightUp[0] && x <= limitPointRightDown[0] + 1)) 
    return 1;
  

  if ((x == 1 && y == 5) || (x == 9 && y == 17) || (x == 6 && y == 0) || (x == 9 && y == 7) || (x == 15 && y == 0) || (x == 15 && y == 2) || (x == 18 && y == 15)) 
    return 1;
  


//Initializes the agent
Agent.prototype.initialize = function() 
  var agent = this;
  var lastDir = "right";
  var tryTo = "";
  var trying = false;

  var right = true;
  var up = false;
  var down = false;
  var left = false;
  var timerId = 0;

  //Simulates agent movement [Here is my problem]
  timerId = setInterval(function() 
    RemoveAgent();
    var cell = $("#search_grid .row .grid_item[x=" + agent.x + "][y=" + agent.y + "]");
    cell.css("background-color", "#e2e2e2");
    cell.addClass("agent");
    //start direction: right
    if (right) 
      lastDir = "right";
      if (tryTo == "down" && trying) 
        if (EmptySqm(agent.x + 1, agent.y)) 
          trying = false;
          right = false;
          down = true;
          agent.x++;
        
       else if (tryTo == "up" && trying) 
        if (EmptySqm(agent.x - 1, agent.y)) 
          trying = false;
          right = false;
          up = true;
          agent.x--;
        
      

      if (right) 
        //check if is valid sqm
        if (ValidSqm(agent.x, agent.y + 1)) 
          //go right if empty
          if (EmptySqm(agent.x, agent.y + 1)) 
            agent.y++;
           else 
            right = false;
            //check up sqm
            if (EmptySqm(agent.x - 1, agent.y)) 
              up = true;
              trying = true;
            
            //check down 
            else if (EmptySqm(agent.x + 1, agent.y)) 
              down = true;
              trying = true;
            
          
         else 
          agent.x++;
          right = false;
          left = true;
        
      
      //left direction
     else if (left) 
      lastDir = "left";
      if (tryTo == "down" && trying) 
        if (EmptySqm(agent.x + 1, agent.y)) 
          trying = false;
          left = false;
          down = true;
          agent.x++;
        
       else if (tryTo == "up" && trying) 
        if (EmptySqm(agent.x - 1, agent.y)) 
          trying = false;
          left = false;
          up = true;
          agent.x--;
        
      

      if (left) 
        if (ValidSqm(agent.x, agent.y - 1)) 
          if (EmptySqm(agent.x, agent.y - 1)) 
            agent.y--;
           else 
            left = false;
            if (EmptySqm(agent.x + 1, agent.y)) 
              down = true;
              trying = true;
             else if (EmptySqm(agent.x - 1, agent.y)) 
              up = true;
              trying = true;
            

          
         else 
          agent.x++;
          right = true;
          left = false;
        
      
      //up direction	
     else if (up) 
      tryTo = "down";
      if (lastDir == "left") 
        if (EmptySqm(agent.x, agent.y - 1)) 
          up = false;
          left = true;
          agent.y--;
        
       else if (lastDir == "right") 
        if (EmptySqm(agent.x, agent.y + 1)) 
          up = false;
          right = true;
          agent.y++;
        
      
      if (up) 
        if (ValidSqm(agent.x - 1, agent.y)) 
          if (EmptySqm(agent.x - 1, agent.y)) 
            agent.x--;
           else 
            up = false;
            //check left sqm
            if (EmptySqm(agent.x, agent.y - 1)) 
              left = true;
              agent.y--;
            
            //check right sqm
            else if (EmptySqm(agent.x, agent.y + 1)) 
              right = true;
              agent.y++;
            
            //check down sqm
            else if (EmptySqm(agent.x + 1, agent.y)) 
              down = true;
              agent.x++;
            

          
         else 
          agent.x++;
          up = false;
          down = true;
        
      
      //down direction
     else if (down) 
      tryTo = "up";
      if (lastDir == "left") 
        if (EmptySqm(agent.x, agent.y - 1)) 
          down = false;
          left = true;
          agent.y--;
        
       else if (lastDir == "right") 
        if (EmptySqm(agent.x, agent.y + 1)) 
          down = false;
          right = true;
          agent.y++;
        
      

      if (down) 
        if (ValidSqm(agent.x + 1, agent.y)) 
          if (EmptySqm(agent.x + 1, agent.y)) 
            agent.x++;
           else 
            down = false;
            //check left sqm
            if (EmptySqm(agent.x, agent.y - 1)) 
              left = true;
              agent.y--;
            
            //check right sqm
            else if (EmptySqm(agent.x, agent.y + 1)) 
              right = true;
              agent.y++;
            
            //check up sqm
            else if (EmptySqm(agent.x - 1, agent.y)) 
              up = true;
              agent.x--;
            
          
         else 
          agent.x--;
          up = true;
          down = false;
        
      
    
  , 100);

  var stopInterval = function() 
    clearInterval(timerId);
  ;
;

EmptySqm = function(x, y) 
  var bNotWall = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("wall");
  return bNotWall;


RemoveAgent = function() 
  $("#search_grid .row .grid_item").removeClass("agent");


ValidSqm = function(x, y) 
  return ((x >= 0 && x < gridSize) && (y >= 0 && y < gridSize));
html,
body 
  height: 100%;
  margin: 0;


.buttons 
  float: right;
  position: relative;
  right: 10px;
  top: 10px;


.buttons a 
  text-decoration: none;


#content 
  margin: 0 auto;
  width: 98%;
  text-align: center;


#controls 
  text-align: center;
  margin-bottom: 25px;
  padding: 5px;


#search_grid 
  width: 320px;
  height: 300px;
  position: relative;


#main 
  margin: auto;
  width: 20%;


.grid_item 
  display: block;
  border: 1px solid #bbb;
  float: left;
  line-height: 12px;
  font-size: 10px;


.grid_item.wall 
  background-color: #000000;


.grid_item.weight1 
  background-color: #ffffff;


.agent 
  text-align: center;
  color: grey;
  font-size: 20px;
  background-color: red !important;
  color: blue;
  font-weight: bold;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>
  <div id="content">
    <input type="button" id="btnInit" value="Start" /><br><br>
    <div id="main">
      <div id="search_grid">Loading...</div>
    </div>
  </div>
  <div id="footer"></div>
</body>

【问题讨论】:

你有一个看起来很酷的例子,但是当前的代码很难理解算法和回答问题。您可以删除无关代码以获得重现问题的Minimal, Complete, and Verifiable example 吗?此外,如果您将葡萄牙语更改为英语,您可能会得到更多答案。 @styfle 我已经删除了一些内容以使其更简单并专注于我的问题所在,但我同意你的观点,我会尝试进一步清理代码。 您要实现什么特定的通用算法?为什么不使用 A* 之类的东西? @zero298 如果我不能改进这个算法,我会尝试使用 A* 来解决我的问题,谢谢。 【参考方案1】:

我在a*算法的帮助下解决了我的问题,更具体地说是this implementation,障碍物的偏差是用move方法完成的,它返回某个路径细胞

path = grid.move(currentCell, endCell);

var agentSpeed = 10;
var WALL = 0;
var started = false;
var gridSize = 20;
var x = 0;
var y = 0;
var runsSameLine = false;

class Agent 
  constructor(x, y, charge, cap, distance) 
    this.x = x;
    this.y = y;
    this.charge = charge;
    this.cap = cap;
    this.distance = distance;
  


$(function() 
  var $grid = $("#search_grid");

  var opts = 
    gridSize: gridSize
  ;

  var grid = new GraphSearch($grid, opts, astar.search);

  //Initializes the agent
  $("#btnInit").click(function() 
    if (!started) 
      var agent = new Agent(0, 0, 100, 50, 0);
      agent.initialize();
      started = true;
    

  );
);

//Initializes the matrix
function GraphSearch($graph, options, implementation) 
  this.$graph = $graph;
  this.search = implementation;
  this.opts = options;
  this.initialize();


var grid;

GraphSearch.prototype.move = function($start, $end) 
  var end = this.nodeFromElement($end);
  if ($end.hasClass("wall")) 
    return;
  
  var start = this.nodeFromElement($start);
  var path = this.search(this.graph.nodes, start, end, true);
  if (!path || path.length == 0) 
    //this.animateNoPath();
   else 
    return path;
  
;

GraphSearch.prototype.nodeFromElement = function($cell) 
  return this.graph.nodes[parseInt($cell.attr("x"))][parseInt($cell.attr("y"))];
;

//Initializes the matrix
GraphSearch.prototype.initialize = function() 
  this.grid = [];
  var self = this,
    nodes = [],
    $graph = this.$graph;

  $graph.empty();

  var cellWidth = ($graph.width() / this.opts.gridSize) - 2,
    cellHeight = ($graph.height() / this.opts.gridSize) - 2,
    lineHeight = (this.opts.gridSize >= 30 ? "9.px" : ($graph.height() / this.opts.gridSize) - 10 + "px"),
    fontSize = (this.opts.gridSize >= 30 ? "10px" : "20px");
  $cellTemplate = $("<span />").addClass("grid_item").width(cellWidth).height(cellHeight).css("line-height", lineHeight).css("font-size", fontSize);

  for (var x = 0; x < this.opts.gridSize; x++) 
    var $row = $("<div class='row' />");
    nodeRow = [],
      gridRow = [];

    for (var y = 0; y < this.opts.gridSize; y++) 
      var id = "cell_" + x + "_" + y,
        $cell = $cellTemplate.clone();
      $cell.attr("id", id).attr("x", x).attr("y", y);
      $row.append($cell);
      gridRow.push($cell);

      var isWall = addWall(x, y, this.opts.gridSize);
      if (isWall === 1) 
        $cell.addClass("wall");
        nodeRow.push(1);
       else 
        $cell.addClass('weight1');
        nodeRow.push(0);
      

    
    $graph.append($row);
    this.grid.push(gridRow);
    nodes.push(nodeRow);

    //Fix for *** snippet
    if ($(window).width() < 700) 
      $("#search_grid").css("width", "320px");
      $("#main").css("width", "38%");
     else 
      $("#search_grid").css("width", "300px");
      $("#main").css("width", "20%");
    
  
  this.graph = new Graph(nodes);
  this.$cells = $graph.find(".grid_item");
  grid = this;
;

//Where will be wall in the matrix
addWall = function(x, y, size) 
  var limitPointLeftUp = [2, 3];
  var limitPointRightUp = [2, size - 4];

  var limitPointLeftDown = [size - 4, 2];
  var limitPointRightDown = [size - 4, size - 4];

  if ((x == 2 && y == 2) || (x == 2 && y == size - 3)) 
    return 1;
  

  if ((x == size - 3 && y == 2) || (x == size - 3 && y == size - 3)) 
    return 1;
  

  if (x >= 2 && (y == 3 && x >= limitPointLeftUp[0] && x <= limitPointLeftDown[0] + 1)) 
    return 1;
  

  if (x >= 2 && (y == size - 4 && x >= limitPointRightUp[0] && x <= limitPointRightDown[0] + 1)) 
    return 1;
  

  if ((x == 1 && y == 5) || (x == 9 && y == 17) || (x == 6 && y == 0) || (x == 9 && y == 7) || (x == 15 && y == 0) || (x == 15 && y == 2) || (x == 18 && y == 15)) 
    return 1;
  


//Initializes the agent
Agent.prototype.initialize = function() 
  var agent = this;
  var goToLeft = false;
  var goToRight = true;
  var rightLimit = gridSize - 1;
  var leftLimit = 0;
  var lastPos = 0;
  var path = [];
  var completedPath = true;

  timerId = setInterval(function() 
    agent.x = x;
    agent.y = y;
    currentCell = $("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]");
    currentCell.css("background-color", "#e2e2e2");

    if (agent.x == gridSize - 1 && agent.y == 0) 
      stopInterval(timerId);
      return false;
    

    if (goToRight && y == rightLimit) 
      if (runsSameLine) 
        goToLeft = true;
        goToRight = false;
        runsSameLine = false;
       else 
        if (FreeCell((x + 1), y)) 
          endCell = $("#search_grid .row .grid_item[x=" + (x + 1) + "][y=" + y + "]");
          x++;
          goToLeft = true;
          goToRight = false;
         else 
          endCell = FindNextFreeCell(x, y, "limDir");
          goToLeft = true;
          goToRight = false;
        
      
     else if (goToLeft && y == leftLimit) 
      if (runsSameLine) 
        goToLeft = false;
        goToRight = true;
        runsSameLine = false;
       else 
        if (FreeCell((x + 1), y)) 
          endCell = $("#search_grid .row .grid_item[x=" + (x + 1) + "][y=" + y + "]");
          x++;
          goToLeft = false;
          goToRight = true;
         else 
          endCell = FindNextFreeCell(x, y, "limEsq");
          goToLeft = false;
          goToRight = true;
        
      

     else if (goToRight) 
      if (FreeCell(x, (y + 1))) 
        endCell = $("#search_grid .row .grid_item[x=" + x + "][y=" + (y + 1) + "]");
        y++;
       else 
        endCell = FindNextFreeCell(x, y, "dir");
      
     else if (goToLeft) 
      if (FreeCell(x, (y - 1))) 
        endCell = $("#search_grid .row .grid_item[x=" + x + "][y=" + (y - 1) + "]");
        y--;
       else 
        endCell = FindNextFreeCell(x, y, "esq");
      
    

    if (completedPath) 
      path = grid.move(currentCell, endCell);
    

    if (path) 
      if (lastPos == path.length - 1) 
        completedPath = true;
      



      if (path.length > 1 && lastPos < path.length && lastPos != path.length - 1) 
        x = path[lastPos].x;
        y = path[lastPos].y;
        lastPos++;
        completedPath = false;
       else if (completedPath) 
        x = path[lastPos].x;
        y = path[lastPos].y;
        lastPos = 0;

      
    
    grid.$cells.removeClass("agent");
    $("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").addClass("agent");
  , agentSpeed);

  var stopInterval = function() 
    clearInterval(timerId);
  ;
;

FindNextFreeCell = function(x, y, dir) 
  if (dir == "limDir") 
    if (x != gridSize) 
      for (var y = y; y >= 0; y--) 
        if (FreeCell((x + 1), y)) 
          return getCell((x + 1), y);
        
      
    
   else if (dir == "limEsq") 
    if (x != gridSize) 
      for (var y = y; y <= gridSize; y++) 
        if (FreeCell((x + 1), y)) 
          return getCell((x + 1), y);
        
      
    
   else if (dir == "dir") 
    for (var y = y; y < gridSize - 1; y++) 
      if (FreeCell(x, (y + 1))) 
        return getCell(x, (y + 1));
      
    
    for (var x = x; x <= gridSize - 1; x++) 
      if (FreeCell((x + 1), y)) 
        runsSameLine = true;
        return getCell((x + 1), y);
      
    

   else if (dir == "esq") 
    for (var y = y; y > 0; y--) 
      if (FreeCell(x, (y - 1))) 
        return getCell(x, (y - 1));
      
    
    for (var x = x; x <= gridSize - 1; x++) 
      if (FreeCell((x + 1), y)) 
        runsSameLine = true;
        return getCell((x + 1), y);
      
    
  


EmptySqm = function(x, y) 
  var bNotWall = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("wall");
  return bNotWall;


getCell = function(x, y) 
  return $("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]");


FreeCell = function(x, y) 
  var bNaoTemParede = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("wall");
  var bNaoTemLixeira = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("lixeira");
  var bNaoTemRecarga = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("pontoRecarga");
  return bNaoTemParede && bNaoTemLixeira && bNaoTemRecarga;


ValidSqm = function(x, y) 
  return ((x >= 0 && x < gridSize) && (y >= 0 && y < gridSize));


// javascript-astar
// http://github.com/bgrins/javascript-astar
// Freely distributable under the MIT License.
// Implements the astar search algorithm in javascript using a binary heap.

var astar = 
  init: function(grid) 
    for (var x = 0, xl = grid.length; x < xl; x++) 
      for (var y = 0, yl = grid[x].length; y < yl; y++) 
        var node = grid[x][y];
        node.f = 0;
        node.g = 0;
        node.h = 0;
        node.cost = node.type;
        node.visited = false;
        node.closed = false;
        node.parent = null;
      
    
  ,
  heap: function() 
    return new BinaryHeap(function(node) 
      return node.f;
    );
  ,
  search: function(grid, start, end, diagonal, heuristic) 
    astar.init(grid);
    heuristic = heuristic || astar.manhattan;
    diagonal = !!diagonal;

    var openHeap = astar.heap();

    openHeap.push(start);

    while (openHeap.size() > 0) 

      // Grab the lowest f(x) to process next.  Heap keeps this sorted for us.
      var currentNode = openHeap.pop();

      // 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.
      currentNode.closed = true;

      // Find all neighbors for the current node. Optionally find diagonal neighbors as well (false by default).
      var neighbors = astar.neighbors(grid, currentNode, diagonal);

      for (var i = 0, il = neighbors.length; i < il; i++) 
        var neighbor = neighbors[i];

        if (neighbor.closed || neighbor.isWall() || $("#search_grid .row .grid_item[x=" + neighbor.x + "][y=" + neighbor.y + "]").hasClass("pontoRecarga") || $("#search_grid .row .grid_item[x=" + neighbor.x + "][y=" + neighbor.y + "]").hasClass("lixeira")) 
          // Not a valid node to process, skip to next neighbor.
          continue;
        

        // The 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 + neighbor.cost;
        var beenVisited = neighbor.visited;

        if (!beenVisited || gScore < neighbor.g) 

          // Found an optimal (so far) path to this node.  Take score for node to see how good it is.
          neighbor.visited = true;
          neighbor.parent = currentNode;
          neighbor.h = neighbor.h || heuristic(neighbor.pos, end.pos);
          neighbor.g = gScore;
          neighbor.f = neighbor.g + neighbor.h;

          if (!beenVisited) 
            // Pushing to heap will put it in proper place based on the 'f' value.
            openHeap.push(neighbor);
           else 
            // Already seen the node, but since it has been rescored we need to reorder it in the heap
            openHeap.rescoreElement(neighbor);
          
        
      
    

    // No result was found - empty array signifies failure to find path.
    return [];
  ,
  manhattan: function(pos0, pos1) 
    // See list of heuristics: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html

    var d1 = Math.abs(pos1.x - pos0.x);
    var d2 = Math.abs(pos1.y - pos0.y);
    return d1 + d2;
  ,
  neighbors: function(grid, node, diagonals) 
    var ret = [];
    var x = node.x;
    var y = node.y;

    // West
    if (grid[x - 1] && grid[x - 1][y]) 
      ret.push(grid[x - 1][y]);
    

    // East
    if (grid[x + 1] && grid[x + 1][y]) 
      ret.push(grid[x + 1][y]);
    

    // South
    if (grid[x] && grid[x][y - 1]) 
      ret.push(grid[x][y - 1]);
    

    // North
    if (grid[x] && grid[x][y + 1]) 
      ret.push(grid[x][y + 1]);
    

    if (diagonals) 

      // Southwest
      if (grid[x - 1] && grid[x - 1][y - 1]) 
        ret.push(grid[x - 1][y - 1]);
      

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

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

      // Northeast
      if (grid[x + 1] && grid[x + 1][y + 1]) 
        ret.push(grid[x + 1][y + 1]);
      

    

    return ret;
  
;

// javascript-astar
// http://github.com/bgrins/javascript-astar
// Freely distributable under the MIT License.
// Includes Binary Heap (with modifications) from Marijn Haverbeke.
// http://eloquentjavascript.net/appendix2.html


var GraphNodeType = 
  OPEN: 0,
  WALL: 1
;

// Creates a Graph class used in the astar search algorithm.
function Graph(grid) 
  var nodes = [];

  for (var x = 0; x < grid.length; x++) 
    nodes[x] = [];

    for (var y = 0, row = grid[x]; y < row.length; y++) 
      nodes[x][y] = new GraphNode(x, y, row[y]);
    
  

  this.input = grid;
  this.nodes = nodes;


Graph.prototype.toString = function() 
  var graphString = "\n";
  var nodes = this.nodes;
  var rowDebug, row, y, l;
  for (var x = 0, len = nodes.length; x < len; x++) 
    rowDebug = "";
    row = nodes[x];
    for (y = 0, l = row.length; y < l; y++) 
      rowDebug += row[y].type + " ";
    
    graphString = graphString + rowDebug + "\n";
  
  return graphString;
;

function GraphNode(x, y, type) 
  this.data = ;
  this.x = x;
  this.y = y;
  this.pos = 
    x: x,
    y: y
  ;
  this.type = type;


GraphNode.prototype.toString = function() 
  return "[" + this.x + " " + this.y + "]";
;

GraphNode.prototype.isWall = function() 
  return this.type === GraphNodeType.WALL;
;


function BinaryHeap(scoreFunction) 
  this.content = [];
  this.scoreFunction = scoreFunction;


BinaryHeap.prototype = 
  push: function(element) 
    // Add the new element to the end of the array.
    this.content.push(element);

    // Allow it to sink down.
    this.sinkDown(this.content.length - 1);
  ,
  pop: function() 
    // Store the first element so we can return it later.
    var result = this.content[0];
    // Get the element at the end of the array.
    var end = this.content.pop();
    // If there are any elements left, put the end element at the
    // start, and let it bubble up.
    if (this.content.length > 0) 
      this.content[0] = end;
      this.bubbleUp(0);
    
    return result;
  ,
  remove: function(node) 
    var i = this.content.indexOf(node);

    // When it is found, the process seen in 'pop' is repeated
    // to fill up the hole.
    var end = this.content.pop();

    if (i !== this.content.length - 1) 
      this.content[i] = end;

      if (this.scoreFunction(end) < this.scoreFunction(node)) 
        this.sinkDown(i);
       else 
        this.bubbleUp(i);
      
    
  ,
  size: function() 
    return this.content.length;
  ,
  rescoreElement: function(node) 
    this.sinkDown(this.content.indexOf(node));
  ,
  sinkDown: function(n) 
    // Fetch the element that has to be sunk.
    var element = this.content[n];

    // When at 0, an element can not sink any further.
    while (n > 0) 

      // Compute the parent element's index, and fetch it.
      var parentN = ((n + 1) >> 1) - 1,
        parent = this.content[parentN];
      // Swap the elements if the parent is greater.
      if (this.scoreFunction(element) < this.scoreFunction(parent)) 
        this.content[parentN] = element;
        this.content[n] = parent;
        // Update 'n' to continue at the new position.
        n = parentN;
      

      // Found a parent that is less, no need to sink any further.
      else 
        break;
      
    
  ,
  bubbleUp: function(n) 
    // Look up the target element and its score.
    var length = this.content.length,
      element = this.content[n],
      elemScore = this.scoreFunction(element);

    while (true) 
      // Compute the indices of the child elements.
      var child2N = (n + 1) << 1,
        child1N = child2N - 1;
      // This is used to store the new position of the element,
      // if any.
      var swap = null;
      var child1Score;
      // If the first child exists (is inside the array)...
      if (child1N < length) 
        // Look it up and compute its score.
        var child1 = this.content[child1N];
        child1Score = this.scoreFunction(child1);

        // If the score is less than our element's, we need to swap.
        if (child1Score < elemScore) 
          swap = child1N;
        
      

      // Do the same checks for the other child.
      if (child2N < length) 
        var child2 = this.content[child2N],
          child2Score = this.scoreFunction(child2);
        if (child2Score < (swap === null ? elemScore : child1Score)) 
          swap = child2N;
        
      

      // If the element needs to be moved, swap it, and continue.
      if (swap !== null) 
        this.content[n] = this.content[swap];
        this.content[swap] = element;
        n = swap;
      

      // Otherwise, we are done.
      else 
        break;
      
    
  
;
html,
body 
  height: 100%;
  margin: 0;


.buttons 
  float: right;
  position: relative;
  right: 10px;
  top: 10px;


.buttons a 
  text-decoration: none;


#content 
  margin: 0 auto;
  width: 98%;
  text-align: center;


#controls 
  text-align: center;
  margin-bottom: 25px;
  padding: 5px;


#search_grid 
  width: 300px;
  height: 300px;
  position: relative;


#main 
  margin: auto;
  width: 20%;


.grid_item 
  display: block;
  border: 1px solid #bbb;
  float: left;
  line-height: 12px;
  font-size: 10px;


.grid_item.wall 
  background-color: #000000;


.grid_item.weight1 
  background-color: #ffffff;


.agent 
  text-align: center;
  color: grey;
  font-size: 20px;
  background-color: red !important;
  color: blue;
  font-weight: bold;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<body>
  <div id="content">
    <input type="button" id="btnInit" value="Start" /><br><br>
    <div id="main">
      <div id="search_grid">Loading...</div>
    </div>
  </div>
  <div id="footer"></div>
</body>

【讨论】:

以上是关于防止与新路径发生碰撞的主要内容,如果未能解决你的问题,请参考以下文章

海康威视复赛题 ---- 碰撞避免方案

多次调用 SpriteKit 碰撞

SpriteKit中精灵之间的碰撞

如何防止因哈希碰撞引起的DoS攻击

如何防止因哈希碰撞引起的DoS攻击

如何防止因哈希碰撞引起的DoS攻击