实验三 基于A*算法的走迷宫程序

一、实验内容

1)迷宫游戏是非常经典的游戏,在该题中要求随机生成一个迷宫,并求解迷宫;

2) 要求查找并理解迷宫生成的算法,并尝试用两种不同的算法来生成随机的迷宫。

3)要求迷宫游戏支持玩家走迷宫,和系统走迷宫路径两种模式。玩家走迷宫,通过键盘方向键控制,并在行走路径上留下痕迹;系统提示迷宫路径要求基于A*算法实现,输出玩家当前位置到迷宫出口的最优路径。设计交互友好的游戏图形界面。

二、开发工具

  编程语言:java
  开发工具:idea

三、算法思想

深度优先迷宫生成算法,这个算法可以表示为

1.将起点作为当前迷宫单元并标记为已访问
2.当还存在未标记的迷宫单元,进行循环
    (1).如果当前迷宫单元有未被访问过的的相邻的迷宫单元
        1.随机选择一个未访问的相邻迷宫单元
        2.将当前迷宫单元入栈
        3.移除当前迷宫单元与相邻迷宫单元的墙
        4.标记相邻迷宫单元并用它作为当前迷宫单元
   ( 2).如果当前迷宫单元不存在未访问的相邻迷宫单元,并且栈不空
        1.栈顶的迷宫单元出栈
        2.令其成为当前迷宫单元

初始化地图:

System.out.println("初始化地图:");
for (int i = 0; i < r; i++) {

    for (int j = 0; j < c; j++) {

        LabId[i][j] = 0;// 将所有格子都设为墙, 0 为墙 1为路
        if (i % 2 == 1 && j % 2 == 1)// 将奇数行奇数列设为路,1为路,0为墙
            LabId[i][j] = 1;
        System.out.print(LabId[i][j] + " ");// 打印初始化地图,在控制台输出查看
    }
    System.out.println();
}

 

深度优先构建迷宫的思想就是,每次把新找到的未访问迷宫单元作为优先,寻找其相邻的未访问过的迷宫单元,直到所有的单元都被访问到。通俗的说,就是从起点开始随机走,走不通了就返回上一步,从下一个能走的地方再开始随机走。一般来说,深度优先法生成的迷宫极度扭曲,有着一条明显的主路。

使用DFS算法,借助递归思想访问某一顶点v,找v点附近且未被访问的点w,在找w附近未被访问的点(循环...),直到没有继续能找下去的点,依次退回最近被访问的点,如果还有该顶点的其他邻居没有被访问,就从邻居点开始继续搜索,把相邻的部分格子打通。
public void DFS(int[] LabG, int v) {

    LabG[v] = 1;// 访问顶点
    int[] neighbor = {
            v + row, v - row, v - 1, v + 1 };// 该点的四个邻居 上下左右
    int[] offR = {
            0, 0, -1, 1 }, offC = {
            1, -1, 0, 0 };// Row上个方向的偏移 Column上各方向的偏移,上下左右
    int[] tag = {
            -1, -1, -1, -1 };// 记录打通位置
    int n = 0;// 打通的次数
    while (n < 4) {
        // 上下左右四个方向都遍历,
        int i = rand.nextInt(4);// 随机打通一个方向
        if (tag[i] == 1)
            continue;// 进入下一轮循环
        tag[i] = 1;// 打通墙,设为1
        n++;
        int w = neighbor[i];// 定义一个该方向上的邻居
        if (w > LabG.length - 1 || w < 0)
            continue; // w不存在,即该方向上没有邻居

        // 取出现在的v点的位置
        int x = v % row;
        int y = v / row;

        // 遍历到四个边界时再往边界方向就没有邻居了,进入下一轮循环
        if (i == 0 && y == column - 1)
            continue;// 上方向
        if (i == 1 && y == 0)
            continue;// 下方向
        if (i == 2 && x == 0)
            continue;// 左方向
        if (i == 3 && x == row - 1)
            continue;// 右方向

        // 如果该点有未访问的邻居,则把该点与其邻居间的墙打通,即相邻的格子中间的位置放1
        if (LabG[w] == 0) {

            LabId[2 * x + 1 + offR[i]][2 * y + 1 + offC[i]] = 1;
            DFS(LabG, w);// 递归
        }
    }

A*搜寻算法
    A*搜寻算法,俗称A星算法,作为启发式搜索算法中的一种,这是一种在图形平面上,有多个节点的路径,求出最低通过成本的算法。常用于游戏中的NPC的移动计算,或线上游戏的BOT的移动计算上。该算法像Dijkstra算法一样,可以找到一条最短路径;也像BFS一样,进行启发式的搜索。

    A*算法最为核心的部分,就在于它的一个估值函数的设计上:
        f(n)=g(n)+h(n)

    其中f(n)是每个可能试探点的估值,它有两部分组成:
    一部分,为g(n),它表示从起始搜索点到当前点的代价(通常用某结点在搜索树中的深度来表示)。
    另一部分,即h(n),它表示启发式搜索中最为重要的一部分,即当前结点到目标结点的估值,
    h(n)设计的好坏,直接影响着具有此种启发式函数的启发式算法的是否能称为A*算法。

   一种具有f(n)=g(n)+h(n)策略的启发式算法能成为A*算法的充分条件是:
      1、搜索树上存在着从起始点到终了点的最优路径。
      2、问题域是有限的。
      3、所有结点的子结点的搜索代价值>0。
      4、h(n)=

    当此四个条件都满足时,一个具有f(n)=g(n)+h(n)策略的启发式算法能成为A*算法,并一定能找到最优解。

    对于一个搜索问题,显然,条件1,2,3都是很容易满足的,而条件4: h(n)<=h*(n)是需要精心设计的,由于h*(n)显然是无法知道的,所以,一个满足条件4的启发策略h(n)就来的难能可贵了。

    不过,对于图的最优路径搜索和八数码问题,有些相关策略h(n)不仅很好理解,而且已经在理论上证明是满足条件4的,从而为这个算法的推广起到了决定性的作用。

    且h(n)距离h*(n)的呈度不能过大,否则h(n)就没有过强的区分能力,算法效率并不会很高。对一个好的h(n)的评价是:h(n)在h*(n)的下界之下,并且尽量接近h*(n)。

A*算法的寻路详细步骤  

1.         把起点加入 open list 。

2.         重复如下过程:

a.         遍历 open list ,查找 F 值最小的节点,把它作为当前要处理的节点。

b.         把这个节点移到 close list 。

c.         对当前方格的 8 个相邻方格的每一个方格?

◆     如果它是不可抵达的或者它在 close list 中,忽略它。否则,做如下操作。

◆     如果它不在 open list 中,把它加入 open list ,并且把当前方格设置为它的父亲,记录该方格的 F , G 和 H 值。

◆     如果它已经在 open list 中,检查这条路径 ( 即经由当前方格到达它那里 ) 是否更好,用 G 值作参考。更小的 G 值表示这是更好的路径。如果是这样,把它的父亲设置为当前方格,并重新计算它的 G 和 F 值。如果你的 open list 是按 F 值排序的话,改变后你可能需要重新排序。

d.         停止,当你

◆     把终点加入到了 open list 中,此时路径已经找到了,或者

◆     查找终点失败,并且 open list 是空的,此时没有路径。

3.         保存路径。从终点开始,每个方格沿着父节点移动直至起点,这就是你的路径。

 

 

计算G值:

private int calcG(Node start, Node node) {

    int G = STEP;
    int parentG = node.parent != null ? node.parent.G : 0;
    return G + parentG;
}

计算H值:

private int calcH(Node end, Node node) {

    int step = Math.abs(node.x - end.x) + Math.abs(node.y - end.y);
    return step * STEP;
}

你可能感兴趣的:(java,idea)