寻路算法 --- 深度寻路算法

深度寻路:大地图 空旷地形 适用于不一定要找到最佳路径的情况  尽量每个角落都走遍

广度寻路:不需要回退 一定能找到最佳路径 循环多 小地图

#include <iostream>
using namespace std;

#include <graphics.h>

#include "MyStack.h"

//格子宽高
#define SPACE   80


//Y   竖着 行数
#define ROWS  10
//X   横着 列数
#define COLS  10
//状态	 	  路   墙
enum states{ Road,Wall };
//4个方向可以试探-> 人为规定试探方向 枚举
enum direct{p_up,p_down,p_left,p_right};

//用数组下标区分地图上的某一个位置
class MyPoint{
public:
	int row, col;          //为了操作方便,写成公有属性-> 行 列
	friend bool operator==(const MyPoint& p1, const MyPoint& p2);
};

bool operator==(const MyPoint& p1, const MyPoint& p2){//双目运算符一般声明为友元
	if ((p1.row == p2.row) && (p1.col == p2.col) ) return true;
	return false;
}

//辅助地图-> 地图元素不同
class PathNode{
public:
	//states		val;	//地图上的值
	direct		dir;		//当前试探方向
	bool		isFind;		//是否走过
};

//图片变量
IMAGE pos, ren, road, wall;


void printMap(int map[ROWS][COLS], MyPoint pos);         //显示地图
void drawMap(int map[ROWS][COLS],MyPoint pos);

int main(){
	initgraph(SPACE*COLS, SPACE*ROWS,SHOWCONSOLE);       //窗口宽高
	loadimage(&road, "road.bmp", SPACE, SPACE, true);
	loadimage(&wall, "wall.bmp", SPACE, SPACE, true);
	loadimage(&ren, "ren.bmp", SPACE, SPACE, true);
	loadimage(&pos, "pos.bmp", SPACE/2, SPACE/2, true);  //点
	//地图
	int map[ROWS][COLS] = {
		{ Wall, Wall, Wall, Wall, Wall, Wall, Wall, Wall, Wall, Wall },
		{ Wall, Road, Wall, Road, Road, Wall, Wall, Road, Road, Wall },
		{ Wall, Road, Wall, Road, Wall, Wall, Wall, Road, Wall, Wall },
		{ Wall, Road, Wall, Road, Road, Road, Wall, Road, Wall, Wall },
		{ Wall, Road, Road, Road, Wall, Road, Wall, Road, Wall, Wall },
		{ Wall, Road, Wall, Wall, Wall, Road, Wall, Road, Wall, Wall },
		{ Wall, Road, Wall, Wall, Wall, Road, Road, Road, Road, Wall },
		{ Wall, Road, Wall, Road, Road, Road, Wall, Road, Wall, Wall },
		{ Wall, Road, Wall, Road, Wall, Road, Wall, Road, Road, Wall },
		{ Wall, Wall, Wall, Wall, Wall, Wall, Wall, Wall, Wall, Wall }
	};
	//辅助地图-> 1.记录每个点的当前试探方向 2.记录每个点有没有走过
	PathNode pathMap[ROWS][COLS] = { p_up };
	/* 有3个元素的情况 记录地图上的值,需要原地图的值拷贝到辅助地图中-> 如果只有两个元素可以不考虑
	for (int i = 0; i < ROWS; i++){
		for (int j = 0; j < COLS; j++){
			pathMap[i][j] = map[i][j];
		}
	}
	*/
	MyPoint begPos = { 1, 1 };//起点 
	MyPoint endPos = { 8, 8 };//终点

	
	while (1);
	return 0;
}

void drawMap(int map[ROWS][COLS], MyPoint pos){
	for (int i = 0; i < ROWS; i++){
		for (int j = 0; j < COLS; j++){
			if (i == pos.row && j == pos.col){
				putimage(j*SPACE, i*SPACE, &ren);
			}
			else if (Wall == map[i][j]){
				putimage(j*SPACE, i*SPACE, &wall);
			}
			else if (Road == map[i][j]){
				putimage(j*SPACE, i*SPACE, &road);
			}
		}
	}
}
void printMap(int map[ROWS][COLS], MyPoint pos){
	system("cls");
	for (int i = 0; i < ROWS; i++){
		for (int j = 0; j < COLS; j++){
			if (i == pos.row && j == pos.col){
				cout << "人";
			}
			else if (Wall == map[i][j]){
				cout << "墙";
			}
			else if (Road == map[i][j]){
				cout << "  ";
			}
		}
		cout << endl;
	}
}

