簡體   English   中英

java - 在2d char數組中生成隨機路徑的算法

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

我正在嘗試在二維char數組中生成從一個點到另一個點的隨機路徑,但是它遵循以下規則:

  • 唯一允許的字符是:
    • O =開放路徑
    • - =接受來自左側右側的路徑
    • | =接受來自頂部底部的路徑
    • \\ =接受來自路徑: 頂部 頂部底部至底部。
    • / =接受來自路徑: 底部 底部右側 頂部 ,和頂部
    • “接受路徑”意味着其他路徑( /-|\\ )只能從特定的邊連接。

下面是一個圖片來了解字符和他們做了什么:( -紅色, \\藍色, /在綠色|橙色)

字符及其含義。

  • 路徑不能越過自己 - 它只能進入開放的地方(開放路徑: O )。 想象一下結果路徑就像蛇,這個心愛的游戲 - 它無法通過它自己。
  • 2d陣列可以是任何大小
  • 結尾可以在任何地方引導 - 它沒有標記X或任何類似的角色,但它必須符合邏輯。

正確的產出:

開始:(0,0),結束:(3,3)

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

第一個例子基本上是這樣的: 第一個例子作為圖像。

開始:(1,0),結束:(1,4)

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

第二個例子基本上是這樣的: 第二個例子作為圖像。

我試圖使用此代碼來完成此操作,但由於某種原因,它無法正常工作:

碼:

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

它不斷輸出錯誤和不合邏輯的路徑,例如:

OOOO
O/OO
O-OO
O-OO

或者(地圖大小為6):

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

我不知道為什么會這樣。 誰能告訴我我的代碼有什么問題並幫我解決這個問題?

提前致謝!

PS:在你問之前,不,這不是一個功課問題。

編輯:我更新了我的代碼,現在該方法確實返回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它並不完全遵循規則而且它沒有顯示開始。 這是為什么?

我看到幾個錯誤(我沒有運行你的代碼)。

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坐標輸出

你可能在函數avilableMovement中錯誤地計算了x,y的下一個坐標。 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.如果當前單元格中未找到路徑,則不返回單元格的“O”標記,並且不檢查下一個可能的移動:

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

這是您考慮的另一個想法。 從一條簡單的路徑開始,例如,沿着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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM