C++实现迷宫生成与解决

数据结构实验课要求解决一个迷宫问题,这里给定长宽用prime算法随机生成了一个迷宫并从指定起点与终点打印出了迷宫的解决方案,此处用到了栈数据结构,这里的jmc::Stack是我自己写的栈,这里就不放了,可以换成一切具有常规意义的empty、pop、push接口的栈ADT,或者直接使用std::stack就行,注意头文件的#include"Stack"也改一下

Maze.h:

#pragma once
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<random>
#include<string>
#include"Stack.h"
#include<functional>
#include<algorithm>
#include<cassert>
namespace jmc {
 using blockpic = std::vector<std::string>;
 const blockpic block{
 "▉"," ","※"
 };

 class locat {
 public:
 using rowType = size_t;
 using calType = size_t;

 locat(rowType r = 0, calType c = 0)
 :loc(r, c) {}

 rowType x(void)const { return loc.first; } //返回一维坐标
 rowType x(const rowType& r) { loc.first = r; return loc.first; }//修改并返回一维坐标
 calType y(void)const { return loc.second; } //返回二维坐标
 calType y(const calType& c) { loc.second = c; return loc.second; }//修改并返回二维坐标
 locat up(void)const { return { loc.first - 1, loc.second }; }
 locat down(void)const { return { loc.first + 1, loc.second }; }
 locat left(void)const { return { loc.first, loc.second - 1 }; }
 locat right(void)const { return { loc.first, loc.second + 1 }; }
 locat& operator()(const rowType& r, const calType& c) {
 x(r), y(c);
 return *this;
 }
 locat& operator()(const locat& oth) {
 return (*this)(oth.x(), oth.y());
 }
 bool operator<(const locat& oth)const {
 return x() == oth.x() ? y() < oth.y() : x() < oth.x();
 }
 bool operator==(const locat& oth)const {
 return x() == oth.x() && y() == oth.y();
 }
 friend std::ostream& operator<<(std::ostream& o, const locat& l)
 {
 o << '(' << l.x() << ',' << l.y() << ')';
 return o;
 }
 private:
 std::pair<rowType, calType> loc;
 };

 class Maze
 {
 public:
 using rowType = locat::rowType;
 using calType = locat::calType;
 using locats = std::vector<locat>;

 enum blockType {
 wall,
 road,
 way
 }; 

 Maze(const locat& l) :xyMsg(l), Map(l.x(), mazeLine(l.y(), wall)) {}
 Maze(rowType row, calType cal); // 随机生成一个迷宫,采用Prim算法

 std::function<locat(const locat& l)> operat[4]{
 [](const locat& l) {return l.up(); },
 [](const locat& l) {return l.down(); },
 [](const locat& l) {return l.left(); },
 [](const locat& l) {return l.right(); },
 };

 auto& operator()(const rowType& r,const calType& c) {
 return Map[r][c];
 }
 auto& operator()(const locat& p) {
 return (*this)(p.x(), p.y());
 }

 rowType row(void) { return xyMsg.x(); } // 返回迷宫的行数
 calType cal(void) { return xyMsg.y(); } // 返回迷宫的列数
 locat& start(void) { return _start; }
 locat& end(void) { return _end; }
 void show(const blockpic pic = block); // 打印迷宫

 private:
 using mazeLine = std::vector<blockType>; // 单行迷宫
 using mazeMap = std::vector<mazeLine>; // 迷宫图

 locats findWall(const locat& p); //返回一个路周围的墙
 locats findRoad(const locat& p); //返回一个墙周围的路

 locat xyMsg;
 mazeMap Map;
 locat _start, _end;
 };

 //给出迷宫问题的解决方案
 class Solute
 :public Maze
 {
 public:
 Solute(const rowType& r, const calType& c)
 :Maze(r, c) {
 rowType tmpR;
 calType tmpC;
 show();

 std::cout << std::endl << std::endl
 << "请输入起点的行坐标与列坐标:";
 std::cin >> tmpR >> tmpC;
 (*this)(end()(tmpR, tmpC)) = way;
 std::cout << "请输入终点的行坐标与列坐标:";
 std::cin >> tmpR >> tmpC;
 (*this)(start()(tmpR, tmpC)) = way;

 solve(start());
 show();
 std::cout << std::endl << std::endl;
 showWay();
 }

 bool isIn(const locat& p) {
 return p.x() < row() && p.y() < cal();
 }
 bool solve(const locat& p);
 void showWay(void) {
 if (!ans.empty()) {
 std::cout << ans.top();
 ans.pop();
 if (!ans.empty())
  std::cout << " -> ";
 showWay();
 }
 };
 private:
 Maze mark{ locat{row(),cal()} };
 jmc::Stack<locat> ans{};
 };
}

Maze.cpp:

#include "Maze.h"

jmc::Maze::Maze(rowType row, calType cal)
 :xyMsg(2 * row + 1, 2 * cal + 1), Map(2 * row + 1, mazeLine(2 * cal + 1, wall))
{
 // 初始化随机数生成器
 static std::random_device rd;
 static std::default_random_engine e(rd());
 static std::uniform_int_distribution<> d;

 std::map<blockType, std::set<locat>> mark{
 {wall,{}},{road,{}}
 };

 for (rowType i = 1; i < row * 2 + 1; i += 2)
 {
 for (calType j = 1; j < cal * 2 + 1; j += 2)
 {
 (*this)(i,j) = road;
 }
 }

 //随机生成起点,把边框分为四段
 auto i = d(e, decltype(d)::param_type{ 0,3 });
 auto j = i % 2 ?
 d(e, decltype(d)::param_type{ 0,(int)row - 2 }) :
 d(e, decltype(d)::param_type{ 0,(int)cal - 2 });
 switch (i)
 {
 case 0:
 _start(j, 0); break;
 case 1:
 _start(0, j - 1); break;
 case 2:
 _start(row - 1, j); break;
 case 3:
 _start(j + 1, cal - 1); break;
 }
 _start(_start.x() * 2 + 1, _start.y() * 2 + 1); //将起点对应到实际位置
 locats tmpRoad{ _start };
 locats tmpWall = findWall(_start);
 mark[road].insert(tmpRoad.begin(), tmpRoad.end());
 mark[wall].insert(tmpWall.begin(), tmpWall.end());

 while (!mark[wall].empty())
 {
 auto it = mark[wall].begin();
 std::advance(it,
 d(e, decltype(d)::param_type{ 0,(int)mark[wall].size()-1 }));
 tmpRoad = findRoad(*it); //随机将一个wall集合中的元素传入findRoad
 auto s1 = mark[road].size(); //插入set前set大小
 bool flag = false;
 for (auto& i : tmpRoad)
 {
 mark[road].insert(i);
 if (s1 != mark[road].size()) {
 s1 = mark[road].size();
 tmpWall = findWall(i);
 mark[wall].insert(tmpWall.begin(), tmpWall.end());
 flag = true;
 }
 }
 //若size有变化,表示此wall周围的road有未标记的,将此wall置为road
 if (flag) {
 mark[road].insert(*it);
 (*this)(*it) = road;
 }
  mark[wall].erase(it);
 }
 _end(tmpRoad.back());
}

void jmc::Maze::show(const blockpic pic)
{
 size_t m{}, n{};
 for (const auto& i : Map)
 {
 for (const auto& j : i)
 {
 std::cout << pic[j];
 }
 std::cout << m++ << std::endl;
 }
 for (size_t i = 0; i < cal(); printf("%2d", i++));
}

jmc::Maze::locats jmc::Maze::findWall(const locat& p)
{
 locats ret;
 locat tmp;
 if (p.x() != 1) {
 tmp = p.up();
 if ((*this)(tmp) == wall)
 ret.push_back(tmp);
 }
 if (p.y() != 1) {
 tmp = p.left();
 if ((*this)(tmp) == wall)
 ret.push_back(tmp);
 }
 if (p.x() != row() - 2) {
 tmp = p.down();
 if ((*this)(tmp) == wall)
 ret.push_back(tmp);
 }
 if (p.y() != cal() - 2) {
 tmp = p.right();
 if ((*this)(tmp) == wall)
 ret.push_back(tmp);
 }
 return ret;
}

jmc::Maze::locats jmc::Maze::findRoad(const locat& p)
{
 assert(p.x() != 0 && p.x() != row() && p.y() != 0 && p.y() != cal());

 locats ret;
 locat tmp;

 for (auto& i : operat)
 {
 tmp = i(p);
 if ((*this)(tmp) == road)
 ret.push_back(tmp);
 }

 return ret;
}

bool jmc::Solute::solve(const locat& p)
{
 if (p == end()) return true;
 mark(p) = road;
 (*this)(p) = way;
 ans.push(p);

 for (auto& i : operat)
 {
 auto tmp = i(p);
 if (isIn(tmp) && (*this)(tmp) != wall
 && mark(tmp) != road && solve(tmp)) {
 return true;
 }
 }

 ans.pop();
 mark(p) = wall;
 (*this)(p) = road;
 return false;
}

主函数文件(测试用):

#include"Maze.h"
int main(int argc, char* argv[])
{
 jmc::Solute s(30, 30);
 return 0;
}

运行截图:

输出解决路径:

当然这里也可以写成展示每一步走的动画的样子,加个延时与清屏就可以了这里就不演示了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C++实现迷宫算法实例解析

    本文以实例形式描述了C++实现迷宫算法.本例中的迷宫是一个矩形区域,它有一个入口和一个出口.在迷宫的内部包含不能穿越的墙或障碍.障碍物沿着行和列放置,它们与迷宫的矩形边界平行.迷宫的入口在左上角,出口在右下角 本实例迷宫算法的功能主要有: 1.自动生成10*10迷宫图 2.判断是否有迷宫出口,并且画出路线图 具体实现代码如下: # include <iostream> # include <list> # include <sys/timeb.h> # include

  • C++控制台实现随机生成路径迷宫游戏

    本程序是在控制台下随机生成迷宫路径的一个C++程序,可以通过修改宏定义 M 和 N 的值来修改迷宫的长度和宽度,运行程序后 按1开始游戏 按2退出游戏,游戏入口在左上角,出口在右下角,人物(星星)到达右下角出口提示成功闯关. #include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h> #include<iostream.h> #include<ctime

  • C++ 迷宫游戏实现代码

    C++ 迷宫游戏实现代码 题目 通过让游戏角色自动寻找迷宫出口,走出迷宫,来练习C++面向对象之封装的基础知识.迷宫图如下所示,其中X表示墙. 1.程序分析 走出去的原理:遵循右手规则或左手规则.右手扶墙走,就会走出迷宫,反之,亦然. step1 创建迷宫类,打印出迷宫地图. step2 创建走迷宫的人的类. 2.程序实现 MazeMap.h #ifndef MAZEMAP_H #define MAZEMAP_H #include <iostream> #include <Windows

  • 迷宫游戏控制台版C++代码

    本文实例分享了C++设计的一个可以调整大小的迷宫游戏,给定迷宫的入口.如果存在出口,程序能够显示行走的路径,并最终到达出口,并输出"成功走出迷宫":如果不存在出口,程序也能够显示行走的过程,并最终回退到入口,并输出"回退到入口". //这是一个迷宫游戏 #include<iostream> #include<ctime> #include<cstdlib>/*用于生成随机数,形成随机变化的迷宫*/ #include<ioma

  • C++实现简单走迷宫的代码

    本文实例为大家分享了C++实现走迷宫的具体代码,供大家参考,具体内容如下 用n*n个小方格代表迷宫,每个方格上有一个字符0或1,0代表这个格子不能走,1代表这个格子可以走.只能一个格子一个走,而且只能从一个格子向它的上.下.左.右四个方向走,且不能重复.迷宫的入口和出口分别位于左上角和右下角,存在唯一的一条路径能够从入口到达出口,试着找出这条路径. 例如,下图是一个迷宫,红色表示走出迷宫的一条路径 输入:入口坐标(startX,startY),出口坐标(endX,endY) 输出:如果存在这样一

  • C++基于prim实现迷宫生成

    本文实例为大家分享了C++实现迷宫生成的具体代码,供大家参考,具体内容如下 只用到了c++中的vector,其余的和纯C差别不大,纯C可能需要手动弄一个vector太繁琐了不太想弄. 看了迷宫的一些算法,prim还是比较好看的,网上的代码python c#居多,而且不太容易搞懂,那我在这里用C++(大部分C)实现了这个目的 prim算法:随机Prim算法生成的迷宫岔路较多,整体上较为自然而又复杂,算法核心为(根据维基百科). 1.让迷宫全是墙. 2.选一个单元格作为迷宫的通路(我一般选择起点),

  • C++利用循环和栈实现走迷宫

    本文实例为大家分享了C++利用循环和栈实现走迷宫的具体代码,供大家参考,具体内容如下 要求: 1.将地图的数组保存在文件中,从文件中读取行列数 2..动态开辟空间保存地图 3..运行结束后再地图上标出具体的走法 说明: 1.文件中第一行分别放置的是地图的行数和列数 2.其中1表示墙,即路不通,0表示路,即通路 3.程序运行结束后用2标记走过的路径 4.当走到"死胡同"时用3标记此路为死路 5.每到一个点,按照 左 上 右 下 的顺序去试探 6.没有处理入口就是"死胡同&quo

  • C++实现随机生成迷宫地牢

    可以用这个地图核心做成一个无限迷宫类的游戏 main.cpp // Author: FreeKnight 2014-09-02 #include "stdafx.h" #include <iostream> #include <string> #include <random> #include <cassert> /* 简单逻辑流程描述: 将整个地图填满土 在地图中间挖一个房间出来 选中某一房间(如果有多个的话)的墙壁 确定要修建某种新

  • C++ 自定义栈实现迷宫求解

    C++ 自定义栈实现迷宫求解 一:迷宫求解 是一个锻炼我们的算法求解能力的问题,它的实现方法有很多:今天我们就介绍其中的用栈求解的方法. 二:什么是栈: 大家应该都有往袋子里装东西的经历,在往袋子里装满东西之后,当我们去取的时候,总是先从最后放进去的东西的地方去取.也就是后进先出(FILO).虽然栈的单向性用起来会没有链表那样可以在任意位置对数据进行操作,但是正因为如此栈也带来了很大的方便. 三:迷宫求解 现在我们要在下面的迷宫寻找一条可行的路径 1 1 1 1 1 1 1 1 1 1 1 0

  • 使用C/C++语言生成一个随机迷宫游戏

    迷宫相信大家都走过,毕竟书本啊啥啥啥的上面都会有迷宫,主要就是考验你的逻辑思维.那么我们学习C/C++也是需要学习到逻辑思维方式的,那今天我就来分享一下,如何用C/C++打造一个简单的随机迷宫游戏.(代码的话我只截取了如何创建迷宫的代码,如果想要全套代码的话可以加群:558502932,群内有很多C/C++学习资料提供学习,大家一起交流进步) 完整版的迷宫游戏效果如下: 代码如下: //创建迷宫 void CreateMaze(int x,int y) { //定义4个方向 int dir[4]

随机推荐