走迷宫问题是指在给定地图中,从寻找一条从起点(设为左上角)到终点(设为右下角)的路径的问题。假设迷宫形状如下:
其中一个方格表示一个位置,从一个位置有上下左右四种走法,但每个位置的四个方向上可能会有墙壁存在,墙壁用黑线表示,无法通过,要求寻找一条从左上角到右下角的路线。
深度优先搜索可以很好地解决迷宫问题,深度优先搜索的思路是从一个位置开始,尝试向某个能到达的方向走一步,在从新的位置重复这个步骤,要注意走过的位置就不要再走了,直到走到一个无路可走的位置时返回上一个位置,尝试上一个位置的另一方向。可以看出深度优先搜索就相当于时枚举出了各种可能的路径,像个铁头娃一路走到底,没路了退一点再朝另一个方向一路走到底,直到把出口路径试出来,因此深度优先搜索得到的路径往往不是最优的。
以下是使用深度优先搜索走迷宫的练习,后面附带一个用SDL对走迷宫进行可视化的过程,程序会随机生成迷宫地图,并尝试走迷宫,但是毕竟是随机生成不保证一定有解,若存在路径则会用红线标注出来。SDL是一个简单的图形库,感兴趣的可以了解一下。效果图如下:
代码很简单,直接贴上,迷宫大小可以在代码里改变。maze.h和maze.cpp实现生成迷宫和走迷宫功能,将maze.cpp中的main函数注释去掉即可运行,后面的SDLtest是可视化部分,需要配置SDL库。
maze.h
扫描二维码关注公众号,回复:
2240756 查看本文章
#pragma once
#include <iostream>
#include <vector>
#include <random>
#define MX 5
#define MY 5
struct point {
int i;
int j;
point() = default;
point(int ii, int jj) :i(ii), j(jj) {}
};
class cell {
public:
cell() = default;
cell(int ttop, int tdown, int tright, int tleft) :top(ttop), down(tdown), right(tright), left(tleft), used(false) {}
bool used;
int top, down, right, left;
};
class maze {
public:
maze() {
for (int i = 0; i<MY; i++) {
std::vector<cell> cell_row(MX);
cells.push_back(cell_row);
}
}
std::random_device rd;
int generate();
void print() const;
void draw() const;
//#ifdef whole
void render() const;
void renderroute() const;
// #endif
int find(int i, int j);
point getroute(int step) {
if (!route.empty())
return route[step];
}
bool routeempty() {
return route.empty();
}
void showroute();
private:
std::vector <std::vector<cell> > cells;
std::vector <point> route;
int rand1();
};
maze.cpp
#include "stdafx.h"
#include "maze.h"
void maze::showroute(){
if (route.empty()){
std::cout<<"empty route";
return;
}
std::vector<point>::iterator it;
for (it=route.begin();it !=route.end();it++){
std::cout<<"("<<it->i<<","<<it->j<<")";
}
}
int maze::generate(){
for (int j=0;j<MX;j++){
cells[0][j].top=0;
}
for (int i=0;i<MY;i++){
cells[i][0].left=0;
}
for (int i=0;i<MY;i++){
for (int j=0;j<MX;j++){
cells[i][j].right=rand1();
cells[i][j].down=rand1();
if (j>=1){
cells[i][j].left=cells[i][j-1].right;
}
if (i>=1){
cells[i][j].top=cells[i-1][j].down;
}
}
}
for (int j=0;j<MX;j++){
cells[MY-1][j].down=0;
}
for (int i=0;i<MY;i++){
cells[i][MX-1].right=0;
}
return 1;
}
int maze::rand1(){
return rd()%2;
}
void maze::print() const{
for (int i=0;i<MY;i++){
for (int j=0;j<MX;j++){ std::cout<<cells[i][j].top<<cells[i][j].down<<cells[i][j].left<<cells[i][j].right<<" ";
}
std::cout<<std::endl;
}
}
void maze::draw() const{
for (int i=0;i<MY;i++){
for (int j=0;j<MX;j++){
std::cout<<" "<<cells[i][j].top<<" ";
}
std::cout<<std::endl;
for (int j=0;j<MX;j++){
std::cout<<cells[i][j].left<<" "<<cells[i][j].right<<" ";
}
std::cout<<std::endl;
for (int j=0;j<MX;j++){
std::cout<<" "<<cells[i][j].down<<" ";
}
std::cout<<std::endl;
}
}
int maze::find(int i,int j){
route.clear();
cells[i][j].used=1;
if ((i==MY-1)&&(j==MX-1)) {
route.insert(route.begin(),point(i,j));
cells[i][j].used=0;
return 1;
}
if (cells[i][j].top==1&&cells[i-1][j].used==0){
if (find(i-1,j)==1) {
route.insert(route.begin(),point(i,j));
cells[i][j].used=0;
return 1;
}
}
if (cells[i][j].down==1&&cells[i+1][j].used==0){
if (find(i+1,j)==1) {
route.insert(route.begin(),point(i,j));
cells[i][j].used=0;
return 1;
}
}
if (cells[i][j].left==1&&cells[i][j-1].used==0){
if (find(i,j-1)==1) {
route.insert(route.begin(),point(i,j));
cells[i][j].used=0;
return 1;
}
}
if (cells[i][j].right==1&&cells[i][j+1].used==0){
if (find(i,j+1)==1) {
route.insert(route.begin(),point(i,j));
cells[i][j].used=0;
return 1;
}
}
cells[i][j].used=0;
return 0;
}
/*
int main() {
maze m;
m.generate();
m.print();
m.draw();
int a, b;
if (m.find(0, 0)) {
m.showroute();
std::cout << "found" << std::endl;
}
else std::cout << "not found" << std::endl;
while (1) {
std::cin >> a >> b;
std::cout << a << "," << b << std::endl;
if (m.find(a, b)) {
m.showroute();
std::cout << "found" << std::endl;
}
else std::cout << "not found" << std::endl;
}
}
*/
SDLtest
#include "stdafx.h"
#define SDL_MAIN_HANDLED
#include <iostream>
#include <vector>
#include "maze.h"
#include <SDL.h>
#define bx 66
#define by 66
#define gap 66
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
void maze::render() const {
for (int j = 0; j<MX; j++) {
if (cells[0][j].top == 0) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
}
else {
SDL_SetRenderDrawColor(renderer, 175, 175, 225, 0);
}
SDL_RenderDrawLine(renderer, bx + j*gap, by, bx + (j + 1)*gap, by);
}
for (int i = 0; i<MY; i++) {
if (cells[i][0].left == 0) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
}
else {
SDL_SetRenderDrawColor(renderer, 175, 175, 225, 0);
} SDL_RenderDrawLine(renderer, bx, by + i*gap, bx, by + (i + 1)*gap);
}
for (int i = 0; i<MY; i++) {
for (int j = 0; j<MX; j++) {
if (cells[i][j].down == 0) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
}
else {
SDL_SetRenderDrawColor(renderer, 175, 175, 225, 0);
} SDL_RenderDrawLine(renderer, bx + j*gap, by + (i + 1)*gap, bx + (j + 1)*gap, by + (i + 1)*gap);
if (cells[i][j].right == 0) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
}
else {
SDL_SetRenderDrawColor(renderer, 175, 175, 225, 0);
} SDL_RenderDrawLine(renderer, bx + (j + 1)*gap, by + i*gap, bx + (j + 1)*gap, by + (i + 1)*gap);
}
}
}
void maze::renderroute() const {
if (route.empty()) {
return;
}
int x1, x2, y1, y2;
for (auto it = route.begin(); it != (route.end() - 1); it++) {
y1 = (it->i)*gap + 0.5*gap + by;
y2 = ((it + 1)->i)*gap + 0.5*gap + by;
x1 = (it->j)*gap + 0.5*gap + bx;
x2 = ((it + 1)->j)*gap + 0.5*gap + bx;
SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
}
}
void init() {
SDL_Init(SDL_INIT_VIDEO);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
window = SDL_CreateWindow("MAZE", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 480, 480, SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED || SDL_RENDERER_PRESENTVSYNC);
}
void close() {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
int main() {
maze m;
m.generate();
m.find(0, 0);
init();
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION,
"PROMPT", "Click on the screen to create a new maze", NULL);
SDL_SetRenderDrawColor(renderer, 100, 100, 200, 0);
SDL_RenderClear(renderer);
bool quit = false;
SDL_Event e;
while (!quit) {
SDL_SetRenderDrawColor(renderer, 155, 155, 200, 0);
SDL_RenderClear(renderer);
while (SDL_PollEvent(&e)) {
switch (e.type) {
case SDL_QUIT: quit = true;
break;
case SDL_MOUSEBUTTONUP:
m.generate();
if (m.find(0, 0)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION,
"result", "Found it.", NULL);
}
else {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION,
"result", "Cannot find the route.please try more.", NULL);
}
break;
default:
break;
}
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
m.render();
SDL_SetRenderDrawColor(renderer, 250, 0, 0, 0);
m.renderroute();
SDL_RenderPresent(renderer);
}
return 0;
}