深度寻路算法思想

有4个可以移动的方向,需要逐个去尝试、去找 -> 一般会人为规定试探的顺序

    1. 只走直线,总共有四个方向可以试探,没有八个方向用来试探(不能走斜线)
        人为规定试探顺序      一般来说是 顺时针 或 逆时针-> 走格子类的游戏,地图中有很多个宝箱,不知道宝箱在哪里,用深度寻路算法,从某个地方出发,一路去找,每个角落都去走一遍,把每个宝箱都打开. . .
        这里按照上下左右的顺序-> 给每一个格子都人为设置试探顺序:每一个格子一开始都是往上走,一定是按照上、下、左、右的顺序
        并且记录每个点的当前试探方向-> 节约时间,往上试过了,往下试过了,就没必要重复试探,直接往左边开始. . .
    2. 走过的标记为走过-> 判断是否能走:1.判断是路,不是障碍物  2.并且没有走过
    3. 回退机制-> 上、下、左、右都不能走的情况,不能直接寻路结束,应该有回退机制
        3.1 每走一步 把每一个点的坐标都入栈
        3.2 需要回退的时候
            3.2.1 删除栈顶元素
            3.2.2 跳到当前栈顶元素处

所有的回退,存档,函数传参都是栈结构实现的:利用先进后出的特性,可以存数据,可以很好地记录顺序,需要撤销、回退时,非常方便

人物到达死胡同,需要回退,只需要把栈顶元素删掉,让人物跳到当前栈顶处即可,就实现了回退,要加入元素,在当前栈顶入栈

注意:回退时,已经把它从栈中删掉了,所以,从起点找到终点后,当前栈中记录的元素为蓝色部分-> 即从起点找到终点的路径,实际走的路线为红色部分

1.已知当前点的坐标,找试探点-> 在辅助地图中记录了当前点的当前试探方向

2.判断试探点是否能走, 如果能走,走的时候标记点已经走过了,要入栈 如果不能走:

2.1.(前面三个方向中某一个能走)试探方向改变 

2.2.(第四个方向还是不能走) 回退,删除栈顶元素,跳到当前栈顶元素处即可 

3.判断是否结束循环

3.1找到终点了

3.2没有找到终点,但是栈空了-> 整个地图都找遍了

