简体   繁体   English

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

[英]java - Algorithm for generating random path in 2d char array

I'm trying to generate a random path from a point to another one in a 2 dimensional char array , but so it'd follow these rules: 我正在尝试在二维char数组中生成从一个点到另一个点的随机路径,但是它遵循以下规则:

  • The only chars allowed are: 唯一允许的字符是:
    • O = Open path O =开放路径
    • - = Accepts paths from it's left or from it's right - =接受来自左侧右侧的路径
    • | = Accepts paths from it's top or from it's bottom =接受来自顶部底部的路径
    • \\ = Accepts paths from: top to left , left to top , bottom to right , and right to bottom. \\ =接受来自路径: 顶部 顶部底部至底部。
    • / = Accepts paths from: bottom to left , left to bottom , right to top , and top to right / =接受来自路径: 底部 底部右侧 顶部 ,和顶部
    • "Accepts paths" means that other paths ( /-|\\ ) can only connect from the sides speficied. “接受路径”意味着其他路径( /-|\\ )只能从特定的边连接。

Here's an image to understand the chars and what they do: ( - in red, \\ in blue, / in green, | in orange) 下面是一个图片来了解字符和他们做了什么:( -红色, \\蓝色, /在绿色|橙色)

字符及其含义。

  • The path cannot cross over itself - it can only go in open places (Open paths: O ). 路径不能越过自己 - 它只能进入开放的地方(开放路径: O )。 Imagine the outcome path as snake, the beloved game - it cannot go through itself. 想象一下结果路径就像蛇,这个心爱的游戏 - 它无法通过它自己。
  • The 2d array can be any size 2d阵列可以是任何大小
  • The ending can lead anywhere - It isn't marked with X or any character like it, but it has to go somewhere logical. 结尾可以在任何地方引导 - 它没有标记X或任何类似的角色,但它必须符合逻辑。

Correct outputs: 正确的产出:

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

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

The first example is basically this: 第一个例子基本上是这样的: 第一个例子作为图像。

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

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

The second example is basically this: 第二个例子基本上是这样的: 第二个例子作为图像。

I'm trying to accompilsh this using this code, but for some reason, it's not working: 我试图使用此代码来完成此操作,但由于某种原因,它无法正常工作:

Code: 码:

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;
}

When I run the code using this code, 当我使用此代码运行代码时,

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);
    }
}

It keeps outputting wrong & illogical paths, such as: 它不断输出错误和不合逻辑的路径,例如:

OOOO
O/OO
O-OO
O-OO

Or (with map size 6): 或者(地图大小为6):

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

I don't know why this happens. 我不知道为什么会这样。 Can anyone tell me what's wrong with my code and help me solve this? 谁能告诉我我的代码有什么问题并帮我解决这个问题?

Thanks in advance! 提前致谢!

PS: Before you ask, no, this is not a homework question. PS:在你问之前,不,这不是一个功课问题。

EDIT: I updated my code, and now the method does return true and it reaches the ending, but there's a problem. 编辑:我更新了我的代码,现在该方法确实返回true并且它到达结尾,但是有一个问题。 My updated code: 我的更新代码:

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;
}

My main code: 我的主要代码:

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();
    }

I can see in the output that it reaches it's final destenation, but it doesn't show the beginning. 我可以在输出中看到它到达它的最终destenation,但它没有显示开始。 Why is that? 这是为什么?

Here are some example outputs from the new, updated code: 以下是新更新代码的一些示例输出:

OOOO
O/OO
O/OO
O---

OOOO
O//-
OO/O
OOO|

As you can see, the outputs still dont make sense, but it's closer than before :P It doesn't exactly follow the rules and it doesn't show the beginning. 正如你所看到的,输出仍然没有意义,但它比以前更接近:P它并不完全遵循规则而且它没有显示开始。 Why is that? 这是为什么?

I see several mistakes (I didn't run your code). 我看到几个错误(我没有运行你的代码)。

1.Main problem is that you probably mixed x and y coordinates in the your logic and output to the screen, try to change 1.主要问题是你可能在你的逻辑中混合x和y坐标并输出到屏幕,尝试改变

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

to something like 喜欢的东西

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

Ie change looping through x and y coordinates for output 即改变循环通过x和y坐标输出

2.You probably incorrectly calculate next coordinates from x,y in function avilableMovement. 你可能在函数avilableMovement中错误地计算了x,y的下一个坐标。 lx and ly already contains x and y , ie you add x and y 2 times in x+lx , y+ly : lxly已经包含xy ,即你在x+lxy+ly添加xy 2次:

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);
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};

3.You don't return 'O' mark for cell if path is not finded in current cell, and you don't check next possible move: 3.如果当前单元格中未找到路径,则不返回单元格的“O”标记,并且不检查下一个可能的移动:

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

Here's another idea for your consideration. 这是您考虑的另一个想法。 Starting with a simple path, for example, straight along the x-axis then straight along the y-axis (or vice versa) from start to end, 从一条简单的路径开始,例如,沿着x轴直线然后沿着y轴直线(或反之亦然)从开始到结束,

start--\
       |
       |    
       |
       \end

we can modify the path using a pre-set dictionary of options. 我们可以使用预先设置的选项字典来修改路径。 For any one cell that is between two others in the path (which excludes the start and end cells) we define 6 possibilities, each with two ways to modify it. 对于路径中两个其他单元格之间的任何一个单元格(不包括起始单元格和结束单元格),我们定义了6种可能性,每种可能性都有两种方法来修改它。 In the following two examples, we are concerned only with modifying the middle cell, x : 在以下两个示例中,我们只关注修改中间单元格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 /

Since cells cannot be connected via diagonals, there are only 4 choose 2 = 6 configurations to consider. 由于细胞不能通过对角线连接,因此只有4 choose 2 = 6配置需要考虑。 We can easily create a dictionary of options to randomly try, based on delta configurations of cells in the path. 我们可以根据路径中单元格的增量配置轻松创建随机尝试的选项字典。 The two examples above would be: 上面的两个例子是:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM