算法学习笔记:随机迷宫

随机迷宫

  • 迷宫生成算法也有很多种,也正是由于结果随机,反过来讲就意味着该问题由无数种解,所以它完全可以利用回溯的思想。
  • 常见算法由三种:
    • 十字分割法
    • 随机prim算法
    • 深度优先算法

十字分割法

  1. 先画一个十字分成四个部分
  2. 在三面墙上打洞
  3. 再在每个子部分中重复这一步骤,直至空间不够分割(这个值需要我们自行设置)

十字分割法生成的迷宫会形成一个一个大小不一的房间,适合制作RPG游戏地图。

代码

import java.util.Random;

public class RandomMaze {
	
	private int row, col;
	
	private Random random;
	
	private boolean[][] maze;
	
	RandomMaze(int row, int col) {
		
		this.row = row;
		this.col = col;
		this.random = new Random();
		this.maze = initialMaze();
	}
	
	/**
	 * 根据给定的高和宽生成一个初始迷宫,初始迷宫只是在没有任何阻碍的迷宫外侧添加一圈墙壁
	 */
	private boolean[][] initialMaze() {
		
		if (row % 2 == 0 || col % 2 == 0) {
			System.out.println("必须为奇数");
			return null;
		}
		boolean[][] m = new boolean[this.row][this.col];
		for (int i = 0; i < this.col; i++) {
			m[0][i] = true;
			m[this.row - 1][i] = true;
		}
		for (int i = 0; i < this.row; i++) {
			m[i][0] = true;
			m[i][this.col - 1] = true;
		}
		return m;
	}
	
	public void makeMaze() {
		
		drawMaze(1, 1, this.row - 2, this.col - 2);
	}
	
	/**
	 * 迷宫生成算法,采用递归方式实现,随机画横竖两条线,然后在线上随机开门
	 * 左上角为入口
	 * 右下角为出口
	 * 墙的坐标只能是偶数,路的坐标只能是奇数,如何保证奇偶是本算法的难点
	 */
	private void drawMaze(int row1, int col1, int row2, int col2) {
		
		if (row1 == row2 || col1 == col2) return;
		
		int row3, col3;
		
		//横着画线,在偶数位置画线
		row3 = row1 + random.nextInt((row2 - row1) / 2) * 2 + 1;
		for (int i = col1; i <= col2; i++) {
			maze[row3][i] = true;
		}
		
		//竖着画一条线,在偶数位置画线
		col3 = col1 + random.nextInt((col2 - col1) / 2) * 2 + 1;
		for (int i = row1; i <= row2; i++) {
			maze[i][col3] = true;
		}
		
		//开门
		switch (random.nextInt(4)) {
			case 0:
				//digging(row3, col1, row3, col3 - 1);//left
				digging(row3 + 1, col3, row2, col3);//down
				digging(row3, col3 + 1, row3, col2);//right
				digging(row1, col3, row3, col3);//up
				break;
			case 1:
				digging(row3, col1, row3, col3 - 1);//left
				//digging(row3 + 1, col3, row2, col3);//down
				digging(row3, col3 + 1, row3, col2);//right
				digging(row1, col3, row3, col3);//up
				break;
			case 2:
				digging(row3, col1, row3, col3 - 1);//left
				digging(row3 + 1, col3, row2, col3);//down
				//digging(row3, col3 + 1, row3, col2);//right
				digging(row1, col3, row3, col3);//up
				break;
			case 3:
				digging(row3, col1, row3, col3 - 1);//left
				digging(row3 + 1, col3, row2, col3);//down
				digging(row3, col3 + 1, row3, col2);//right
				//digging(row1, col3, row3, col3);//up
				break;
			
			default:
				break;
		}
		
		//递归
		//左上角
		drawMaze(row1, col1, row3 - 1, col3 - 1);
		//右上角
		drawMaze(row1, col3 + 1, row3 - 1, col2);
		//右下角
		drawMaze(row3 + 1, col3 + 1, row2, col2);
		//左下角
		drawMaze(row3 + 1, col1, row2, col3 - 1);
	}
	
	/**
	 * 从起点到终点随机打一个洞,道路坐标只能是奇数
	 */
	private void digging(int x1, int y1, int x2, int y2) {
		
		int pos;
		if (x1 == x2) {//横线打洞,坐标只能是奇数
			pos = y1 + random.nextInt((y2 - y1) / 2 + 1) * 2;
			maze[x1][pos] = false;
		}
		if (y1 == y2) {//竖线打洞
			pos = x1 + random.nextInt((x2 - x1) / 2 + 1) * 2;
			maze[pos][y1] = false;
		}
	}
	
	public void showMaze() {
		
		for (int i = 0; i < maze.length; i++) {
			for (int j = 0; j < maze[i].length; j++) {
				System.out.print((this.maze[i][j]) ? "X " : "  ");
			}
			System.out.println();
		}
	}
	
	public static void main(String[] args) {
		
		RandomMaze rMaze = new RandomMaze(21, 23);//设置迷宫大小
		if (rMaze.maze != null) {
			rMaze.makeMaze();
			rMaze.showMaze();
		}
	}
}

重点理解

  1. 十字分割法是递归算法,不是回溯算法,这里注意体会一下。
  2. 我们规定整个迷宫最外围由墙壁包裹,所以迷宫的长与宽必须是奇数,且最小的大小是3X3
  3. 墙的坐标只能是偶数,路的坐标只能是奇数,如何保证奇偶是本算法的难点
  4. 如果每次递归都只在三面墙上打洞,则迷宫走法只有一个解,这在实际应用中意义不大,如果想要有多种走法,降低迷宫难度,则可以考虑有时候在四面墙上打洞,使得迷宫存在回路。

结果

X X X X X X X X X X X X X X X X X X X X X X X 
                                    X       X 
X X X X X X X X X X X X X X X   X X X   X   X 
X                                       X   X 
X X X X X   X X X X X X X X X X X X X X X X X 
X   X       X           X           X       X 
X   X X X   X X X   X X X X X X X   X   X   X 
X                                       X   X 
X X X X X X X X X X X X X X X X X   X   X   X 
X   X   X   X   X           X   X   X   X   X 
X   X   X   X   X   X   X   X   X   X   X   X 
X   X   X   X   X   X   X   X       X   X   X 
X   X   X   X   X X X   X   X X X   X   X   X 
X           X           X           X   X   X 
X   X   X X X   X   X X X X X X X   X X X   X 
X   X       X   X       X           X   X   X 
X   X   X X X   X X X X X X X X X   X   X   X 
X   X   X   X   X                   X       X 
X   X   X   X   X X X X X X X   X X X   X   X 
X   X           X                   X   X     
X X X X X X X X X X X X X X X X X X X X X X X 
发布了45 篇原创文章 · 获赞 46 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/founderznd/article/details/89683170
今日推荐