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;
}
執行截圖:
輸出解決路徑:
當然這裡也可以寫成展示每一步走的動畫的樣子,加個延時與清屏就可以了這裡就不演示了。
歡迎指正與詢問
相關文章
- C++基於控制檯的迷宮實現(上)C++
- 【Javascript + Vue】實現隨機生成迷宮圖片JavaScriptVue隨機
- PHP 生成迷宮路線PHP
- 回溯法解決迷宮問題
- Python迷宮生成器Python
- 簡單介紹Python迷宮生成和迷宮破解演算法Python演算法
- 隨機迷宮生成演算法隨機演算法
- 用C語言解決迷宮問題C語言
- (C++)資料結構實驗二——迷宮問題C++資料結構
- 走迷宮
- 1744 迷宮
- PHP 解迷宮之 H 最小PHP
- 解密迷宮問題:三種高效演算法Java實現,讓你輕鬆穿越未知迷宮解密演算法Java
- PHP 解迷宮之 G + H 最小PHP
- 如何用程式解圖片迷宮?
- 【dawn·資料結構】迷宮問題(C++)資料結構C++
- JAVA 實現《複雜迷宮》遊戲|CSDN創作打卡Java遊戲
- 509迷宮
- 回溯和遞迴實現迷宮問題(C語言)遞迴C語言
- 【Javascript + Vue】實現對任意迷宮圖片的自動尋路JavaScriptVue
- dfs深度優先搜尋解決迷宮類問題(遍歷)
- c++迷宮問題回溯法遞迴演算法C++遞迴演算法
- 內容是超正統的迷宮RPG?PSP遊戲《迷宮旅人2》深度解析遊戲
- 【面試】如何找到迷宮出口面試
- [SDOI2012] 走迷宮 題解
- 回溯法求迷宮問題
- 自動走迷宮小遊戲~遊戲
- 藍橋杯-走迷宮(BFS)
- POJ3984-迷宮問題
- 洛谷 p1605 迷宮問題 詳解
- 使用A*演算法解迷宮最短路徑問題演算法
- 迷宮問題【資料結構實驗報告】資料結構
- 用 Canvas + WASM 畫一個迷宮CanvasASM
- 51nod 1459 迷宮遊戲遊戲
- C語言動態走迷宮C語言
- 藍橋杯-迷宮(BFS+DFS)
- 用python深度優先遍歷解迷宮問題Python
- [省選聯考 2024] 迷宮守衛 題解