C++实现迷宫生成(基于算法:随机prim)

看一下效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
思路:用到了c++中的vector,看了迷宫的一些算法,发现prim生成的迷宫还是比较好看的,网上的代码python c#居多,而且不太容易搞懂,那我在这里用C++的STL实现了这个目的
prim算法:随机Prim算法生成的迷宫岔路较多,整体上较为自然而又复杂,算法核心为(根据维基百科)。

1.让迷宫全是墙.
2.选一个单元格作为迷宫的通路(我一般选择起点),然后把它的邻墙(上下左右)放入列表
3.当列表里还有墙时
①.从列表里随机选一个墙,如果这面墙分隔的两个单元格只有一个单元格被访问过
(a)那就从列表里移除这面墙,即把墙打通,让未访问的单元格成为迷宫的通路
(b)把这个格子的墙加入列表
②.如果墙两面的单元格都已经被访问过(都打通了),那就从列表里移除这面墙

看代码辅助理解。

#include <bits/stdc++.h>
using namespace std;
#define m 11//row
#define n 11
#define down 1
#define right 2
#define left 4
#define up 8
#define WALL -1
#define NOTHING 2

struct block{
	int row,column,direction;
	block(int _row,int _column,int _direction){
		row = _row;
		column = _column;
		direction = _direction;
	}
};
struct point {
	int x;
	int y;
}start,end;

vector<block> myblock;
int x_num=1,y_num=1;//矿工位置
int G[100][100];

void init() {
	//将地图全部置为墙
	memset(G,WALL,sizeof(G));
	//定义起始点
	G[1][1] = NOTHING;
	start.x = start.y = 1;
}
void FindBlock() {
	//找出与当前位置相邻的墙
	if(x_num+1<=m && G[x_num+1][y_num] == WALL) {//down
		myblock.push_back(block(x_num+1,y_num,down));
	}
	if(y_num+1<=n && G[x_num][y_num+1] == WALL) {//right
		myblock.push_back(block(x_num,y_num+1,right));
	}
	if(x_num-1>=1 && G[x_num-1][y_num] == WALL) {//up
		myblock.push_back(block(x_num-1,y_num,up));
	}
	if(y_num-1>=1 && G[x_num][y_num-1] == WALL) {//left
		myblock.push_back(block(x_num,y_num-1,left));
	}
}

int main() {
	init();
	srand((unsigned)time(NULL));//随机数种子
	FindBlock();
	//第一步压入两堵墙(起点右边和起点下面)进入循环
	while(myblock.size()) {
		int BlockSize = myblock.size();
		//随机选择一堵墙(生成0 ~ BlockSize-1之间的随机数,同时也是vector里墙的下标)
		int randnum = rand() % BlockSize;
		block SelectBlock = myblock[randnum];
		x_num = SelectBlock.row;//矿工来到我们“选择的墙”这里
		y_num = SelectBlock.column;
		//根据当前选择的墙的方向进行后续操作
		//此时,起始点 选择的墙 目标块 三块区域在同一直线上
		//我们让矿工从“选择的墙”继续前进到“目标块”
		//矿工有穿墙能力 :)
		switch(SelectBlock.direction) {
			case down: {
				x_num++;
				break;
			}
			case right: {
				y_num++;
				break;
			}
			case left: {
				y_num--;
				break;
			}
			case up: {
				x_num--;
				break;
			}
		}
		//目标块如果是墙
		if(G[x_num][y_num]==WALL) {
			//打通墙和目标块
			G[SelectBlock.row][SelectBlock.column] = G[x_num][y_num] = NOTHING;
			//再次找出与矿工当前位置相邻的墙
			FindBlock();
		}
		else{//如果不是呢?说明我们的矿工挖到了一个空旷的通路上面 休息一下就好了
			//relax
		}
		//删除这堵墙(把用不了的墙删了,对于那些已经施工过了不必再施工了,同时也是确保我们能跳出循环)
		myblock.erase(myblock.begin()+randnum);
	}
	for (int i=0;i<=m+1;i++) {
		for (int j=0;j<=n+1;j++) {
			if(i == start.x && j == start.y) {
				printf("%c%c",0xa7,0xb0 );
			} 
			else if(G[i][j] == NOTHING) {
				printf("  ");
			} 
			else {
				printf("%c%c", 0xa8, 0x80);
			}
		}
		printf("\n");
	}
	return 0;
}

