C++ prim迷宫算法

效果图

在这里插入图片描述

代码

结合了前一篇A寻路算法。
先用prim算法生成地图,再用A
进行寻路

目前已知问题

  1. 起点和终点很容易生成在很久的位置。
  2. 其他bug和A*一样,还没修复
#include <iostream>
#include <vector>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>

int steps = 0;
namespace MapFunction
{
    using MapItem = std::string;
    using MapContainer = std::vector<std::vector<MapItem>>;

    const int MapSize = 40;
    int BlockCount = 110;
    const MapItem BlockItem = "\033[93m█\033[0m";
    const MapItem TargetItem = "\033[92m█\033[0m";
    const MapItem RoleItem = "\033[91m█\033[0m";
    const MapItem SpaceItem = " ";
    const MapItem PathItem = "\033[94m█\033[0m";
    const MapItem ProgressItem = "\033[97m█\033[0m";

    struct Point
    {
        int x;
        int y;
    };

    enum Dir
    {
        cur_up,
        cur_down,
        cur_left,
        cur_right
    };

    void _m_FlushDelay()
    {
        usleep(50000);
    }

    Point up{0, -1};
    Point down{0, 1};
    Point left{-1, 0};
    Point right{1, 0};

    std::vector<Point> DirOffset{up, down, left, right};
}

namespace PrimMap
{
    using namespace MapFunction;

    class MapPoint
    {
    private:
        Point m_point;  // 该点的坐标
    public:
        int WallDir;  // 该点的墙壁方向
        MapItem Type;  // 该点的类型
    public:
        MapPoint() = default;
        ~MapPoint() = default;
        int x(){return m_point.x;}  // 获取x坐标
        int y(){return m_point.y;}  // 获取y坐标
        void SetX(int x){  // 设置x坐标
            this->m_point.x = x;
        }

        void SetY(int y){  // 设置y坐标
            this->m_point.y = y;
        }
        MapPoint(const Point &pos)  
        {  // 构造函数
            m_point.x = pos.x;
            m_point.y = pos.y;
        }
        MapPoint operator =(const Point &pos)
        {  // 赋值运算符重载
            this->m_point.x = pos.x;
            this->m_point.y = pos.y;
            return *this;
        }
    };
    class BlockMapGen
    {
    private:
        const MapItem WallItem = "\033[33m█\033[0m";
        const MapItem SpaceItem = " ";
        const MapItem NoneItem = "X";
        int PrimMapSize;
        std::vector<MapPoint *> RoadList;  // 通路点列表
        std::vector<MapPoint *> WallList;  // 墙壁点列表
        MapContainer PrimMap;

    public:
        
        bool WallCheck(MapPoint &pos){    
            // 不在地图内的点不符合要求
            if (pos.x() < 0 || pos.y() < 0 || pos.x() >= PrimMapSize || pos.y() >= PrimMapSize)
            {
                return false;
            }
            // 已经置为通路的点不符合要求
            if (PrimMap[pos.y()][pos.x()] == SpaceItem) 
            {
                return false;
            }
            return true;
        }
        // 检查四个方向的点
        void AllDirCheck(MapPoint &pos){ 
            for (size_t i = 0; i < 4; i++)
            {
                MapPoint* TempPos = new MapPoint();
                TempPos->SetX(pos.x() + DirOffset[i].x);
                TempPos->SetY(pos.y() + DirOffset[i].y);
                if (WallCheck(*TempPos))
                {
                    TempPos->WallDir = i;
                    TempPos->Type = WallItem;
                    WallList.push_back(TempPos);
                }else{
                    delete TempPos;
                }
            }

        }

        MapPoint *RandomPos(const int &range)
        {
            srand(time(NULL));
            MapPoint *pos = new MapPoint();
            pos->SetX(rand() % range);
            pos->SetY(rand() % range);
            return pos;
        }

