随机迷宫生成算法——深度优先算法

迷宫是我们小时候经常玩的游戏,如何用代码来快速生成上面这种迷宫呢?

迷宫算法有三大算法:深度优先算法、prim算法和递归分割算法。这里用的是深度优先算法,在此说一下算法思路,希望对各位有所帮助。

 

首先我的假设是,迷宫只有一条正确的道路。

这个时候请把自己想象成一只地鼠,要在这个区域不停的挖,直到任何一块区域再挖就会挖穿了为止。

我们挖的道路就像树结构,树上有很多的分支,分支也有子分支,每个子分支都不能相交,相交了就说明墙被挖穿了,那么此时的迷宫就可能存在多条正确道路,这不是我想看到的。

那么基于唯一道路的原则,我们向某个方向挖一块新的区域时,要先判断新区域是否有挖穿的可能,如果可能挖穿要立即停止并换个方向再挖。如图:

如图所示,挖之前要确保上下左右四个位置中只有一个位置是路。了解了这一规则以后,就可以上代码了:

#include<stdio.h>
#include<Windows.h>
#include<time.h>
#include<math.h>

//地图长度L,包括迷宫主体40,外侧的包围的墙体2,最外侧包围路径2(之后会解释)
#define L 44

//墙和路径的标识
#define WALL  0
#define ROUTE 1

//控制迷宫的复杂度,数值越大复杂度越低,最小值为0
static int Rank = 0;

//生成迷宫
void CreateMaze(int **maze, int x, int y);

int main(void) {
	srand((unsigned)time(NULL));

	int **Maze = (int**)malloc(L * sizeof(int *));
	for (int i = 0; i < L; i++) {
		Maze[i] = (int*)calloc(L, sizeof(int));
	}

	//最外围层设为路径的原因,为了防止挖路时挖出边界,同时为了保护迷宫主体外的一圈墙体被挖穿
	for (int i = 0; i < L; i++){
		Maze[i][0] = ROUTE;
		Maze[0][i] = ROUTE;
		Maze[i][L - 1] = ROUTE;
		Maze[L - 1][i] = ROUTE;
	}

	//创造迷宫,(2,2)为起点
	CreateMaze(Maze, 2, 2);

	//画迷宫的入口和出口
	Maze[2][1] = ROUTE;

	//由于算法随机性,出口有一定概率不在(L-3,L-2)处,此时需要寻找出口
	for (int i = L - 3; i >= 0; i--) {
		if (Maze[i][L - 3] == ROUTE) {
			Maze[i][L - 2] = ROUTE;
			break;
		}
	}

	//画迷宫
	for (int i = 0; i < L; i++) {
		for (int j = 0; j < L; j++) {
			if (Maze[i][j] == ROUTE) {
				printf("  ");
			}
			else {
				printf("国");
			}
		}
		printf("\n");
	}

	for (int i = 0; i < L; i++) free(Maze[i]);
	free(Maze);

	system("pause");
	return 0;
}

void CreateMaze(int **maze, int x, int y) {
	maze[x][y] = ROUTE;

	//确保四个方向随机
	int direction[4][2] = { { 1,0 },{ -1,0 },{ 0,1 },{ 0,-1 } };
	for (int i = 0; i < 4; i++) {
		int r = rand() % 4;
		int temp = direction[0][0];
		direction[0][0] = direction[r][0];
		direction[r][0] = temp;

		temp = direction[0][1];
		direction[0][1] = direction[r][1];
		direction[r][1] = temp;
	}

	//向四个方向开挖
	for (int i = 0; i < 4; i++) {
		int dx = x;
		int dy = y;

		//控制挖的距离,由Rank来调整大小
		int range = 1 + (Rank == 0 ? 0 : rand() % Rank);
		while (range>0) {
			dx += direction[i][0];
			dy += direction[i][1];

			//排除掉回头路
			if (maze[dx][dy] == ROUTE) {
				break;
			}

			//判断是否挖穿路径
			int count = 0;
			for (int j = dx - 1; j < dx + 2; j++) {
				for (int k = dy - 1; k < dy + 2; k++) {
					//abs(j - dx) + abs(k - dy) == 1 确保只判断九宫格的四个特定位置
					if (abs(j - dx) + abs(k - dy) == 1 && maze[j][k] == ROUTE) {
						count++;
					}
				}
			}

			if (count > 1) {
				break;
			}

			//确保不会挖穿时,前进
			--range;
			maze[dx][dy] = ROUTE;
		}

		//没有挖穿危险,以此为节点递归
		if (range <= 0) {
			CreateMaze(maze, dx, dy);
		}
	}
}

