【问题标题】:Random path keep getting stuck随机路径不断卡住
【发布时间】:2014-06-13 00:34:29
【问题描述】:

您好,我正在尝试编写一款塔防游戏。 我目前正在尝试构建小怪将遵循的路径。

但我的道路总是蜷缩起来。

路径的工作方式是使用二维数组,即网格。由包含 isPath 属性的单元格对象组成的 40 行和 40 列。

我创建路径的方式是选择一个随机方向,然后检查我们尝试访问的单元格是否还不是路径的一部分,并且它不会与多个单元格(即它来自的单元格)。我还看看我是否在我们不想向左走的第一个列,因为下一个单元格最终会出现在最后一个列的上排。到最后也一样。

这是我迄今为止为路径算法写的内容:

function createPath(){

var indexesOfCellsInLastCol = new Array();
for(var o = NumberOfRow; o < (NumberOfRow * NumberOfRow); o+= NumberOfRow)
    indexesOfCellsInLastCol.push(o);

var indexesOfCellsInFirstCol = new Array();
for(var k = 1; k < (NumberOfRow * NumberOfRow); k+= NumberOfRow)
    indexesOfCellsInFirstCol.push(k);

var usedDirection = [];

var x = 0;
var y = 0;

 // random walk without crossing
 for(var i = 0; i < 50000; i++){
    var direction = Math.floor((Math.random()*4));

    //always start the same way
    if(i < 10){
        if(i == 9){
            grid[2][i].isPath = true;
            grid[1][i].isPath = true;
            x = i;
            y = 2;
        }
        grid[0][i].isPath = true;
    }   
    else
    {
        switch(direction){
            //left
            case 0: 
                if(!contains(usedDirection, 0)){
                    if(collideDirection(y,x - 1) == 1){
                        //check if you are not in first col, because if you go left while you're in first                     col you go back to last row.
                        if(!contains(indexesOfCellsInFirstCol, x) && !grid[y][x - 1].isPath){
                            grid[y][x - 1].isPath = true;
                            x--;
                            usedDirection = [];
                        }
                        else
                            usedDirection.push(0);
                    }
                }
            break;
            //up
            case 1:
                if(!contains(usedDirection, 1)){
                    if(collideDirection(y - 1,x) == 1){
                        if(y - 1 > 1 && !grid[y - 1][x].isPath){
                            grid[y - 1][x].isPath = true;
                            y--;
                            usedDirection = [];
                        }
                        else
                            usedDirection.push(1);
                    }
                }                   
            break;
            //right
            case 2:
                if(!contains(usedDirection, 2)){                
                    if(collideDirection(y,x + 1) == 1){
                        //same as going left whil you're on the first col
                        if(!contains(indexesOfCellsInLastCol, x) && !grid[y][x + 1].isPath){
                            grid[y][x + 1].isPath = true;
                            x++;
                            usedDirection = [];
                        }
                        //don't be no fool and try to repeat your self
                        else
                            usedDirection.push(2);
                    }
                }                   
            break
            //down
            case 3:
                if(!contains(usedDirection, 3)){
                    if(collideDirection(y + 1,x) == 1 ){
                        if((y + 1 < (NumberOfRow - 1)) && !grid[y + 1][x].isPath){
                            grid[y + 1][x].isPath = true;
                            y++;
                            usedDirection = [];
                        }
                        else
                            usedDirection.push(3);
                    }   
                }                   
            break;
        }
    }
 }

}

我已将所有其余代码放入 js fiddle http://jsfiddle.net/xZ7tH/

我不一定想要代码anwser,也许只是提示我应该去哪里或应该做什么。

我考虑过看看这条路如果左转超过 3 次,那么它必须向右转。但我认为它会在一条太多的线性路径中上升。

有什么想法吗??

感谢您的回答!

【问题讨论】:

  • 你能补充更多关于职位系统的信息吗?路径是由网格上的单元格组成的吗?平面上的任意向量?

标签: javascript algorithm path grid


【解决方案1】:

以下是在 2d 网格上随机游走的 Java 实现,没有交叉点。关于它的几点说明:

1) 我没有重复处理不同方向的代码,而是使用了 4 个方向的预定义列表([-1,0]、[0,1]、[1,0]、[0,-1 ]) 并在我每次扫描所有可能的方向以继续时随机播放。

2)您的解决方案似乎失败了,因为它不涉及任何回溯 - 每次到达死胡同时,您都应该返回上一步并尝试转向另一个方向。我正在使用递归来简化回溯。

3) 该算法是递归的,因此对于长路径它可能会因 StackOverflowError 而失败。如果您需要它来处理长路径,请考虑使用堆栈来模拟递归。

4) 该算法不处理边界矩形。这需要稍作改动。

public class RandomPathCreator {
  private final static List<Location> DIRECTIONS = Arrays.asList(new Location[]{new Location(-1, 0), new Location(0, -1), new Location(1, 0), new Location(0, 1)});

  public static Path randomPath(int len) {
    Path path = new Path();
    path.append(new Location(0,0)); //The random walk starts from [0,0]
    findPath(len, path);
    return path;
  }

  ///////////////////////////////
  // The main logic is here
  ///////////////////////////////
  private static boolean findPath(int len, Path path) {
    if (path.size() == len)
      return true;

    Location lastPos = path.getLast();
    Collections.shuffle(DIRECTIONS);
    for (Location dir : DIRECTIONS) {
      Location newPos = lastPos.add(dir);
      if (path.append(newPos)) {
        if (findPath(len, path))
          return true;
        path.removeLast();
      }      
    }
    return false;
  }

  private static class Location {
    public final int x;
    public final int y;

    public Location(int x, int y) {
      this.x = x;
      this.y = y;
    }

    public Location add(Location other) {
      return new Location(x + other.x, y + other.y);
    }

    @Override
    public int hashCode() {
      return 31 * (31 + x) + y;
    }

    @Override
    public boolean equals(Object obj) {
      Location other = (Location) obj;
      return (x == other.x && y == other.y); 
    }

    @Override
    public String toString() {
      return "Location [x=" + x + ", y=" + y + "]";
    }
  }

  private static class Path {
    private List<Location> list = new ArrayList<Location>();
    private Set<Location> set = new HashSet<Location>();

    public boolean append(Location l) {
      if (set.add(l)) {
        list.add(l);
        return true;
      }
      return false;
    }

    public Location getLast() {
      return list.get(list.size() - 1);
    }

    public void removeLast() {
      Location last = list.remove(list.size() - 1);
      set.remove(last);
    }

    public int size() {
      return list.size();
    }

    @Override
    public String toString() {
      return list.toString();
    }
  }
}

【讨论】:

  • 只有一个问题 ovridden hashcode 的目的是什么?
  • @FrancisGroleau:必须重写 Hashcode() 和 equals() 以使 Location 类适合作为哈希集中的键。否则,使用默认实现,任何两个不同的位置实例都被哈希集认为是不同的,而不管它们的 x 和 y 值如何。 BTW:这个实现中的集合不是强制性的;它仅用于提高路径交叉检查的性能。
猜你喜欢
  • 2018-03-22
  • 1970-01-01
  • 2019-10-16
  • 2021-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-18
相关资源
最近更新 更多