小型迷宫实现---迷宫算法(递归回溯法)

首先我们来了解迷宫包含的算法—-回溯法
回溯法的基本思想:
对一个包括有很多个结点,每个结点有若干个搜索分支的问题,把原问题分解为若干个子问题求解的算法;当搜索到某个结点发现无法再继续搜索下去时,就让搜索过程回溯(回退)到该节点的前一个结点,继续搜索该节点外的其他尚未搜索的分支;如果发现该结点无法再搜索下去,就让搜索过程回溯到这个结点的前一结点继续这样的搜索过程;这样的搜索过程一致进行到搜索到问题的解或者搜索完了全部可搜索分子没有解存在为止。

这是回溯算法的思想,也是采用递归的算法实现,应用到迷宫中去,当从迷宫的入口进去时,我们首先选择一个方向(上、下、左、右)一直走 ,如果走到出口成功,但往往迷宫是有许多死胡同的,当遇到死胡同,那么我们查看当前位置其他方向是否有出口,若有,则继续走,若没有,则需要我们沿着刚来的路径回退一步,判断当前这个位置是否有可以走通的方向,不断重复上述的步骤,直到我们走出迷宫。

接下来我们来实现简单迷宫

  • 我们要有我们的迷宫地图(在这里我将我的地图(1 0组成的二维数列)保存到文件中);
  • 我们要对迷宫的走向进行设置
  • 打印我们走过的迷宫(2代表走通的路径,3代表死胡同);

1.首先是我的迷宫地图:
这里写图片描述
我们这里将迷宫设置了两关,第一关游戏通过后才能进行选择进入第二关

2.我们要将文件中的地图读取并保存到我们自己定义的二维数组中,这里我们采用了scanf和fgetc函数:
这里写图片描述
功 能: 从一个流中执行格式化输入,fscanf遇到空格和换行时结束,注意空格时也结束。这与fgets有区别,fgets遇到空格不结束。

用 法: int fscanf(FILE *stream, char *format,[argument…]);
在本次算法中,我用该函数读取了迷宫地图的关卡号,大小和入口

这里写图片描述
意为从文件指针stream指向的文件中读取一个字符,读取一个字节后,光标位置后移一个字节。它是一个字符一个字符的读取,我们用它来读取地图

这里我遇到了一个问题:开始的时候我也是用fscanf函数来读取地图,但是在调用迷宫的析构函数时,会发生崩溃,显示我的地图成员是错误指针,但是用fgetc函数就不会产生这种情况?原因是什么我现在还没搞清楚

迷宫代码:

#include<stdio.h>
#include<iostream>
using namespace std;


struct seat
{
    seat(int x=0,int y=0)
        :_x(x)
        ,_y(y)
    {}
    int _x;
    int _y;
};

class Maze
{
public:
    Maze(FILE *fp,int row,int col)
        :_row(row)
        ,_col(col)
    {
        _map= new char*[_row];//为文件动态开辟一个二维数组存放迷宫地图
        for(int idx=0; idx<_row; ++idx)
        {       
            _map[idx] = new char[_col];
        }

        for(int i=0; i<_row; ++i)//从文件中读取迷宫地图
        {
            for(int j=0; j<_col; ++j)
            {
                fgetc(fp);//?????
                char temp = fgetc(fp);
                if(temp==' '||temp=='\n')
                {
                    --j;
                }
                else
                {
                    _map[i][j] = temp;
                }

                //fscanf(fp,"%d",&_map[i*_row+j]);//_map是错误指针
                //fprintf(stdout,"%d ",(int)_map[i*_row+j]);
            }
            //printf("\n");
        }
    }

    bool IsPass(const seat& s)const//判断当前位置是否可以通过(即为1)
    {
        if(_map[s._x][s._y]== '1')
            return true;
        return false;
    }

    bool PassMaze(seat &s)//迷宫走向
    {
        if((s._x<0||s._x>=_row) || (s._y<0||s._y>=_col))
        {
            cout<<"走出迷宫"<<endl;
            PrintMaze();
            return true;
        }
        if(IsPass(s))
        {
            _map[s._x][s._y] = '2';//????

            seat left(s._x,s._y -1);//向左走
            if(PassMaze(left))
            {
                return true;
            }

            seat right(s._x,s._y+1);//向右走
            if(PassMaze(right))
            {
                return true;
            }

            seat front(s._x-1,s._y);//向上走
            if(PassMaze(front))
            {
                return true;
            }

            seat back(s._x+1,s._y);//向后走
            if(PassMaze(back))
            {
                return true;
            }
            _map[s._x][s._y] ='3';//???注意
            return false;
        }
        return false;
    }


    void PrintMaze()//打印迷宫地图
    {
        for(int i=0; i<_row; ++i)
        {
            for(int j=0; j<_col; ++j)
            {
                printf("%c ",_map[i][j]);
            }
            printf("\n");
        }
    }