算法的资源消耗较大,因此我设置了Rank来降低复杂度,但因此也会使得迷宫变得非常简单,在平衡中做取舍吧。

随机迷宫生成算法——prime算法

随机迷宫生成算法——递归分割算法

防止各位没看明白,重新写了篇,个人觉得讲的更详细点

  • 59
    点赞
  • 298
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
生成迷宫的一种常见算法是基于深度优先遍历的随机迷宫生成算法。该算法的基本思路是从一个起始点出发,随机选择一个相邻的未被访问过的点,将其标记为已访问,并将两点之间的墙壁打通。然后以新访问的点为起点继续随机选择未访问过的点,直到所有的点都被访问过。 在Java中,可以使用二维数组表示迷宫地图。数组中的每个元素表示一个格子,可以包含四面墙壁状态的信息(例如用0表示墙壁存在,用1表示墙壁不存在),以及是否被访问过的信息(例如用0表示未被访问过,用1表示已被访问过)。以下是一个基于深度优先遍历的随机迷宫生成算法示例代码: ``` java import java.util.Random; public class MazeGenerator { private int width; // 迷宫宽度 private int height; // 迷宫高度 private int[][] maze; // 迷宫地图 private Random random; // 随机生成器 // 构造函数 public MazeGenerator(int width, int height) { this.width = width; this.height = height; maze = new int[height][width]; random = new Random(); generateMaze(0, 0); // 从左上角的格子开始生成迷宫 } // 生成迷宫 private void generateMaze(int row, int col) { maze[row][col] = 1; // 标记当前格子已访问过 // 随机顺序访问邻居格子 int[] directions = {0, 1, 2, 3}; // 上、右、下、左 shuffle(directions); // 随机打乱顺序 for (int direction : directions) { int newRow = row; int newCol = col; switch (direction) { case 0: // 上 newRow--; break; case 1: // 右 newCol++; break; case 2: // 下 newRow++; break; case 3: // 左 newCol--; break; } // 判断新格子是否在迷宫范围内且未被访问过 if (newRow >= 0 && newRow < height && newCol >= 0 && newCol < width && maze[newRow][newCol] == 0) { // 打通两格之间的墙壁 if (direction == 0) { // 上 maze[row][col] &= ~1; // 当前格子的上墙壁打通 maze[newRow][newCol] &= ~4; // 新格子的下墙壁打通 } else if (direction == 1) { // 右 maze[row][col] &= ~2; // 当前格子的右墙壁打通 maze[newRow][newCol] &= ~8; // 新格子的左墙壁打通 } else if (direction == 2) { // 下 maze[row][col] &= ~4; // 当前格子的下墙壁打通 maze[newRow][newCol] &= ~1; // 新格子的上墙壁打通 } else if (direction == 3) { // 左 maze[row][col] &= ~8; // 当前格子的左墙壁打通 maze[newRow][newCol] &= ~2; // 新格子的右墙壁打通 } generateMaze(newRow, newCol); // 递归访问新格子 } } } // 随机打乱数组元素的顺序 private void shuffle(int[] array) { for (int i = array.length - 1; i > 0; i--) { int j = random.nextInt(i + 1); int temp = array[i]; array[i] = array[j]; array[j] = temp; } } // 打印迷宫地图 public void printMaze() { for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { System.out.print(maze[i][j] + " "); } System.out.println(); } } // 测试代码 public static void main(String[] args) { MazeGenerator generator = new MazeGenerator(10, 10); generator.printMaze(); } } ``` 运行上述代码,可以生成一个10x10的迷宫地图,并打印出来。你可以根据自己的需要修改迷宫大小,或者将迷宫地图保存为图片等。
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值