细节:起点随你定,终点无法确定 任何空的地方都可以作为终点 你会发现任何两个空的之间都有路可走
m,n需要均为奇数
PS:你可以在纸上模拟一个比较小的图,来理解这个算法,同时,你会发现这个图是没有环的,形成了一个树的结构。

用我的视频辅助理解:请务必看一下代码再看视频。

https://www.bilibili.com/video/BV1364y1u7LV

  • 37
    点赞
  • 144
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
Prim算法: ```java import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.PriorityQueue; import java.util.Set; public class PrimMST { public static List<Edge> primMST(Graph graph) { List<Edge> result = new ArrayList<>(); Set<Integer> visited = new HashSet<>(); PriorityQueue<Edge> pq = new PriorityQueue<>((a, b) -> a.weight - b.weight); visited.add(0); for (Edge e : graph.edges[0]) { pq.offer(e); } while (!pq.isEmpty() && visited.size() < graph.vertices) { Edge e = pq.poll(); if (visited.contains(e.to)) { continue; } visited.add(e.to); result.add(e); for (Edge next : graph.edges[e.to]) { if (!visited.contains(next.to)) { pq.offer(next); } } } return result; } } ``` Kruskal算法: ```java import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class KruskalMST { public static List<Edge> kruskalMST(Graph graph) { List<Edge> result = new ArrayList<>(); UnionFind uf = new UnionFind(graph.vertices); List<Edge> edges = new ArrayList<>(); for (int i = 0; i < graph.vertices; i++) { edges.addAll(graph.edges[i]); } // sort edges by weight Collections.sort(edges, Comparator.comparingInt(a -> a.weight)); for (Edge e : edges) { int root1 = uf.find(e.from); int root2 = uf.find(e.to); if (root1 != root2) { uf.union(root1, root2); result.add(e); } } return result; } } ``` 测试代码: ```java import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.List; public class TestMST { @Test public void testPrim() { Graph g = new Graph(5); g.addEdge(0, 1, 2); g.addEdge(0, 3, 6); g.addEdge(1, 3, 8); g.addEdge(1, 2, 3); g.addEdge(1, 4, 5); g.addEdge(2, 4, 7); g.addEdge(3, 4, 9); List<Edge> result = PrimMST.primMST(g); Assertions.assertEquals(result.size(), 4); Assertions.assertTrue(result.contains(new Edge(0, 1, 2))); Assertions.assertTrue(result.contains(new Edge(1, 2, 3))); Assertions.assertTrue(result.contains(new Edge(1, 4, 5))); Assertions.assertTrue(result.contains(new Edge(0, 3, 6))); } @Test public void testKruskal() { Graph g = new Graph(5); g.addEdge(0, 1, 2); g.addEdge(0, 3, 6); g.addEdge(1, 3, 8); g.addEdge(1, 2, 3); g.addEdge(1, 4, 5); g.addEdge(2, 4, 7); g.addEdge(3, 4, 9); List<Edge> result = KruskalMST.kruskalMST(g); Assertions.assertEquals(result.size(), 4); Assertions.assertTrue(result.contains(new Edge(0, 1, 2))); Assertions.assertTrue(result.contains(new Edge(1, 2, 3))); Assertions.assertTrue(result.contains(new Edge(1, 4, 5))); Assertions.assertTrue(result.contains(new Edge(0, 3, 6))); } } ```
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值