一、 实验要求
1、迷宫随机生成
2、玩家走迷宫,留下足迹
3、系统用A*算法寻路,输出路径
二、前期准备
解决迷宫问题要用到两个算法,深度优先遍历(DFS)生成迷宫,A*算法寻路。那么首先要对这两种算法有清晰的了解。
1.深度优先遍历(DFS)
基于深度优先遍历的随机迷宫生成,我自己的理解简而言之可以分为以下几步:
a. 建立一张地图,用二维数组表示,地图上全是障碍物。然后再创建一个用来表示每个格子是否被访问过的二维数组。再创建一个用来表示路径的栈结构。
b.随机选择地图上的一点,为了方便我初始点直接取的是左上角即坐标表示为(0,0)的格子。终点的话因为不涉及到交互就暂时没有。
c.查找当前格子的邻接格(注意,这里的邻接格子都是还未被访问的)。随机选择一个邻接格子为下一 格,当前格移动到下一格,标记当前格为已访问,将当前格压入路径栈中。一直重复第三步操作。
d.在第三步操作中,如果当前格子不存在可访问的邻接格,则将栈顶的元素弹出,即退回上一步操作,如果栈为空,则结束程序,打印结果。
2.A*算法
公式表示为: f(n)=g(n)+h(n),
其中, f(n) 是从初始状态经由状态n到目标状态的代价估计,
g(n) 是在状态空间中从初始状态到状态n的实际代价,
h(n) 是从状态n到目标状态的最佳路径的估计代价。
(对于路径搜索问题,状态就是图中的节点,代价就是距离)
三、代码展示
AStart类:
import java.util.ArrayList;
import java.util.List;
class AStart {
public static int[][] NODES;//定义一个迷宫单元数组
public int STEP = 10;//设每一步的权值为10
private ArrayList<Node> openList = new ArrayList<Node>();//维护一个开放列表
private ArrayList<Node> closeList = new ArrayList<Node>();//维护一个关闭列表
public AStart() {
NODES=Maze.LabId;//初始化迷宫单元为新生成的对应地图,把Maze2类里面生成的地图传给NODES,再在此地图基础上用A*算法寻路径
Node startNode = new Node(1, 1);//起点
Node endNode = new Node(19, 19);//终点
Node parent = findPath(startNode, endNode); //父节点
ArrayList<Node> arrayList = new ArrayList<Node>();
while (parent != null) {
arrayList.add(new Node(parent.x, parent.y));
parent = parent.parent;
}
//打印有路径的地图,在控制台输出查看
System.out.println("\n"+"打印有路径的地图:");
for (int i = 0; i < NODES.length; i++) {
for (int j = 0; j < NODES.length; j++) {
if (exists(arrayList, i, j)) {
NODES[i][j]=2;//标记关闭列表里的方格为2,为了方便后面在界面画系统寻路路径
}
System.out.print(NODES[i][j] + " ");
}
System.out.println();
}
}
//寻找开放列表里F值最小的节点的方法
public Node findMinFNodeInOpneList() {
Node tempNode = openList.get(0);
for (Node node : openList) {
if (node.F < tempNode.F) {
tempNode = node;
}
}
return tempNode;
}
//遍历当前节点上下左右四个邻居的方法,
public ArrayList<Node> findNeighborNodes(Node currentNode) {
ArrayList<Node> arrayList = new ArrayList<Node>();
// 只考虑上下左右,不考虑斜对角
int topX = currentNode.x;
int topY = currentNode.y - 1;
if (canReach(topX, topY) && !exists(closeList, topX, topY)) {
arrayList.add(new Node(topX, topY));
}
int bottomX = currentNode.x;
int bottomY = currentNode.y + 1;
if (canReach(bottomX, bottomY) && !exists(closeList, bottomX, bottomY)) {
arrayList.add(new Node(bottomX, bottomY));
}
int leftX = currentNode.x - 1;
int leftY = currentNode.y;
if (canReach(leftX, leftY) && !exists(closeList, leftX, leftY)) {
arrayList.add(new Node(leftX, leftY));
}
int rightX = currentNode.x + 1;
int