java - 在2d char数组中生成随机路径的算法

时间:2016-01-22 19:42:41

标签: java algorithm path-finding

我正在尝试在 2维字符数组中生成从一个点到另一个点的随机路径,但是它遵循这些规则:

  • 唯一允许的字符是:
    • O =开放路径
    • - =接受来自的路径或来自的路径
    • | =接受来自 top 的路径或来自 bottom 的路径
    • \ =接受以下路径: top left left top ,< em> bottom right right 到底。
    • / =接受以下路径:底部底部,< em>正确到顶部顶部正确
    • “接受路径”表示其他路径(/-|\)只能从已设置的边连接。

这是一张了解字符及其作用的图片:( -为红色,\为蓝色,/为绿色,|为橙色)

The chars and their meanings.

  • 路径不能越过自己 - 它只能进入空旷的地方(开放路径:O)。想象一下结果路径就像蛇一样,这是一部备受喜爱的游戏 - 它无法自拔。
  • 2d数组可以是任何大小
  • 结尾可以在任何地方出现 - 它没有标记X或任何类似的字符,但它必须符合逻辑。

正确的输出:

开始:(0,0),结束:(3,3)

START-> - - \ O
        O O \ \
        O / - /
        O \ - \ <- END

第一个例子基本上是这样的: The first example as an image.

开始:(1,0),结束:(1,4)

START v
    O - \ O O
    / - / O O
    \ - - - \
    O O O O |
    O - - - / 
      ^ END

第二个例子基本上是这样的: The second example as an image.

我正在尝试使用此代码来完成此操作,但出于某种原因,它无效:

代码:

int x, y, mapsize;
char[][] map;
public Random rand = new Random();
public boolean findPath(int x, int y, int xGoal, int yGoal){
    if(x==xGoal&&y==yGoal)return true;
    int[] avilableMovement = avilableMovement(x, y);
    if(avilableMovement==null)return false;
    int moveX = avilableMovement[0];
    int moveY = avilableMovement[1];
    map[moveX][moveY]=mark(x, y, moveX, moveY);
    if(findPath(moveX, moveY, xGoal, yGoal))return true;
    return false;
}
public char mark(int fromX, int fromY, int toX, int toY){
    //If moved to up/down and <>, mark |
    //If moved to <> and left/right, mark -
    //If moved to up and left, or to down and right, mark \
    //If moved to up and right, or to down and left, mark /
    boolean toUp = fromY<toY;
    boolean toDown = fromY>toY;
    boolean toRight = fromX<toX;
    boolean toLeft = fromX>toX;
    if((toUp||toDown)&&!(toLeft||toRight)){
        return '|';
    }
    if((toLeft||toRight)&&!(toUp||toDown)){
        return '-';
    }
    if((toUp&&toLeft)||(toDown&&toRight)){
        return '\\';
    }
    if((toUp&&toRight)||(toDown&&toLeft)){
        return '/';
    }
    return '?';
}
private boolean onMap(int x, int y){
    return x>0&&y>0&&x<mapsize&&y<mapsize;
}
private int[] avilableMovement(int x, int y){
    ArrayList<Integer> numsX = new ArrayList<>(Arrays.asList(-1+x, 0+x, 1+x));
    ArrayList<Integer> numsY = new ArrayList<>(Arrays.asList(-1+y, 0+y, 1+y));
    Collections.shuffle(numsX);
    Collections.shuffle(numsY);
    //^^ Making it random instead of going in same order every timee
    for(int lx : numsX){
        for(int ly : numsY){
            if(onMap(y+ly, x+lx)&&map[y+ly][x+lx]=='O'){
                return new int[]{x+lx, y+ly};
            }
        }
    }
    return null;
}

当我使用此代码运行代码时,

private void initMap(int mapsize){
    this.mapsize=mapsize;
     map = new char[mapsize][mapsize];
    for(int i = 0; i<mapsize; i++){
        for(int j = 0; j<mapsize; j++){
            map[i][j]='O';
        }
    }
}
public static void main(String[] args){
    Main main = new Main();
    main.initMap(4);
    System.out.println(main.findPath(0, 0, 3, 3));
    for(char[] ch : main.map){
        System.out.println(ch);
    }
}

它不断输出错误的&amp;不合逻辑的路径,例如:

OOOO
O/OO
O-OO
O-OO

或(地图大小为6):

OOOOOO
O/OOOO
O-OOOO
OOO/OO
OOOOOO
OOOOOO

我不知道为什么会这样。谁能告诉我我的代码有什么问题并帮我解决这个问题?

提前致谢!

P.S:在你提出问题之前,不,这不是一个家庭作业问题。

编辑:我更新了我的代码,现在该方法返回true并且到达结尾,但是有问题。我的更新代码:

