隨機生成一個迷宮並探索一條路徑的JAVA實現
阿新 • • 發佈:2019-02-11
問題:實現一個隨機迷宮,可以想象是一個二維陣列,入口在左上角,出口在右下角。
要求:
1、不能超過邊界2、路線不能重複,也就是說每個點只能經過一次
3、走出迷宮的路線是隨機生成的,每次生成的路線都應該不一樣4、迷宮的大小可以任意指定,也就是說明二維陣列的大小可以隨意變化
5、最終生成的迷宮需要打印出來
迷宮實體類MazePoint:
public class MazePoint { private boolean isVisited = false; private boolean wallUp = true; private boolean wallRight = true; private boolean wallDown = true; private boolean wallLeft = true; public boolean isVisited() { return isVisited; } public void setVisited(boolean isVisited) { this.isVisited = isVisited; } public boolean isWallUp() { return wallUp; } public void setWallUp(boolean wallUp) { this.wallUp = wallUp; } public boolean isWallRight() { return wallRight; } public void setWallRight(boolean wallRight) { this.wallRight = wallRight; } public boolean isWallDown() { return wallDown; } public void setWallDown(boolean wallDown) { this.wallDown = wallDown; } public boolean isWallLeft() { return wallLeft; } public void setWallLeft(boolean wallLeft) { this.wallLeft = wallLeft; } }
迷宮類Maze:
import java.util.Random; import java.util.Scanner; import java.util.Stack; public class Maze { private final static int dirUp = 0; private final static int dirRight = 1; private final static int dirDown = 2; private final static int dirLeft = 3; private final static int gridWall = 1; private final static int gridEmpty = 0; private final static int gridBlind = -1; private final static int gridPath = 2; private int width; private int height; private MazePoint[][] matrix; private int[][] maze; /* * 構造一個迷宮,初始化迷宮的寬度和高度,同時初始化包含MazePoint的點陣 */ public Maze(int height, int width) { this.width = width; this.height = height; this.matrix = new MazePoint[height][width]; for (int i=0; i<height; i++) for (int j=0; j<width; j++) matrix[i][j] = new MazePoint(); this.maze = new int[2*height+1][2*width+1]; //構建寬為2*height+1、長為2*width+1的迷宮 } /* * 檢查目標點的上下左右的鄰居是否可以被訪問,如果目標點超出界限則視為已被訪問 */ public boolean isNeighborOK(int x, int y, int dir) { boolean isNeighborVisited = false; switch ( dir ) { case dirUp: if ( x <= 0 ) isNeighborVisited = true; //越界視為已被訪問 else isNeighborVisited = matrix[x-1][y].isVisited(); break; case dirRight: if ( y >= width - 1 ) isNeighborVisited = true; else isNeighborVisited = matrix[x][y+1].isVisited(); break; case dirDown: if ( x >= height - 1 ) isNeighborVisited = true; else isNeighborVisited = matrix[x+1][y].isVisited(); break; case dirLeft: if ( y <= 0 ) isNeighborVisited = true; else isNeighborVisited = matrix[x][y-1].isVisited(); break; } return !isNeighborVisited; //若點未被訪問過(isNeighborVisited為false),則返回值為true,表示有鄰居可以被訪問 } /* * 檢查目標點的上下左右是否至少有一個可以訪問 */ public boolean isNeighborOK(int x, int y) { return (this.isNeighborOK(x, y, dirUp) || this.isNeighborOK(x, y, dirRight) || this.isNeighborOK(x, y, dirDown) || this.isNeighborOK(x, y, dirLeft)); } /* * 獲得一個可以被訪問的方向 */ public int getRandomDir(int x, int y) { int dir = -1; Random rand = new Random(); if ( isNeighborOK(x, y) ) { do { dir = rand.nextInt(4); } while ( !isNeighborOK(x, y, dir) ); //(x,y)的dir方向不可被訪問,重新選擇方向 } return dir; } /* * 將相鄰可以訪問的點設定為通路 */ public void pushWall(int x, int y, int dir) { switch ( dir ) { case dirUp: matrix[x][y].setWallUp(false); matrix[x-1][y].setWallDown(false); //將該點與其上面相鄰的點設定通路 break; case dirRight: matrix[x][y].setWallRight(false); matrix[x][y+1].setWallLeft(false); //將該點與其右面相鄰的點設定通路 break; case dirDown: matrix[x][y].setWallDown(false); matrix[x+1][y].setWallUp(false); //將該點與其下面相鄰的點設定通路 break; case dirLeft: matrix[x][y].setWallLeft(false); matrix[x][y-1].setWallRight(false); //將該點與其左面相鄰的點設定通路 break; } } /* * 深度優先遍歷 */ public void traversal() { int x = 0; int y = 0; Stack<Integer> stackX = new Stack<Integer>(); Stack<Integer> stackY = new Stack<Integer>(); do { MazePoint p = matrix[x][y]; if ( !p.isVisited() ) { p.setVisited(true); } if ( isNeighborOK(x, y) ) { int dir = this.getRandomDir(x, y); //獲得一個隨機可訪問的方向 this.pushWall(x, y, dir); //設定通路 stackX.add(x); //儲存座標資訊 stackY.add(y); //儲存座標資訊 switch ( dir ) { case dirUp: x--; break; case dirRight: y++; break; case dirDown: x++; break; case dirLeft: y--; break; } } else { x = stackX.pop(); y = stackY.pop(); } } while ( !stackX.isEmpty() ); } /* * 根據MazePoint點陣右側和下側的牆構建迷宮 */ public void create() { // } /* * 列印迷宮 */ public void print() { for (int i=0; i<2*height+1; i++) { for (int j=0; j<2*width+1; j++) if ( maze[i][j] == gridWall ) System.out.print("□"); else if ( maze[i][j] == gridPath ) System.out.print("."); //通路標記為".",其他設定為"□" else System.out.print("□"); System.out.println(); } } /* * 在迷宮陣列中去獲得一個訪問的方向 */ public int getBreakOutDir(int x, int y) { int dir = -1; if ( maze[x][y+1] == 0 ) dir = dirRight; else if ( maze[x+1][y] == 0 ) dir = dirDown; else if ( maze[x][y-1] == 0 ) dir = dirLeft; else if ( maze[x-1][y] == 0 ) dir = dirUp; return dir; } /* * 找到從點 (1, 1) 到點 (2*height-1, 2*width-1) 的一條路徑 */ public void findPath() { int x = 1; int y = 1; Stack<Integer> stackX = new Stack<Integer>(); Stack<Integer> stackY = new Stack<Integer>(); do { int dir = this.getBreakOutDir(x, y); if ( dir == -1 ) { maze[x][y] = gridBlind; //方向不存在的設定為盲點 x = stackX.pop(); y = stackY.pop(); } else { maze[x][y] = gridPath; stackX.add(x); stackY.add(y); //儲存通路點座標資訊 switch ( dir ) { case dirUp: x--; break; case dirRight: y++; break; case dirDown: x++; break; case dirLeft: y--; break; } } } while ( !(x == 2*height-1 && y == 2*width-1) ); maze[x][y] = gridPath; } /* * 清除迷宮中的路徑 */ public void reset() { for (int i=0; i<2*height+1; i++) for (int j=0; j<2*width+1; j++) if ( maze[i][j] != gridWall ) maze[i][j] = gridEmpty; } }
測試的main類:
public static void main(String[] args) { // TODO Auto-generated method stub Scanner scanner = new Scanner(System.in); System.out.println("請輸入n:迷宮的行數為2n+1(包括上下兩道牆)"); int row = scanner.nextInt(); System.out.println("請輸入m:迷宮的列數為2m+1"); int col = scanner.nextInt(); Maze maze = new Maze(row, col); maze.traversal(); //遍歷 maze.create(); //構建迷宮 maze.findPath(); //找到路徑 maze.print(); //列印迷宮 maze.reset(); //清除迷宮 }
執行截圖: