计算机软件实习项目三—走迷宫

目录

实验目的

编程语言与开发环境

游戏的逻辑设计

实验核心


一、实验目的

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

2.要求查找并理解迹;系统提示迷宫路径要求基于A*算法实现,输出玩家当前位置到迷宫出口的最优路径。设计迷宫生成的算法,并尝试用两种不同的算法来生成随机的迷宫。

3.要求迷宫游戏支持玩家走迷宫,和系统走迷宫路径两种模式。玩家走迷宫,通过键盘方向键控制,并在行走路径上留下痕交互友好的游戏图形界面。

二、编程语言与开发环境

     本次开发采用C++QT结合的形式。

三、游戏的逻辑设计

游戏预设:我想做一个人物地点选择界面分为两个部分,左边的话是就是人物选择可以选择小灰灰、美羊羊、沸洋洋三种人物选择,右边是地方选择,可以选择两种模式,进入游戏界面用prime算法随机生成迷宫,再用A*算法实现搜寻到最优路径,同时增加背景音乐的设置。

四、实验核心

prime算法

其基本步骤为:

(1)初始化地图。地图中的每个位置代表迷宫中的一个单元格,初始时所有的单元格都设置为障碍物(例如黑色)。

(2)选择一个障碍物作为起点,并将其在地图上标记为已访问(例如白色)。

(3)在已访问的单元格中选择一个与未访问的单元格相邻的单元格,并将其在地图上标记为已访问。

(4)重复步骤3,直到地图上所有的单元格都被访问过,或者没有与未访问的单元格相邻的已访问单元格。

(5)如果地图上还有未访问的单元格,则从这些单元格中选择一个作为新的起点,重复步骤2-4,直到地图上所有的单元格都被访问过。

(6)如果迷宫中存在环路(例如两个单元格之间存在两条路径),则删除其中的一条路径。

(7)最后,根据需要将迷宫的出口标记为终点(例如红色)。

        Prime算法的主要优点是可以快速生成迷宫,但是生成的迷宫可能不是最优解,即可能存在一些不必要的曲折或者不是最短路径。为了生成更加复杂的迷宫,可以在算法中加入随机性或者其他规则。

prime算法的代码:

while(true){//利用prim算法生成迷宫

        temp.i=i;//起始点

        temp.j=j;

        int randnum=rand()%4;

        switch (randnum) {

        case 0: if(!up&&i>2&&maze[i-2][j].state==0){

                build_maze_stack.push(temp);

                maze[i-2][j].state=1;

                maze[i-1][j].state=1;

                i=i-2;

                if(maze[i-1][j].state==0)

                    up=false;

                else

                    up=true;

                if(maze[i+1][j].state==0)

                    down=false;

                else

                    down=true;

                if(maze[i][j-1].state==0)

                    left=false;

                else

                    left=true;

                if(maze[i][j+1].state==0)

                    right=false;

                else

                    right=true;

            }

            else{

                up=true;

            }

            break;

        case 1: if(!down&&i<maze_row-3&&maze[i+2][j].state==0)

            {

                build_maze_stack.push(temp);

                maze[i+2][j].state=1;

                maze[i+1][j].state=1;

                i=i+2;

                if(maze[i-1][j].state==0)

                    up=false;

                else

                    up=true;

                if(maze[i+1][j].state==0)

                    down=false;

                else

                    down=true;

                if(maze[i][j-1].state==0)

                    left=false;

                else

                    left=true;

                if(maze[i][j+1].state==0)

                    right=false;

                else

                    right=true;

            }

            else{

                down=true;

            }

            break;

        case 2: if(!left&&j>2&&maze[i][j-2].state==0)

            {

                build_maze_stack.push(temp);

                maze[i][j-2].state=1;

                maze[i][j-1].state=1;

                j=j-2;

                if(maze[i-1][j].state==0)

                    up=false;

                else

                    up=true;

                if(maze[i+1][j].state==0)

                    down=false;

                else

                    down=true;

                if(maze[i][j-1].state==0)

                    left=false;

                else

                    left=true;

                if(maze[i][j+1].state==0)

                    right=false;

                else

                    right=true;

            }

            else{

                left=true;

            }

            break;

        case 3: if(!right&&j<maze_col-3&&maze[i][j+2].state==0)

            {

                build_maze_stack.push(temp);

                maze[i][j+2].state=1;

                maze[i][j+1].state=1;

                j=j+2;

                if(maze[i-1][j].state==0)

                    up=false;

                else

                    up=true;

                if(maze[i+1][j].state==0)

                    down=false;

                else

                    down=true;

                if(maze[i][j-1].state==0)

                    left=false;

                else

                    left=true;

                if(maze[i][j+1].state==0)

                    right=false;

                else

                    right=true;

            }

            else{

                right=true;

            }

            break;

        }

      if(up&&down&&left&&right){//上下左右都是通路,则此点为圆环,舍弃

            if(!build_maze_stack.isEmpty()){

                i=build_maze_stack.top().i;

                j=build_maze_stack.top().j;

                build_maze_stack.pop();

                if(maze[i-1][j].state==0)

                    up=false;

                else

                    up=true;

                if(maze[i+1][j].state==0)

                    down=false;

                else

                    down=true;

                if(maze[i][j-1].state==0)

                    left=false;

                else

                    left=true;

                if(maze[i][j+1].state==0)

                    right=false;

                else

                    right=true;

            }

            else{

                maze[1][1].state=2;

                maze[maze_row-3][maze_col-3].state=3;

                creat_maze=true;

                for(int i=0; i<maze_row; i++)//这一段是防止生成迷宫后依旧显示路线

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

                        path[i][j].state=0;//在这里的状态表示父节点,1,2,3,4分别表示从上下左右发展过来

                        path[i][j].i=i;

                        path[i][j].j=j;

                    }

                return;

            }

        }

    }

A*搜索算法

        A*搜索算法是一种静态路网中求解最短路最有效的方法。公式表示为:f(n)=g(n)+h(n),其中f(n)是节点n从初始点到目标点的估价函数,g(n)是在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取:估价值h(n)小于等于n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低,但能得到最优解。如果估价值大于实际值,搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。A*搜索算法的流程图:

A*搜索算法的求解步骤说明:

1.将起点方格(节点)加入A_search栈中,作为寻路开始的起点;

2.循环执行以下步骤,直到A_search栈为空结束或者终点(节点)加入到A_search中:

(1)在A_search中找到F值最小的那个节点(如果有相等的情况,就选择最先找到的那个节点)作为[ 当前节点 ];

(2)在A_search中将第1步找到的那个F值最小的节点,从A_search中删除掉;

(3)在auto_path中将第1步找到的那个F值最小的节点,加入auto_path中;

(4)围绕第1步找到的那个F值最小的(当前节点),找到与它相邻的四个方向(上下左右)上的节点,这里要判断邻居节点的有效性,看邻居节点是否满足以下条件:

<1>邻居节点是否越界—节点的x或者y是否在可视范围内;

<2>邻居节点是否为障碍方格(节点)—比如本程序中的 MAZE[i][j]=1 即为障碍,MAZE[i][j]=0 即为可用;

<3>邻居节点是否已经在A_search栈中或者auto_path数组中;

A*搜索算法的代码

void play_maze::on_A_search_clicked()//A*算法

{

    if(flag_click||flag_success){

        return;

    }

    if(!creat_maze){

        return;

    }

    A_search.clear();

    //int md;//曼哈顿距离

//    qDebug()<<"begin find path";

    ftime.start();

    for(int i=0; i<maze_row; i++)

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

            path[i][j].state=0;//在这里的状态表示父节点,1,2,3,4分别表示从上下左右发展过来

            path[i][j].i=i;

            path[i][j].j=j;

        }

    //用于记录该点是否搜索的矩阵

    for(int i=0; i<maze_row; i++)

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

            if(maze[i][j].state==0)

                graph[i][j]=1;

            else

                graph[i][j]=0;//初始化未被搜索

        }

    QString message;

    int searchnum=0;

    point top;

    top.i=control_X;

    top.j=control_Y;

    top.state=abs(control_X-target_X)+abs(control_Y-target_Y);

    A_search.push_back(top);//这里的状态什么也不表示

    graph[top.i][top.j]=0;

    while(!A_search.isEmpty()){

        qSort(A_search.begin(),A_search.end(),cmp);

        top=A_search.front();

        //qDebug()<<top.i<<" "<<top.j<<" "<<top.state<<endl;

        A_search.pop_front();

        if(graph[top.i][top.j]==0){

            searchnum+=1;

            if(maze[top.i][top.j].state==3){

                break;

            }

            //将此点标记为访问过

            //并将真实路径代价计算进去,用graph存储

            switch (path[top.i][top.j].state) {

            case 1:

                graph[top.i][top.j]=graph[top.i-1][top.j]+1;

                break;

            case 2:

                graph[top.i][top.j]=graph[top.i+1][top.j]+1;

                break;

            case 3:

                graph[top.i][top.j]=graph[top.i][top.j-1]+1;

                break;

            case 4:

                graph[top.i][top.j]=graph[top.i][top.j+1]+1;

                break;

            default:

                graph[top.i][top.j]=1;

                break;

            }

            //将未访问的子节点放入开节点表

    if((graph[top.i+1][top.j]==0)&&(maze[top.i+1][top.j].state!=0)){

                A_search.push_back(point(top.i+1,top.j,(graph[top.i][top.j]+1+abs(top.i+1-target_X)+abs(top.j-target_Y))));

                path[top.i+1][top.j].state=1;

                //graph[top.i+1][top.j]=graph[top.i][top.j]+1;

            }

            if((graph[top.i-1][top.j]==0)&&(maze[top.i-1][top.j].state!=0)){

                A_search.push_back(point(top.i-1,top.j,(graph[top.i][top.j]+1+abs(top.i-1-target_X)+abs(top.j-target_Y))));

                path[top.i-1][top.j].state=2;

                //graph[top.i-1][top.j]=graph[top.i][top.j]+1;

            }  if((graph[top.i][top.j+1]==0)&&(maze[top.i][top.j+1].state!=0)){             A_search.push_back(point(top.i,top.j+1,(graph[top.i][top.j]+1+abs(top.i-target_X)+abs(top.j+1-target_Y))));

                path[top.i][top.j+1].state=3;

            }

            if((graph[top.i][top.j-1]==0)&&(maze[top.i][top.j-1].state!=0)){

                A_search.push_back(point(top.i,top.j-1,(graph[top.i][top.j]+1+abs(top.i-target_X)+abs(top.j-1-target_Y))));

                path[top.i][top.j-1].state=4;

                /[表情]archnum+=1;

                //graph[top.i][top.j-1]=graph[top.i][top.j]+1;

            }

        }

    }

//    qDebug()<<"find the path!"<<endl;

}

                path[top.i][top.j+1].state=3;

            }

            if((graph[top.i][top.j-1]==0)&&(maze[top.i][top.j-1].state!=0)){

                A_search.push_back(point(top.i,top.j-1,(graph[top.i][top.j]+1+abs(top.i-target_X)+abs(top.j-1-target_Y))));

                path[top.i][top.j-1].state=4;

                /[表情]archnum+=1;

                //graph[top.i][top.j-1]=graph[top.i][top.j]+1;

            }

        }

    }

//    qDebug()<<"find the path!"<<endl;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值