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

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

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

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

  • 我们要有我们的迷宫地图(在这里我将我的地图(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指针操作,不会参产生冲突)
    原文作者:回溯法
    原文地址: https://blog.csdn.net/fern_girl/article/details/70575918
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