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;
}
執行截圖:
輸出解決路徑:
當然這裡也可以寫成展示每一步走的動畫的樣子,加個延時與清屏就可以了這裡就不演示了。
歡迎指正與詢問
相關文章
- 【Javascript + Vue】實現隨機生成迷宮圖片JavaScriptVue隨機
- PHP 生成迷宮路線PHP
- Python迷宮生成器Python
- 簡單介紹Python迷宮生成和迷宮破解演算法Python演算法
- (C++)資料結構實驗二——迷宮問題C++資料結構
- PHP 解迷宮之 H 最小PHP
- 解密迷宮問題:三種高效演算法Java實現,讓你輕鬆穿越未知迷宮解密演算法Java
- 【dawn·資料結構】迷宮問題(C++)資料結構C++
- 走迷宮
- 1744 迷宮
- 509迷宮
- PHP 解迷宮之 G + H 最小PHP
- [SDOI2012] 走迷宮 題解
- 【Javascript + Vue】實現對任意迷宮圖片的自動尋路JavaScriptVue
- 回溯和遞迴實現迷宮問題(C語言)遞迴C語言
- JAVA 實現《複雜迷宮》遊戲|CSDN創作打卡Java遊戲
- 迷宮的最短路徑
- 迷宮問題
- 3090 走迷宮
- 3089 探索迷宮
- c++迷宮問題回溯法遞迴演算法C++遞迴演算法
- dfs深度優先搜尋解決迷宮類問題(遍歷)
- 創造你的專屬迷宮 《磚塊迷宮建造者》上架WeGameGAM
- 內容是超正統的迷宮RPG?PSP遊戲《迷宮旅人2》深度解析遊戲
- [省選聯考 2024] 迷宮守衛 題解
- 洛谷 p1605 迷宮問題 詳解
- 迷宮城堡(HDU-1269)
- 迷宮可行路徑數
- 最小生成樹的性質與prim演算法(C++實現)演算法C++
- 使用A*演算法解迷宮最短路徑問題演算法
- 用python深度優先遍歷解迷宮問題Python
- 用Q-learning演算法實現自動走迷宮機器人演算法機器人
- 藍橋杯-走迷宮(BFS)
- 回溯法求迷宮問題
- POJ3984-迷宮問題
- NDT演算法詳解與C++實現演算法C++
- 基於JavaFX圖形介面演示的迷宮建立與路徑尋找Java
- 關於用棧和佇列分別解決走迷宮問題的方法討論(參與者:陳卓,毛敏磊)佇列