public Random rand = new Random();
public boolean findPath(int x, int y, int xGoal, int yGoal){
    if(x==xGoal&&y==yGoal)return true;
    int[] avilableMovement = avilableMovement(x, y);
    if(avilableMovement==null)return false;
    int moveX = avilableMovement[0];
    int moveY = avilableMovement[1];
    map[moveX][moveY]=mark(x, y, moveX, moveY);
    if(findPath(moveX, moveY, xGoal, yGoal))return true;
    return false;
}
public char mark(int fromX, int fromY, int toX, int toY){
    //If moved to up/down and <>, mark |
    //If moved to <> and left/right, mark -
    //If moved to up and left, or to down and right, mark \
    //If moved to up and right, or to down and left, mark /
    boolean toUp = fromY<toY;
    boolean toDown = fromY>toY;
    boolean toRight = fromX<toX;
    boolean toLeft = fromX>toX;
    if((toUp||toDown)&&!(toLeft||toRight)){
        return '|';
    }
    if((toLeft||toRight)&&!(toUp||toDown)){
        return '-';
    }
    if((toUp&&toLeft)||(toDown&&toRight)){
        return '\\';
    }
    if((toUp&&toRight)||(toDown&&toLeft)){
        return '/';
    }
    return 'O';
}
private boolean onMap(int x, int y){
    return x>0&&y>0&&x<mapsize&&y<mapsize;
}
private int[] avilableMovement(int x, int y){
    ArrayList<Integer> numsX = new ArrayList<>(Arrays.asList(-1+x, x, 1+x));
    ArrayList<Integer> numsY = new ArrayList<>(Arrays.asList(-1+y, y, 1+y));
    Collections.shuffle(numsX);
    Collections.shuffle(numsY);
    //^^ Making it random instead of going in same order every timee
    for(int lx : numsX){
        for(int ly : numsY){
            if(onMap(ly, lx)&&map[ly][lx]=='O'){
                return new int[]{lx, ly};
            }
        }
    }
    return null;
}

我的主要代码:

Main main = new Main();
    main.initMap(4);
    boolean b = main.findPath(0, 0, 3, 3);
    while(!b)b = main.findPath(0, 0, 3, 3);
    for(int i = 0; i<main.mapsize; i++){
        for(int j = 0; j<main.mapsize; j++){
            System.out.print(main.map[j][i]);
        }
        System.out.println();
    }

我可以在输出中看到它到达它的最终destenation,但它没有显示开始。那是为什么?

以下是新更新代码的一些示例输出:

OOOO
O/OO
O/OO
O---

OOOO
O//-
OO/O
OOO|

正如你所看到的,输出仍然没有意义,但它比以前更接近:P它并不完全遵循规则而且它没有显示开始。那是为什么?

2 个答案:

答案 0 :(得分:1)

我发现了几个错误(我没有运行你的代码)。

1.主要问题是你可能在你的逻辑中混合x和y坐标并输出到屏幕,试着改变

for(char[] ch : main.map){
    System.out.println(ch);
}

类似

for(int i = 0; i<mapsize; i++){
    for(int j = 0; j<mapsize; j++){
        System.out.print(map[j][i]);
    }
    System.out.println();
}

即。更改循环输出的x和y坐标

2.您可能在函数avilableMovement中错误地计算了x,y的下一个坐标。 lxly已包含xy,即您在xyx+lx两次添加y+lyArrayList<Integer> numsX = new ArrayList<>(Arrays.asList(-1+x, 0+x, 1+x)); ArrayList<Integer> numsY = new ArrayList<>(Arrays.asList(-1+y, 0+y, 1+y)); Collections.shuffle(numsX); Collections.shuffle(numsY); for(int lx : numsX){ for(int ly : numsY){ if(onMap(y+ly, x+lx)&&map[y+ly][x+lx]=='O'){ return new int[]{x+lx, y+ly}; 1}}:

map[moveX][moveY]=mark(x, y, moveX, moveY);
if(findPath(moveX, moveY, xGoal, yGoal))return true;
return false;

3.你不会回来&#39; O&#39;如果路径未在当前单元格中找到,则标记为单元格,并且您不会检查下一个可能的移动:

asadm -e "info"

答案 1 :(得分:0)

这是您考虑的另一个想法。从一条简单的路径开始,例如,沿着x轴直线然后沿着y轴直线(或反之亦然)从头到尾,

start--\
       |
       |    
       |
       \end

我们可以使用预先设置的选项字典来修改路径。对于路径中两个其他单元格之间的任何一个单元格(排除了开始和结束单元格),我们定义了6种可能性,每种可能性都有两种方法来修改它。在以下两个示例中,我们只关注修改中间单元x

(1) cell is connected from west and east:

  o x o

we can move x either north or south:

  / x \
  o   o  or  o   o
             \ x /

(2) cell is connected from west and south:

  o x
    o

we can move x either north or east:

  / x
  o |  or  o - x
    o        o /

由于无法通过对角线连接单元,因此只需考虑4 choose 2 = 6个配置。我们可以根据路径中单元格的增量配置轻松创建随机尝试的选项字典。上面的两个例子是:

(dictionary key)   (dictionary value)
Δx1 Δy1 Δx2 Δy2
 1   0  -1   0  => try north or south
 1   0   0  -1  => try north or east