在边界坐标内找到坐标

时间:2019-07-28 15:47:32

标签: javascript path-finding

我有x,y 4x5仪表板。我有对象的碰撞数组,即:

const collisions = [{x: 1, y: 0}, {x: 2, y: 0}, {x: 0, y: 1}, {x: 0, y: 2}, {x: 1, y: 3}, {x: 2, y: 3}, {x: 3, y: 1}, {x: 3, y: 2}];

基本上是一个没有边缘的正方形。我也有一系列目的地:

const destinations = [{x: 0, y: 0}, {x: 1, y: 1}, {x: 0, y: 4}];

图形表示为:

enter image description here

其中红色是collisions,金色是destinations

我需要一种算法,该算法可以找到被冲突包围的目的地。我不能斜着走,所以在上方的场景中,我想找到{x:1,y:1}。

如何实现?

2 个答案:

答案 0 :(得分:1)

可能有更有效的算法来计算此值,但是乍一想,您可以简单地迭代所有目的地,并一一检查所有4个方向(左,右,上,下)的邻居平方。

这是一个实现。这有点冗长,但是您可以通过分离函数来简化它:

const collisions = [{x: 1, y: 0}, {x: 2, y: 0}, {x: 0, y: 1}, {x: 0, y: 2}, {x: 1, y: 3}, {x: 2, y: 3}, {x: 3, y: 1}, {x: 3, y: 2}];
const destinations = [{x: 0, y: 0}, {x: 1, y: 1}, {x: 0, y: 4}];

const surrounded = [];

// boundaries
var minX = 0, minY = 0;
var maxX = 3, maxY = 4;

var point = {x: 0, y: 0};
for(dest of destinations){

  var left = false;
  var right = false;
  var up = false;
  var down = false;

  point.x = dest.x;
  point.y = dest.y;

  // left check
  while(point.x--){

    // hit check
    if(collisions.findIndex(e => e.x==point.x&&e.y==point.y) > -1){
      // console.log("left hit for point:")
      // console.log(dest)
      left = true;
      break;
    }

    if(point.x <= minX || point.x >= maxX || point.y <= minY || point.y >= maxY){
      break;
    }

  }

  if(!left)
    continue;

  point.x = dest.x;
  point.y = dest.y;

  // right check
  while(point.x++){

    // hit check
    if(collisions.findIndex(e => e.x==point.x&&e.y==point.y) > -1){
      // console.log("right hit for point:")
      // console.log(dest)
      right = true;
      break;
    }

    if(point.x <= minX || point.x >= maxX || point.y <= minY || point.y >= maxY){
      break;
    }

  }

  if(!right)
    continue;

  point.x = dest.x;
  point.y = dest.y;

  // up check
  while(point.y--){

    // hit check
    if(collisions.findIndex(e => e.x==point.x&&e.y==point.y) > -1){
      // console.log("up hit for point:")
      // console.log(dest)
      up = true
      break;
    }

    if(point.x <= minX || point.x >= maxX || point.y <= minY || point.y >= maxY){
      break;
    }

  }

  if(!up)
    continue;

  point.x = dest.x;
  point.y = dest.y;

  // down check
  while(point.y++){

    // hit check
    if(collisions.findIndex(e => e.x==point.x&&e.y==point.y) > -1){
      // console.log("down hit for point:")
      // console.log(dest)
      down = true
      break;
    }

    if(point.x <= minX || point.x >= maxX || point.y <= minY || point.y >= maxY){
      break;
    }

  }

  if(!down)
    continue;

  if(left && right && up && down){
    surrounded.push(dest)
  }

}

console.log("Surrounded found: " + surrounded.length);
console.log(surrounded);

这里是jsbin

答案 1 :(得分:1)

我可能不是尝试创建新算法,而是尝试使用经过测试的已建立(并且已经实现)的路径查找算法,例如 A * (基本上是Dijkstra算法的优化版本,请阅读更多内容)。关于路径查找算法here),并适应您的情况,以便可以使用它们。我认为这种方法将为您节省很多时间,并使您的代码更可靠。

请注意,我已将您的坐标对象转换为坐标数组,这是a)以这种方式表示坐标的更常见的情况,以及b)使用它们更容易(而且很可能更快=>数组很快速)。

对于您的示例,我们基本上希望从实际网格的某个外部点找到到每个目标的路径。我们还需要确保目的地位于网格边缘,例如[0,0][0,4]可以通过某种方式访问​​,例如一条路可以通往他们。因此,我们扩展/“填充”网格,每侧有一个节点。这意味着您的所有坐标都移动了1个节点。

enter image description here

从那里我们可以简单地检查到目的地的路径是否存在。我正在[0,0]进行检查,该位置现在不在您的实际网格中,但是您可以从任何地方进行检查,只要该节点是“填充”节点之一即可:

const collisions = [[1, 0], [2, 0], [0, 1], [0, 2], [1, 3], [2, 3], [3, 1], [3, 2]];
const destinations = [[0, 0], [1, 1], [0, 4]];

// we expand the grid by one node on each side
// otherwise destinations at the edge might not be reachable!
const grid = new PF.Grid(4+2, 5+2);

// set up the blocked nodes
collisions.forEach(collision => {
	// +1 accounts for the grid "padding" of one node
	grid.setWalkableAt(collision[0]+1, collision[1]+1, false);
});

const paintGrid = grid => {
  const rects = [];
  const nodes = grid.nodes.flat();
  nodes.forEach(node => {
    rects.push(`
      <rect x="${node.x*24}" y="${node.y*24}" width="24" height="24" fill="${node.walkable ? '#FFF' : 'red'}" stroke="#000" stroke-opacity="0.2"></rect>
    `);
  });
  destinations.forEach(dest => {
    rects.push(`
      <rect x="${(dest[0]+1)*24}" y="${(dest[1]+1)*24}" width="24" height="24" fill="gold" stroke="#000" stroke-opacity="0.2"></rect>
    `);
  });
  document.querySelector('#grid').innerHTML = rects.join('');
};

const isTrapped = destination => {
	// make a working copy of the grid
	// as it will not be re-usable after processing
	const g = grid.clone();
	const finder = new PF.AStarFinder({
		allowDiagonal: false
	});
	
	// +1 accounts for the grid "padding" of one node
	return finder.findPath(0, 0, destination[0]+1, destination[1]+1, g).length === 0;
};

paintGrid(grid);

destinations.forEach(destination => {
	console.log(`is ${destination} trapped?`, isTrapped(destination));
});
<script src="https://cdn.jsdelivr.net/gh/qiao/PathFinding.js@0.4.18/visual/lib/pathfinding-browser.min.js"></script>

<svg id="grid" width="144" height="168" xmlns="http://www.w3.org/2000/svg">

</svg>

如果您真的需要完整的路径查找,这当然取决于您的实际情况,如果您的网格和目标始终是“小”规模,则可能会找到一种更简单的解决方案,例如@Yavuz建议的解决方案塔斯河

相关问题