        MapPoint* RoadCheck(MapPoint& pos){
            int count = 0;
            MapPoint* RoadPos = nullptr;
            for (size_t i = 0; i < 4; i++)
            {
                MapPoint* TempPos = new MapPoint();
                TempPos->SetX(pos.x() + DirOffset[i].x);
                TempPos->SetY(pos.y() + DirOffset[i].y);
                if (WallCheck(*TempPos))
                {
                    delete TempPos;
                    continue;
                }
                count++;
                RoadPos = TempPos;
            }
            if (count == 1)
            {
                return RoadPos;
            }
            return nullptr;
        }
        MapContainer MapCal(){
            // 选择第一个通路点
            MapPoint *RoadStart = RandomPos(PrimMapSize);
            RoadList.push_back(RoadStart);
            PrimMap[RoadStart->y()][RoadStart->x()] = SpaceItem;
            AllDirCheck(*RoadStart);
            while (WallList.size() > 0)
            {
                int index = rand() % WallList.size();
                auto tempWall = WallList[index];
                for (auto it = WallList.begin(); it != WallList.end(); ++it)
                {
                    if((*it) == tempWall)
                    {
                        WallList.erase(it);
                        break;
                    }
                }
                auto tempRoad = RoadCheck(*tempWall);
                if (nullptr != tempRoad)
                {
                    RoadList.push_back(tempWall);
                    PrimMap[tempWall->y()][tempWall->x()] = SpaceItem;
                    AllDirCheck(*tempWall);
                }
                else
                {
                    delete tempWall;
                }

                // std::cout << "\033c";
                // for (int i = 0; i < PrimMapSize; i++)
                // {
                //     for (int j = 0; j < PrimMapSize; j++)
                //     {
                //         std::cout << PrimMap[i][j] << " ";
                //     }
                //     std::cout << "│\n";
                // }

                // for (int i = 0; i < PrimMapSize; i++)
                //     std::cout << "──";
                // std::cout << "┘\n";
                // usleep(10000);

            }
            return PrimMap;
        }

    public:
        BlockMapGen() = default;
        BlockMapGen(const MapContainer &RawMap)
        {
            PrimMapSize = RawMap.size();
            for (size_t i = 0; i < PrimMapSize; i++)
            {
                std::vector<MapItem> TempCol;
                for (size_t j = 0; j < PrimMapSize; j++)
                {
                    TempCol.push_back(WallItem);
                }
                PrimMap.push_back(TempCol);
            }
        }
        ~BlockMapGen() = default;
    };

} // namespace primMap

namespace MapFunction
{
    Point StartPoint;
    Point EndPoint;

    MapContainer MissionMap(MapSize);

    Point _m_RandomGen()
    {

        srand(time(NULL));
        int x = rand() % MapSize;
        int y = rand() % MapSize;
        while (MissionMap[y][x] != SpaceItem)
        {
            x = rand() % MapSize;
            y = rand() % MapSize;
        }
        Point temp;
        temp.x = x;
        temp.y = y;
        return temp;
    }

    void _m_MapItemSet(const Point &pos, const MapItem &item)
    {
        MissionMap[pos.y][pos.x] = item;
    }

    void _m_SetItemPos()
    {
        PrimMap::BlockMapGen map(MissionMap);
        MissionMap = map.MapCal();

        EndPoint = _m_RandomGen();
        _m_MapItemSet(EndPoint, TargetItem);

        StartPoint = _m_RandomGen();
        _m_MapItemSet(StartPoint, RoleItem);

    }
    void MapInit()
    {
        for (int i = 0; i < MapSize; i++)
        {
            MissionMap[i].resize(MapSize);
        }
        for (int i = 0; i < MapSize; i++)
        {
            for (int j = 0; j < MapSize; j++)
            {
                MissionMap[i][j] = SpaceItem;
            }
        }
        _m_SetItemPos();
    }


    void MapFlush(bool flag)
    {
        if (flag)
        {
            std::cout << "\033c";
            MissionMap[EndPoint.y][EndPoint.x] = TargetItem;
            MissionMap[StartPoint.y][StartPoint.x] = RoleItem;
            for (int i = 0; i < MapSize; i++)
            {
                for (int j = 0; j < MapSize; j++)
                {
                    std::cout << MissionMap[i][j] << MissionMap[i][j];
                }
                std::cout << "│\n";
            }

            for (int i = 0; i < MapSize; i++)
                std::cout << "──";
            std::cout << "┘\n";
            std::cout << steps++ << std::endl;

            _m_FlushDelay();
        }
    }

} // namespace MapFunction

namespace AStarFunction
{
    using namespace MapFunction;
    constexpr int PathCost = 10;
    class MyPoint
    {
    public:
        int F, G, H;
        int x, y;
        bool isWalked;

    public:
        bool operator==(const MyPoint &pos)
        {
            return (pos.x == x && pos.y == y);
        }
        void SetH(const MyPoint &cur, const MyPoint &end)
        {
            H = PathCost * (abs(cur.x - end.x) + abs(cur.y - end.y));
        }
        void SetG(int num) { G = num; }
        void SetF() { F = G + H; }
    };
    class TreeNode
    {
    public:
        // curren Point
        MyPoint pos;
        // container to store one or one more child point
        std::vector<TreeNode *> pChildNode;
        // parent Node;
        TreeNode *pParent;
        int TreeLength;

