其他分享
首页 > 其他分享> > 走迷宫!

走迷宫!

作者:互联网

自动化走迷宫

做maze题时不用自己在看花眼的maze里找路线了!!!

1.策略


  为了能回溯,也就是没路走时可以往回走, 这里采用了栈存储之前的路线,maze则采用了vector二位数组存储。
  那么简单地想,每一点位对四个方向进行检测,不断走下去,直到没路可走,便出栈往回走。这样会碰到什么问题呢? 由于进入一个点位的方向未知, 在试探四个方向时,可能会走回到上一个点位, 那就把该方向屏蔽,这样就需要给每个方向偏移打上一个标记位, 区分是否会回到上一个点位。
  我们采用另一种办法, 即将走过的点位标记为障碍物, 从而避免了自发地走回去的可能性, 而当没路走时, 仍然可以通过栈回溯到之前的点位。

  具体细节请看代码

2.code

先来栈代码
偏移结构和坐标结构也定义在这里,因为这个数据结构是按c风格写的,所以不太方便,只能把结构体定义在这里。

#include <stdio.h>
#include <malloc.h>
#include <stdbool.h>


typedef struct coordinate ElementType;
typedef struct SNode* PtrToSNode;


//坐标
struct coordinate
{
    int row;
    int col;
};

//行动偏移, row表示行偏移, col表示列偏移
struct offsets
{
    int row;
    int col;
};

//初始定义
typedef struct SNode
{
    ElementType* Data;
    int Top;
    int MaxSize;
}* Stack;

//创建一个栈空间
Stack CreateStack(int MaxSize)
{
    Stack s = (Stack)malloc(sizeof(struct SNode));
    s->Data = (ElementType*)malloc(MaxSize * sizeof(ElementType));
    s->Top = -1;
    s->MaxSize = MaxSize;
    return s;
}

//判断栈是否满
bool Isfull(Stack s)
{
    return s->Top == s->MaxSize - 1;
}

//判断栈是否空
bool IsEmpty(Stack s)
{
    return s->Top == -1;
}

//压栈
bool Push(Stack s, ElementType element)
{
    if(Isfull(s))
    {
        printf("Stack is full!");
        return false;
    }
    else 
    {
        s->Data[++(s->Top)] = element;
    }

    return true;
}

//出栈
ElementType Pop(Stack s)
{
    if(IsEmpty(s))
    {
        printf("Stack is empty!");
        return {0, 0};
    }
    else
    {
        return s->Data[s->Top--];
    }
}

然后是主要的实现代码。

//走迷宫,哈哈

#include "stack.h"
#include <iostream>
#include <vector>

using namespace std;

