深度优先搜索走迷宫+SDL可视化

https://apriljia.com/2018/07/18/%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2%E8%B5%B0%E8%BF%B7%E5%AE%ABsdl%E5%8F%AF%E8%A7%86%E5%8C%96/

走迷宫问题是指在给定地图中,从寻找一条从起点(设为左上角)到终点(设为右下角)的路径的问题。假设迷宫形状如下:

其中一个方格表示一个位置,从一个位置有上下左右四种走法,但每个位置的四个方向上可能会有墙壁存在,墙壁用黑线表示,无法通过,要求寻找一条从左上角到右下角的路线。

深度优先搜索可以很好地解决迷宫问题,深度优先搜索的思路是从一个位置开始,尝试向某个能到达的方向走一步,在从新的位置重复这个步骤,要注意走过的位置就不要再走了,直到走到一个无路可走的位置时返回上一个位置,尝试上一个位置的另一方向。可以看出深度优先搜索就相当于时枚举出了各种可能的路径,像个铁头娃一路走到底,没路了退一点再朝另一个方向一路走到底,直到把出口路径试出来,因此深度优先搜索得到的路径往往不是最优的。

以下是使用深度优先搜索走迷宫的练习,后面附带一个用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;
}

猜你喜欢

转载自blog.csdn.net/mingzhiqing/article/details/81097602