很久以前,同事问我要一个随机迷宫的算法,我参考下列链接的启发,也是按照图的深度优先遍历算法,用java写了一个。后来增强为3D版。在这里标记一下,有时间就改为C语言版。
http://hi.baidu.com/%B4%F4%BA%CD%B9%D4%B5%C4%D0%A1%CC%EC%B5%D8/blog/item/98af8518e37c05b04aedbca6.html
2D版的效果图:
3D版在平面显示不出来,就不贴了。
以下分别是2D版和3D版的代码,暂时没有太多注释, C语言版再加注释, 可以参考上面的链接。
package com.gzyui.maze; 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; } }
package com.gzyui.maze; import java.util.Random; 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; /* * constructor, initial width, height and matrix */ public Maze(int width, int height) { this.width = width; this.height = height; this.matrix = new MazePoint[height][width]; for (int i=0; i= 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; } /* * check if the neighbors have at least one non-visited point */ 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)); } /* * pick up a random traversal direction * loop until find a correct one */ 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) ); } return dir; } /* * push down the wall between the adjacent two points */ 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; } } /* * depth first search traversal */ public void traversal() { int x = 0; int y = 0; Stack stackX = new Stack(); Stack stackY = new Stack(); 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() ); } /* * create the maze by the point matrix * only use the right wall and down wall of every point */ public void create() { for (int j=0; j<2*width+1; j++) maze[0][j] = gridWall; for (int i=0; i stackX = new Stack(); Stack stackY = new Stack(); 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; } /* * remove all foot print in the maze */ 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; } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Maze maze = new Maze(5, 3); maze.traversal(); maze.create(); System.out.println("/nCreate a new map"); maze.print(); maze.findPath(); System.out.println("/nFind path"); maze.print(); maze.reset(); System.out.println("/nReset the map"); maze.print(); } }
package com.gzyui.maze; public class Maze3DPoint { private boolean isVisited = false; private boolean wallUp = true; private boolean wallRight = true; private boolean wallDown = true; private boolean wallLeft = true; private boolean wallFront = true; private boolean wallBack = 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; } public boolean isWallFront() { return wallFront; } public void setWallFront(boolean wallFront) { this.wallFront = wallFront; } public boolean isWallBack() { return wallBack; } public void setWallBack(boolean wallBack) { this.wallBack = wallBack; } }
package com.gzyui.maze; import java.util.Random; import java.util.Stack; public class Maze3D { 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 dirFront = 4; private final static int dirBack = 5; private int width; private int height; private int deep; private Maze3DPoint[][][] matrix; private Stack stackX = new Stack(); private Stack stackY = new Stack(); private Stack stackZ = new Stack(); /* * constructor, initial width, height and matrix */ public Maze3D(int width, int height, int deep) { this.width = width; this.height = height; this.deep = deep; this.matrix = new Maze3DPoint[height][width][deep]; for (int i=0; i= width - 1 ) isNeighborVisited = true; else isNeighborVisited = matrix[x][y+1][z].isVisited(); break; case dirDown: if ( x >= height - 1 ) isNeighborVisited = true; else isNeighborVisited = matrix[x+1][y][z].isVisited(); break; case dirLeft: if ( y <= 0 ) isNeighborVisited = true; else isNeighborVisited = matrix[x][y-1][z].isVisited(); break; case dirFront: if ( z <= 0 ) isNeighborVisited = true; else isNeighborVisited = matrix[x][y][z-1].isVisited(); break; case dirBack: if ( z >= deep - 1 ) isNeighborVisited = true; else isNeighborVisited = matrix[x][y][z+1].isVisited(); break; } return !isNeighborVisited; } /* * check if the neighbors have at least one non-visited point */ public boolean isNeighborOK(int x, int y, int z) { return (this.isNeighborOK(x, y, z, dirUp) || this.isNeighborOK(x, y, z, dirRight) || this.isNeighborOK(x, y, z, dirDown) || this.isNeighborOK(x, y, z, dirLeft) || this.isNeighborOK(x, y, z, dirFront) || this.isNeighborOK(x, y, z, dirBack)); } /* * pick up a random traversal direction * loop until find a correct one */ public int getRandomDir(int x, int y, int z) { int dir = -1; Random rand = new Random(); if ( isNeighborOK(x, y, z) ) { do { dir = rand.nextInt(6); } while ( !isNeighborOK(x, y, z, dir) ); } return dir; } /* * push down the wall between the adjacent two points */ public void pushWall(int x, int y, int z, int dir) { switch ( dir ) { case dirUp: matrix[x][y][z].setWallUp(false); matrix[x-1][y][z].setWallDown(false); break; case dirRight: matrix[x][y][z].setWallRight(false); matrix[x][y+1][z].setWallLeft(false); break; case dirDown: matrix[x][y][z].setWallDown(false); matrix[x+1][y][z].setWallUp(false); break; case dirLeft: matrix[x][y][z].setWallLeft(false); matrix[x][y-1][z].setWallRight(false); break; case dirFront: matrix[x][y][z].setWallFront(false); matrix[x][y][z-1].setWallBack(false); break; case dirBack: matrix[x][y][z].setWallBack(false); matrix[x][y][z+1].setWallFront(false); break; } } /* * depth first search traversal */ public void traversal() { int x = 0; int y = 0; int z = 0; do { Maze3DPoint p = matrix[x][y][z]; if ( !p.isVisited() ) { System.out.println("(" + x + ", " + y + ", " + z + ")"); p.setVisited(true); } if ( isNeighborOK(x, y, z) ) { int dir = this.getRandomDir(x, y, z); this.pushWall(x, y, z, dir); stackX.add(x); stackY.add(y); stackZ.add(z); switch ( dir ) { case dirUp: x--; break; case dirRight: y++; break; case dirDown: x++; break; case dirLeft: y--; break; case dirFront: z--; break; case dirBack: z++; break; } } else { x = stackX.pop(); y = stackY.pop(); z = stackZ.pop(); } } while ( !stackX.isEmpty() ); } /* * display the matrix as a maze * only use the right wall and down wall of every point */ public void printMaze(int z) { for (int j=0; j<2*width+1; j++) System.out.print("W"); System.out.println(); for (int i=0; i