①基于rank优化的并查集,用来检测两点是否相连,提高根节点查找效率
②最小生成树,通过随机权值,生成一个随机迷宫
可以初始化一个网格地图,然后逐渐打通其中的墙,这里以5*5网格为例,“ ”表示结点,“#”表示墙;
打通前:
可以看出,这里一共有25个结点,如果要形成迷宫,需要打破24堵结点之间的墙;
创建边Edge类,存储边的起点和终点以及权值,每个结点只和自己在网格地图里上下左右相邻结点之间存在带权边,所以这里一共有5*4*2条带权边,权值随机在0~99999之间,然后存储根据Kruskal算法得到最小生成树(每个结点都与其他结点连通并且树的总权值最小)里的每一条边;根据边集合可以知道需要打通那些结点之间的墙,打通完24堵墙,迷宫生成完毕。
打通后:
边Edge类:
主要用来存储结点与结点之间的权值,start起点,end终点,value边的权值
package 自动生成迷宫;
public class Edge{
int start;
int end;
int value;
public Edge(){
}
public Edge(int start,int end,int value){
this.start = start;
this.end = end;
this.value = value;
}
}
并查集Union类:
主要用来检测两个结点是否连通,连接两个结点,查找指定结点的根节点
package 自动生成迷宫;
public class Union {
int count;
int[] parent;//记录根节点
int[] rank;//层数
public Union(int count){
this.count = count;
parent = new int[count];
rank = new int[count];
for(int i=0;irank[qRoot]){
parent[qRoot] = pRoot;
}else{
parent[pRoot] = qRoot;
rank[qRoot]++;
}
}
}
地图工具MapUtil类
用来生成迷宫数组,实现过程略复杂,简单的划分可以分为以下几步;
①先将网格地图中最上面横边和最左边纵边涉及到的边添加到list中;
②遍历网格中剩下的结点,将其与相邻左边和相邻上面两个结点相连的两条边添加到list中,完成对网格所有结点带权边的信息存储;
③利用Kruskal得到最小生成树,将树中的每条边添加到map中;
④声明大小为(2*row+1)*(2*col+1)的二维数组,用来存储迷宫信息,值为1代表墙,值为-1代表通道;先对每个结点所在位置留空(网格结点分布在奇数行、奇数列上);然后从网格数组的第2列开始对每个结点右侧的墙进行初始化(最左侧的墙先不管);再对网格地图横向铺满的墙(偶数行)进行初始化;最后对最左侧的纵向墙初始化,完成网格墙效果(未连通状态)
⑤对网格墙进行打通:遍历map,得到需要打通的边edge,通过edge可以得到边起点和边终点的结点编号;如果两点相差1,说明左右连通,否则上下连通;start/列数col得到start在纯结点构成的网格中是第x行,start%列数col得到start在纯结点构成的网格中是第y列;在这里保证了start编号一定比end小,如果是左右连通,array1[2*x+1][2*y+2]置空,如果是上下连通,array1[2*x+2][2*y+1]置空(原因:array1在第④步结束时,已经构成了未连通网格地图,在这里只需要对墙进行打通操作就可以了);返回数组array1得到迷宫信息。
package 自动生成迷宫;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class MapUtil {
Union unionUtil;
ArrayList list;
ArrayList map;
int row;
int col;
public MapUtil(int row,int col){
this.row = row;
this.col = col;
unionUtil = new Union(row*col);
list = new ArrayList();
map = new ArrayList();
init();
}
public void init(){
for(int i=0;i() {
@Override
public int compare(Edge o1, Edge o2) {
if(o1.value
面板GamePanel类:
获取图片并显示迷宫
package 自动生成迷宫;
import java.awt.*;
import javax.swing.*;
public class GamePanel extends JPanel{
int[][] map;
MapUtil mapUtil;
int row,col;
int leftX,leftY;
public GamePanel(int row,int col){
this.row = row;
this.col = col;
leftX = 0;
leftY = 0;
mapUtil = new MapUtil(row, col);
map = mapUtil.getMap();
setPreferredSize(new Dimension((col*2+1)*20,(row*2+1)*20));
}
public void paint(Graphics g){
Image image = Toolkit.getDefaultToolkit().getImage("D:/Game/pic1.png");
for(int i=0;i<2*row+1;i++){
for(int j=0;j<2*col+1;j++){
if(map[i][j]!=-1)
g.drawImage(image, leftX+20*j, leftY+20*i, 20, 20,this);
}
}
}
}
窗体Main类:
package 自动生成迷宫;
import javax.swing.JFrame;
public class Main extends JFrame{
public Main(){
this.getContentPane().add(new GamePanel(20, 30));
pack();
setVisible(true);
}
public static void main(String[] args) {
new Main();
}
}
生成一个20行30列的迷宫
墙的素材应该放置在 D://Game路径下,命名为pic1.png;
迷宫可以根据自己需要,在自己指定位置添加入口和出口,修改数组指定位置的值就可以。