该篇文章接上篇并查集应用——生成随机迷宫, 此时已经可以生成一个任意大小随机的迷宫
但是看起来还缺点什么,对,就是路径,没有路径怎么证明这真的是个迷宫,因此现学现用把路径加上。首先寻路算法属于图论算法,要想寻路先得有图,什么是图,这个就不细讲了,很多专门讲这个的文章,简单的说图就是一些点再加上连接这些点的边就构成了图,只要把迷宫抽象成图就能应用图论算法了。
具体来说每个方格可以看做一个点,相连的方格间有路径,被墙隔开的两格间不连通,也就没有路,简单起见先整一个小迷宫说明问题:
这样看一目了然,假如左上角是起点,右下角是终点,则实际求解的问题是从左上角到右下角的最短路,当然对这类迷宫而言最短路差不多也就是唯一路。
图有了,接下来就该选择寻路算法了,首先我们的迷宫图相连两点之间都是双向互通的,并且都是单位长度,因此这个图就是一个无向无权图,有好几种算法都能达到我们的目的, 可以选择的算法有:
- DFS: 单源最短路算法,俗称深度优先算法,简单暴力,可以处理负权但是不能处理负权环,但是就是遇到大数据会超时。
- BFS: 单源最短路算法,俗称广度优先算法,相比DFS不那么暴力,只能处理无权图
- Dijkstra: 效率比较好的单源最短路算法,不能处理负权图
还有其他的寻路算法就不一一列举了,上面说了我们的图是无权的,因此这三种算法都可以,DFS和BFS编码简单,理解起来也比较容易,Dijkstra相对编码复杂些,但是也比较简单,具体算法原理就不细说了,有很多讲的很好的文章。在这里我们用BFS实现,选择邻接表来存图,具体做法很简单,就是在Square类里加上三个字段:
private Integer dist;
private Square path;
private List<Square> adj = new ArrayList<>();
adj是与该点临接的点的列表,初始为空,随着迷宫生成和墙壁被拆掉,越来越多的点被连通,被连通的两点互相将对方加入到自己的邻接表中:
//装方块的列表
private List<Square> slist = new ArrayList<>();
//更新邻接表
Square square1 = (Square)items.get(wallIndex);
Square square2 = (Square)items.get(otherWallIndex);
square1.addAdj(square2);
square2.addAdj(square1);
具体的BFS算法:
private void findWayByBfs(Square start){
Queue<Square> q = new LinkedList<>();
for (Square s : slist) {
s.setDist(-1);
}
start.setDist(0);
q.offer(start);
while (!q.isEmpty()) {
Square s = q.remove();
for (Square w : s.getAdj()) {
if (w.getDist() == -1) {
w.setDist(s.getDist() + 1);
w.setPath(s);
q.offer(w);
}
}
}
}
这里我们寻路后,要把路径显示出来置成别的颜色,这里置成绿色:
private void printPath(Square end) {
if (end.getPath() != null) {
printPath(end.getPath());
}
Item item = items.get(end.getIndex());
item.setColor("green");
}
在生成迷宫的基础上只加上这些代码就可以完成寻路了,是不是很简单,最终效果:
代码已传到github上:https://github.com/LLuckyHe/RandomLabyrinth.git,感兴趣的小伙伴可以拿来参考。