int main()
{
    cout << "请分别输入可行块、障碍块、入口、出口" << endl;
    char able, hinder, entry, exit;
    cin >> able >> hinder >> entry >> exit;
    //分别代表四种方块

    getchar();                                                                  //读取这里的换行符

    Stack s = CreateStack(0x80);                                                //创建一个栈
    struct offsets mov[4] =                                                     
        {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};                                     //偏移数组,0-3四个下标对应上下左右偏移
    vector<char> Row1{hinder};                                                  //新建一个vector容器用来储存第一行,以便于判断列数
                                                                                //在第一列加了边界
    char input;                                                                 //输入缓冲

    cout << "请输入迷宫矩阵, 以“!”表示迷宫输入结束。" << endl;

    while ('\n' != (input = getchar()))                                         //一直读到换行符
    {
        Row1.push_back(input);
    }

    Row1.push_back(hinder);
    int column_size = Row1.size();                                              //在末尾加边界,并计算长度

    vector<vector<char>> maze{vector<char>(column_size, hinder), Row1};         //创建二位的数组, 初始化了前两行,第一行是边界

    while (true)
    {
        cin >> input;
        if (input == '!')
            break;
        maze.push_back(vector<char>{hinder, input});
        int num_row = maze.size() - 1;
        for (int i = 2; i <= column_size - 2; i++)
        {
            cin >> input;
            maze[num_row].push_back(input);
        }
        maze[num_row].push_back(hinder);
    }                                                                           //重复读取直到!, 这里内层循环便于在首尾加边界

    maze.push_back(vector<char>(column_size, hinder));
    int row_size = maze.size();                                                 //在最后加边界, 计算行数

    struct coordinate cd_entry;
    for (int i = 0; i < row_size; i++)
    {
        for (int j = 0; j < column_size; j++)
        {
            if (maze[i][j] == entry)
            {
                cd_entry = {i, j};
                break;
            }
        }
    }                                                                           //检索, 找到入口点

    /* 至此,初始化完毕, 开始走迷宫 */

    struct coordinate next_cd, now_cd;                                          //定义现在坐标、下一步坐标
    int direction = 0, found = 0;                                               //方向(偏移数组的下标), 是否找到出口的标记
    vector<int> route{0};                                                       //储存路线的vector容器
    Push(s, cd_entry);                                                          //初始压栈, 便于待会给定入口坐标
    maze[cd_entry.row][cd_entry.col] = hinder;                                  
    //以下的策略是进入一个点,就将其标记为障碍物,从而杜绝了自发走回已过点位的可能性(靠出栈能往回走), 这里将入口点标记为障碍物

    while (!IsEmpty(s) && !found)                                               //栈空时表示前方无路,通过出栈一直回到了起点
    {
        now_cd = Pop(s);                                                        //回到上一个点位,四个方向都不行时会回到这里。
        route.pop_back();                                                       //删除路线中刚刚记录的行动
        direction = 0;                                                          //重置方向

        //出发
        while (direction < 4 && !found)
        {
            next_cd = {now_cd.row + mov[direction].row, now_cd.col + mov[direction].col};
            if (maze[next_cd.row][next_cd.col] == exit)                         //如果是出口
            {
                route.push_back(direction);
                found = 1;
            }
            else if (maze[next_cd.row][next_cd.col] == able)                    //如果下一个点可以走(没走过且不是障碍物)
            {
                route.push_back(direction);
                Push(s, now_cd);
                maze[next_cd.row][next_cd.col] = hinder;
                now_cd = next_cd;
                direction = 0;
            }
            else
                direction++;                                                    //换一个方向
        }
    }

    cout << endl;
    if (found)
    {
        //终于出来了!呼...呼...呼.........
        for (int i = 0; i < route.size(); i++)
        {
            switch (route[i])
            {
            case 0:
                cout << 'w';
                break;
            case 1:
                cout << 's';
                break;
            case 2:
                cout << 'a';
                break;
            case 3:
                cout << 'd';
                break;
            }
        }
    }
    else
        cout << "被困死了!!!" << endl;         //寄

    return 0;
}

3.改进

  学完栈的实现之后临时起意写的maze程序,有诸多问题,如stack是c风格,不清楚怎么在cpp文件中定义其元素, 所以最后是在h文件中定义了元素结构体。如果改成c++风格的stack,也就是使用模板类写这个stack,会好很多, 不过stl中其实直接就有stack的模板,直接调用也可以, 用模板的方便之处在于,可以直接创建存储不同元素的stack了, 而且函数都是封装好的,比每次还要传入栈这个参数方便。
  再者,看过其他实现方式,也可以定义另外一个矩阵,以存储走过的点位,就不用每次走到某个点位把他变成hinder了(这可能更不方便了)
  然后,这个程序要求最后输入一个!以提示输入完成, 如果在输入时直接指明行数和列数,代码会简单一些,我想尽可能简化使用程序的人的操作,也就是尽可能更智能,可以直接按输入的情况存储矩阵, 但又没想到更好的解决办法,便这么干了。




  还有诸如代码风格等可能存在的其他问题,希望能得到大佬的指正。

标签:struct,int,迷宫,cd,maze,Stack,row
来源: https://www.cnblogs.com/AAAAAtevor/p/16307659.html