    public:
        TreeNode(const MyPoint &next)
        {
            pos = next;
            pParent = nullptr;
        }
    };


    // check border and block
    bool walkCheck(const MapContainer &box, const MyPoint &pos)
    {
        if (pos.y < 0 || pos.x < 0 || pos.y >= MapSize || pos.x >= MapSize)
        {
            return false;
        }

        if (box[pos.y][pos.x] == TargetItem)
        {
            return true;
        }

        // if (box[pos.y][pos.x] == BlockItem || box[pos.y][pos.x] == RoleItem)
        if (box[pos.y][pos.x] != SpaceItem)
        {
            return false;
        }
        return true;
    }

    void StartAStar()
    {
        MapFunction::MapInit();
        MyPoint StartPos;
        StartPos.x = StartPoint.x;
        StartPos.y = StartPoint.y;

        MyPoint EndPos;
        EndPos.x = EndPoint.x;
        EndPos.y = EndPoint.y;
        // root init
        TreeNode *pRoot = new TreeNode(StartPos);
        pRoot->pParent == nullptr;
        pRoot->TreeLength = 0;
        TreeNode *pCur = pRoot;
        TreeNode *pTemp = nullptr;

        std::vector<TreeNode *> buff;
        std::vector<TreeNode *> FinishList;
        std::vector<TreeNode *> OpenList;
        bool FindFlag = false;
        while (1)
        {
            if (pCur != nullptr)
            {
                // check all directions and sava the direction that can move to;
                for (size_t i = 0; i < 4; i++)
                {
                    pTemp = new TreeNode(pCur->pos);
                    switch (i)
                    {
                    case cur_up:
                        pTemp->pos.y--;
                        break;
                    case cur_down:
                        pTemp->pos.y++;
                        break;
                    case cur_left:
                        pTemp->pos.x--;
                        break;
                    case cur_right:
                        pTemp->pos.x++;
                        break;
                    default:
                        break;
                    }

                    if (walkCheck(MissionMap, pTemp->pos))
                    {
                        if (pTemp->pos == EndPos)
                        {
                            buff.clear();
                        }
                        pCur->pChildNode.push_back(pTemp);
                        pTemp->pParent = pCur;
                        pTemp->TreeLength = pCur->TreeLength + 1;
                        pTemp->pos.SetG(PathCost);
                        pTemp->pos.SetH(pTemp->pos, EndPos);
                        pTemp->pos.SetF();
                        buff.push_back(pTemp);

                        if (pTemp->pos == EndPos)
                        {
                            break;
                        }
                    }
                    else
                    {
                        delete pTemp;
                        pTemp = nullptr;
                    }
                }
            }
            // push qualified data into openlist and clean buffer list.
            for (auto it = buff.begin(); it != buff.end(); ++it)
            {
                OpenList.push_back(*it);
            }
            buff.clear();

            if (OpenList.size() > 0)
            {
                /* code */
                // find all minimum score
                auto minF = OpenList.begin();
                for (auto it = OpenList.begin(); it != OpenList.end(); ++it)
                {
                    minF = (*minF)->pos.F < (*it)->pos.F ? minF : it;
                }
                pCur = *minF;
                OpenList.erase(minF);
                MissionMap[pCur->pos.y][pCur->pos.x] = ProgressItem;

                if (pCur->pos == EndPos)
                {
                    FindFlag = true;
                    FinishList.push_back(pCur);
                    pCur = nullptr;
                    break;
                }

                MapFunction::MapFlush(true);
                if (OpenList.size() == 0)
                {
                    break;
                }
            }
        }
        if (FindFlag)
        {
            auto MinSize = FinishList.begin();
            for (auto it = FinishList.begin(); it != FinishList.end(); ++it)
            {
                MinSize = (*MinSize)->TreeLength < (*it)->TreeLength ? MinSize : it;
            }
            auto pTemp2 = *MinSize;
            while (pTemp2->pParent != nullptr)
            {
                MissionMap[pTemp2->pos.y][pTemp2->pos.x] = PathItem;
                pTemp2 = pTemp2->pParent;
            }

            MapFunction::MapFlush(true);
        }
    }

} // namespace A

int main(int argc, char **argv)
{
    AStarFunction::StartAStar();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值