//准备一个栈-> 栈中存坐标
	MyStack<MyPoint> stack;
	//起点标记为走过
	pathMap[begPos.row][begPos.col].isFind = true;
	//起点入栈
	stack.push(begPos);

	//当前点的坐标
	MyPoint currentPos = begPos;
	//试探点-> 用于试探
	MyPoint searchPos;
	//是否找到终点
	bool isFindEnd = false;
	//循环寻路
	while (1){
		
		searchPos = currentPos;//让试探点==当前点
		switch (pathMap[currentPos.row][currentPos.col].dir){//判断当前点的当前试探方向-> 辅助地图
		case p_up:              //上
			searchPos.row--;    //1 找到试探点 试探点==当前点 当前点的当前试探方向往上 y-1
			//2 判断试探点是否能走
			//试探方向改变-> 前面3个方向不管能不能走都直接改 当前点的 试探方向-> 节约代码
			pathMap[currentPos.row][currentPos.col].dir = p_down;       //枚举类型不能直接++ 采用赋值的方式
			if (pathMap[searchPos.row][searchPos.col].isFind == false &&//没有走过
				map[searchPos.row][searchPos.col] == Road){//试探点的值Road 是路 可以走
				//2.1 能走   
				currentPos = searchPos;//走  
				pathMap[currentPos.row][currentPos.col].isFind = true; //辅助地图中标记走过 
				stack.push(currentPos);//入栈
			}
            //else{//2.2 不能走
            //}                
			break;
		case p_down:          //下
			searchPos.row++;  //1 找到试探点
			//2 判断是否能走
			//试探方向改变
			pathMap[currentPos.row][currentPos.col].dir = p_left;
			if (pathMap[searchPos.row][searchPos.col].isFind == false &&//没有走过
				map[searchPos.row][searchPos.col] == Road){//是路 可以走
				//2.1 能走   
				currentPos = searchPos;//走  
				pathMap[currentPos.row][currentPos.col].isFind = true;//标记走过 
				stack.push(currentPos);//入栈
			}
			break;
		case p_left:          //左
			searchPos.col--;  //1 找到试探点
			//2 判断是否能走
			//试探方向改变
			pathMap[currentPos.row][currentPos.col].dir = p_right;
			if (pathMap[searchPos.row][searchPos.col].isFind == false &&//没有走过
				map[searchPos.row][searchPos.col] == Road){//是路 可以走
				//2.1 能走   
				currentPos = searchPos;//走  
				pathMap[currentPos.row][currentPos.col].isFind = true;//标记走过 
				stack.push(currentPos);//入栈
			}
			break;
		case p_right:         //右
			searchPos.col++;  //1 找到试探点-> 往右不需要修改试探方向
			//2 判断是否能走
			if (pathMap[searchPos.row][searchPos.col].isFind == false &&//没有走过
				map[searchPos.row][searchPos.col] == Road){//是路 可以走
				//2.1 能走   
				currentPos = searchPos;//走  
				pathMap[currentPos.row][currentPos.col].isFind = true;//标记走过 
				stack.push(currentPos);//入栈
			}
			else{//2.2.2 第四个方向还不能走  
				//回退
				stack.pop();                 //删除栈顶元素
				currentPos = stack.getTop(); //跳到当前栈顶元素处-> 获取当前栈顶元素
			}
			break;
		}//end of switch (pathMap[currentPos.row][currentPos.col].dir)
		printMap(map, currentPos);           //每一步都做一次打印
		drawMap(map, currentPos);
		Sleep(300);
		//3 判断是否结束循环
		//3.1 找到终点了结束循环
		if (endPos == currentPos){//需要运算符重载-> 没有与这些操作数匹配的"=="运算符
			isFindEnd = true;     //不知道是由于栈空还是找到终点结束循环-> 需要做标记 如果找到终点标记它为真
			break;
		}
		//3.2 栈空了结束循环
		if (stack.isEmpty()) break;
	}

	if (isFindEnd){//找到终点
		cout << "喜大普奔,找到终点啦!" << endl;

		while (!stack.isEmpty()){//栈不等于空 打印路径 栈顶->栈底-> 逆着打印
			cout << "(" << stack.getTop().row << "," 
				<< stack.getTop().col << ") ";
			putimage(stack.getTop().col*SPACE + SPACE/4, 
				stack.getTop().row*SPACE + SPACE / 4, &pos);
			stack.pop();//退掉一个
		}
		cout << endl;

	}

 MyStack.h

#pragma once
//数组描述栈
//pArr[0] 栈底   pArr[size-1] 栈顶
#include <iostream>
using namespace std;

template<class T>
class MyStack
{
	T*		pArr;		//指向动态数组
	int		size;		//描述动态数组元素个数
	int		capacity;	//当前空间
public:
	MyStack(){
		pArr = NULL;
		capacity = size = 0;
	}
	~MyStack(){
		_clear();
	}
	//入栈
	void push(const T& data);
	//出栈
	T pop();
	//遍历栈   栈底到栈顶
	void travel();
	//获取栈顶元素
	T getTop()const{ return pArr[size - 1]; }
	//判断栈是否为空
	bool isEmpty()const{
		return (0 == size);
	}
	//返回栈中元素个数
	int getSize()const{ return size; }
private:
	void _clear();
};
template<class T>
void MyStack<T>::_clear(){
	if (pArr){
		delete[] pArr;
		pArr = NULL;
		capacity = size = 0;
	}
}


template<class T>
//遍历数组
void MyStack<T>::travel(){
	cout << "MyStack   capacity:" << capacity << ",size:" << size << ":";
	for (int i = 0; i < size; i++)
		cout << *(pArr + i) << " ";
	cout << endl;
}
template<class T>
//入栈
void MyStack<T>::push(const T& data){
	//0 判断是否需要开空间
	if (size >= capacity){
		//计算新开空间大小
		capacity = capacity +
			(((capacity >> 1) > 1) ? (capacity >> 1) : 1);
		//1 开空间  
		T* pNew = new T[capacity];
		if (pArr){
			//2 原有数据拷贝过来
			memcpy(pNew, pArr, sizeof(T)*size);
			//3 释放原有内存段
			delete[] pArr;
		}
		//4 pArr指向新内存段
		pArr = pNew;
	}
	//5 新数据进来
	pArr[size++] = data;
}

template<class T>
//出栈
T MyStack<T>::pop(){
	if (size > 0){
		T temp = pArr[size - 1];
		size--;
		//cout << "出栈成功!" << endl;
		return temp;
	}
	//cout << "出栈失败!" << endl;
	//return (T)NULL;
}

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiuqiuyaq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值