    ~Maze()
    {
        if(_map!=NULL)
        {
            for(int i=0; i<_row;++i)
            {
                delete[] _map[i];
                //_map[i] = NULL;
            }
            delete[] _map;
            _map=NULL;
        }
    }
private:
    char** _map;
    int _row;
    int _col;
};



int main()
{
    //第一关地图

    FILE *fp = fopen("file.txt","r");
    if(fp==NULL)
    {
        return -1;
    }
        int number;//关卡
    int count=2;
    do
    {
    cout<<"请选择关卡:1~2"<<endl;

    scanf("%d",&number);

    switch(number)
    {
    case 1:
        {
            int number1 = fgetc(fp)-'0';//读取编号1(第一关)
            int row1;
            int col1;
            seat s1;


            fscanf(fp,"%d",&row1);//读取行和列
            fscanf(fp,"%d",&col1);

            fscanf(fp,"%d",&s1._x);//从文件中读取入口位置
            fscanf(fp,"%d",&s1._y);


            Maze ma1(fp,row1,col1);
            ma1.PassMaze(s1);
            break;
        }
    case 2:
        {
            int number2;//读取第二关
            int row2;
            int col2;
            seat s2;
            fscanf(fp,"%d",&number2);
            fscanf(fp,"%d",&row2);//读取行和列
            fscanf(fp,"%d",&col2);

            fscanf(fp,"%d",&s2._x);//从文件中读取入口位置
            fscanf(fp,"%d",&s2._y);

            Maze ma2(fp,row2,col2);
            ma2.PassMaze(s2);
            break;
        }

    }
    }while(count--);


    fclose(fp);
    fp = NULL;
    getchar();
    return 0;
}

运行结果图:
这里写图片描述
这里写图片描述

总结:

  • 这里只实现了迷宫的思想,界面太丑,要学习添加图形界面;
  • 上述的游戏只能第一关完成后才能而且必须完成第二关,不能自由选择关卡,和重复玩第一关,我觉得解决的办法是将这些迷宫地图分装保存在不同的文件中去(不同的fp指针操作,不会参产生冲突)
  • 17
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我来介绍一下使用回溯法解决迷宫问题的思路和实现方法。 回溯法是一种经典的算法,它的核心思想是“有重复的尝试,并且每次尝试都会在尝试失败后回溯到上一步继续尝试”。在迷宫问题中,我们可以将起点看作是尝试的起点,终点看作是尝试的终点,每次尝试都是从当前位置向四周进行搜索,如果搜索到终点则成功,否则回溯到上一步继续尝试。 具体实现步骤如下: 1. 定义一个二维数组 maze 存储迷宫地图,1 表示墙,0 表示通路,定义一个二维数组 path 存储路径。 2. 定义一个函数 backtrack(x,y),表示从坐标 (x,y) 开始回溯,查找通往终点的路径。 3. 在 backtrack 函数中,首先判断当前坐标是否为终点,如果是,则输出路径并返回 true。 4. 如果当前坐标不是终点,则依次尝试向上、向下、向左、向右四个方向移动。如果移动后的坐标是通路(maze[x][y] == 0),则将当前坐标加入路径(path[x][y] = 1),并调用 backtrack 函数继续查找下一个位置。如果返回 true,则表示已经找到了通往终点的路径,直接返回 true;否则,回溯到当前位置,将当前坐标从路径中删除(path[x][y] = 0),并尝试下一个方向。 5. 如果四个方向都尝试过了,仍然没有找到通往终点的路径,返回 false。 下面是代码示例: ```c++ const int N = 1000; int maze[N+2][N+2]; // 迷宫地图 int path[N+2][N+2]; // 路径 bool backtrack(int x, int y) { if (maze[x][y] == 1 || path[x][y] == 1) { // 墙或者已经走过的位置 return false; } path[x][y] = 1; // 将当前位置加入路径 if (x == N && y == N) { // 到达终点 for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) { cout << path[i][j] << " "; } cout << endl; } cout << endl; return true; } if (backtrack(x-1, y) || // 尝试向上走 backtrack(x+1, y) || // 尝试向下走 backtrack(x, y-1) || // 尝试向左走 backtrack(x, y+1)) { // 尝试向右走 return true; } path[x][y] = 0; // 回溯 return false; } ``` 在这个代码中,我们首先判断当前位置是否为墙或者已经走过的位置,如果是,则返回 false。然后将当前位置加入路径,并尝试向上、向下、向左、向右四个方向移动,如果移动后的位置是通路,则继续递归搜索下一个位置。如果搜索到终点,则输出路径并返回 true;如果四个方向都尝试过了,仍然没有找到通往终点的路径,则回溯到上一步,将当前位置从路径中删除,并返回 false。 这个算法的时间复杂度是 O(4^n),其中 n 是迷宫中的可达位置数,因为每个位置有四个方向可以尝试。当迷宫较大时,这个算法效率较低,可以考虑使用其他更高效的算法,如 A* 算法等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值