首页 > 技术文章 > 《算法七》(深度寻路算法)

Whgy 2020-02-10 20:39 原文

深度寻路算法:
  二维地图:二维数组
  二维数组上标识特定数值作为地图上对象
  应用于RGB游戏中比较广泛
  缺点:1.二维地图,只可以走直线
     2.不一定能找到最佳路径

怎么寻路:
  1.一个方向只能试探一次
  顺时针: 上 右 下 左
  逆时针: 上 左 下 右
  2.需要标记已经走过,走过了的不能再走

深度寻路算法逻辑:

  1.地图

  2 辅助地图

  3.起点 终点

  4.准备栈

  5.标记起点走过

  7起点入栈

  8 寻路:
    8.1 准备变量

    8.2 确定试探点

    8.3 改变当前点试探方向

    8.4 试探试探点能不能走

    8.5 走

    8.6 标记当前点已经走过

    8.7 当前点入栈

 

深度寻路代码:

int _tmain(int argc, _TCHAR* argv[])
{
	//1 地图
	int map[ROWS][COLS] = {
		{ 1, 1, 1, 1, 1, 1, 1, 1 },
		{ 1, 0, 1, 0, 0, 0, 0, 1 },
		{ 1, 0, 1, 0, 1, 0, 1, 1 },
		{ 1, 0, 1, 0, 1, 0, 1, 1 },
		{ 1, 0, 1, 0, 1, 0, 0, 1 },
		{ 1, 0, 1, 0, 1, 0, 1, 1 },
		{ 1, 0, 0, 0, 1, 0, 0, 1 },
		{ 1, 1, 1, 1, 1, 1, 1, 1 }
	};
	//2 辅助地图
	pathNode pathMap[ROWS][COLS] = { 0 };
	for (int i = 0; i < ROWS; i++){
		for (int j = 0; j < COLS; j++){
			pathMap[i][j].val = map[i][j];
		}
	}

	//4 起点 终点
	MyPoint beginPos;
	MyPoint endPos;
	printf("请输入起点(x,y)\n");
	scanf("%d,%d", &(beginPos.col), &(beginPos.row) );
	printf("请输入终点(x,y)\n");
	scanf("%d,%d", &(endPos.col), &(endPos.row));



	//5 准备栈
	MyStack<MyPoint> stack;
	//6 标记起点走过
	pathMap[beginPos.row][beginPos.col].isFind = true;
	//7 起点入栈
	stack.push(beginPos);
	//8 寻路
	//8.1 准备变量

	//当前角色位置
	MyPoint currentPos = beginPos;
	//角色试探点
	MyPoint searchPos;
	bool isFindEnd = false;

	initDraw();//准备图形界面
	while (1){
		searchPos = currentPos;
		switch (pathMap[currentPos.row][currentPos.col].dir)
		{
		case p_up:
			//8.2 确定试探点
			searchPos.row--;
			//8.3 改变当前点试探方向
			pathMap[currentPos.row][currentPos.col].dir = p_right;
			//8.4 试探试探点能不能走
			if (pathMap[searchPos.row][searchPos.col].isFind != true &&//没有走过
				pathMap[searchPos.row][searchPos.col].val != 1)//不是障碍
			{//能走
				//8.5 走
				currentPos = searchPos;
				//8.6 标记当前点已经走过
				pathMap[currentPos.row][currentPos.col].isFind = true;
				//8.7 当前点入栈
				stack.push(currentPos);
			}
			break;
		case p_right:
			//8.2 确定试探点
			searchPos.col++;
			//8.4 改变当前点试探方向
			pathMap[currentPos.row][currentPos.col].dir = p_down;
			//8.3 试探试探点能不能走
			if (pathMap[searchPos.row][searchPos.col].isFind != true &&//没有走过
				pathMap[searchPos.row][searchPos.col].val != 1)//不是障碍
			{//能走
				//8.5 走
				currentPos = searchPos;
				//8.6 标记当前点已经走过
				pathMap[currentPos.row][currentPos.col].isFind = true;
				//8.7 当前点入栈
				stack.push(currentPos);
			}
			break;
		case p_down:
			//8.2 确定试探点
			searchPos.row++;
			//8.4 改变当前点试探方向
			pathMap[currentPos.row][currentPos.col].dir = p_left;
			//8.3 试探试探点能不能走
			if (pathMap[searchPos.row][searchPos.col].isFind != true &&//没有走过
				pathMap[searchPos.row][searchPos.col].val != 1)//不是障碍
			{//能走
				//8.5 走
				currentPos = searchPos;
				//8.6 标记当前点已经走过
				pathMap[currentPos.row][currentPos.col].isFind = true;
				//8.7 当前点入栈
				stack.push(currentPos);
			}
			break;
		case p_left:
			//8.2 确定试探点
			searchPos.col--;
			//8.3 试探试探点能不能走
			if (pathMap[searchPos.row][searchPos.col].isFind != true &&//没有走过
				pathMap[searchPos.row][searchPos.col].val != 1)//不是障碍
			{//能走
				//8.5 走
				currentPos = searchPos;
				//8.6 标记当前点已经走过
				pathMap[currentPos.row][currentPos.col].isFind = true;
				//8.7 当前点入栈
				stack.push(currentPos);
			}
			else{//不能走
				//8.8 回退
				//8.8.1 退栈
				stack.pop();
				//8.8.2 当前点变为栈顶元素
				currentPos = stack.getTop();
			}
			break;
		}

		printMap(map, currentPos);
		drawMap(map, currentPos);


		//找到终点  循环结束
		if (currentPos.row == endPos.row &&
			currentPos.col == endPos.col){
			isFindEnd = true;
			break;
		}
		//栈为空:回到起点  循环结束
		if (stack.isEmpty())
			break;
	}
	//9 打印整个路径
	if (isFindEnd){
		printf("path:");
		while (!stack.isEmpty()){
			//9.1 打印栈顶元素
			printf("(%d,%d)\n", stack.getTop().row, stack.getTop().col);
			//9.2 退栈
			stack.pop();
		}
	}

	while (1);
	return 0;
}

 

完整代码:

//定义栈
//定义栈
template<class T>
class MyStack{
	T* pBuff;
	size_t capacity;
	size_t len;
	
public:
	MyStack(){
		pBuff = NULL;
		capacity = len =0;
	}
	~MyStack(){
		if(pBuff){
			delete[] pBuff;
		}
		pBuff = NULL;
		capacity = len =0;	
	}
	void push(const T& data);//入栈 
	void pop(void);//出栈 
	T getTop(void);//获取栈顶元素 
	bool isEmpty(void);//判断是否为空 
}; 

template<class T>
void MyStack<T>::push(const T& data){//入栈
	if (len >= capacity){
		capacity = capacity + (((capacity >> 1) > 1) ? (capacity >> 1) : 1 );
		T* pNew = new T[capacity];
		if (pBuff){
			memcpy(pNew, pBuff, sizeof(T)*len);
			delete[] pBuff;
		}
		pBuff = pNew;
	}
	pBuff[len++] = data; 
}
 
template<class T> 
//出栈 
void MyStack<T>::pop(void){
	len--;
}

template<class T>
//获取栈顶元素 
T MyStack<T>::getTop(void){
	return pBuff[len - 1];
}

template<class T>
//判断是否为空
bool MyStack<T>::isEmpty(void){
	return (len==0);
} 
 
// 深度寻路算法.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "MyStack.h"
//#include <windows.h>
#include <graphics.h>

/*
	RPG游戏中 地图
	深度寻路算法
		1.二维地图,只能走直线
		2.不一定能找到最佳路径

	广度寻路算法
		
	A星寻路算法
		

寻路:
	1.一个方向只能试探一次
		顺时针: 上 右 下 左
		逆时针: 上 左 下 右
	2.需要标记已经走过,走过了的不能再走
		
*/
//x 横  列数
#define COLS  8
//y 竖  行数
#define ROWS  8
//每个格子大小
#define SPACE  50

//方向枚举
enum direct{p_up,p_right,p_down,p_left};

//辅助地图元素类型
struct pathNode{
	int		val;	//这个点上是什么
	direct	dir;	//试探方向
	bool	isFind;	//有没有走过    0 false  没走过 1 true 走过
};

//点结构
struct MyPoint{
	int row;	//y
	int col;	//x
};

//图片全局变量
IMAGE g_wall, g_road, g_people;


void printMap(int map[ROWS][COLS], MyPoint pos);
void initDraw();
void drawMap(int map[ROWS][COLS], MyPoint pos);

int _tmain(int argc, _TCHAR* argv[])
{
	//1 地图
	int map[ROWS][COLS] = {
		{ 1, 1, 1, 1, 1, 1, 1, 1 },
		{ 1, 0, 1, 0, 0, 0, 0, 1 },
		{ 1, 0, 1, 0, 1, 0, 1, 1 },
		{ 1, 0, 1, 0, 1, 0, 1, 1 },
		{ 1, 0, 1, 0, 1, 0, 0, 1 },
		{ 1, 0, 1, 0, 1, 0, 1, 1 },
		{ 1, 0, 0, 0, 1, 0, 0, 1 },
		{ 1, 1, 1, 1, 1, 1, 1, 1 }
	};
	//2 辅助地图
	pathNode pathMap[ROWS][COLS] = { 0 };
	for (int i = 0; i < ROWS; i++){
		for (int j = 0; j < COLS; j++){
			pathMap[i][j].val = map[i][j];
		}
	}

	//4 起点 终点
	MyPoint beginPos;
	MyPoint endPos;
	printf("请输入起点(x,y)\n");
	scanf("%d,%d", &(beginPos.col), &(beginPos.row) );
	printf("请输入终点(x,y)\n");
	scanf("%d,%d", &(endPos.col), &(endPos.row));



	//5 准备栈
	MyStack<MyPoint> stack;
	//6 标记起点走过
	pathMap[beginPos.row][beginPos.col].isFind = true;
	//7 起点入栈
	stack.push(beginPos);
	//8 寻路
	//8.1 准备变量

	//当前角色位置
	MyPoint currentPos = beginPos;
	//角色试探点
	MyPoint searchPos;
	bool isFindEnd = false;

	initDraw();//准备图形界面
	while (1){
		searchPos = currentPos;
		switch (pathMap[currentPos.row][currentPos.col].dir)
		{
		case p_up:
			//8.2 确定试探点
			searchPos.row--;
			//8.3 改变当前点试探方向
			pathMap[currentPos.row][currentPos.col].dir = p_right;
			//8.4 试探试探点能不能走
			if (pathMap[searchPos.row][searchPos.col].isFind != true &&//没有走过
				pathMap[searchPos.row][searchPos.col].val != 1)//不是障碍
			{//能走
				//8.5 走
				currentPos = searchPos;
				//8.6 标记当前点已经走过
				pathMap[currentPos.row][currentPos.col].isFind = true;
				//8.7 当前点入栈
				stack.push(currentPos);
			}
			break;
		case p_right:
			//8.2 确定试探点
			searchPos.col++;
			//8.4 改变当前点试探方向
			pathMap[currentPos.row][currentPos.col].dir = p_down;
			//8.3 试探试探点能不能走
			if (pathMap[searchPos.row][searchPos.col].isFind != true &&//没有走过
				pathMap[searchPos.row][searchPos.col].val != 1)//不是障碍
			{//能走
				//8.5 走
				currentPos = searchPos;
				//8.6 标记当前点已经走过
				pathMap[currentPos.row][currentPos.col].isFind = true;
				//8.7 当前点入栈
				stack.push(currentPos);
			}
			break;
		case p_down:
			//8.2 确定试探点
			searchPos.row++;
			//8.4 改变当前点试探方向
			pathMap[currentPos.row][currentPos.col].dir = p_left;
			//8.3 试探试探点能不能走
			if (pathMap[searchPos.row][searchPos.col].isFind != true &&//没有走过
				pathMap[searchPos.row][searchPos.col].val != 1)//不是障碍
			{//能走
				//8.5 走
				currentPos = searchPos;
				//8.6 标记当前点已经走过
				pathMap[currentPos.row][currentPos.col].isFind = true;
				//8.7 当前点入栈
				stack.push(currentPos);
			}
			break;
		case p_left:
			//8.2 确定试探点
			searchPos.col--;
			//8.3 试探试探点能不能走
			if (pathMap[searchPos.row][searchPos.col].isFind != true &&//没有走过
				pathMap[searchPos.row][searchPos.col].val != 1)//不是障碍
			{//能走
				//8.5 走
				currentPos = searchPos;
				//8.6 标记当前点已经走过
				pathMap[currentPos.row][currentPos.col].isFind = true;
				//8.7 当前点入栈
				stack.push(currentPos);
			}
			else{//不能走
				//8.8 回退
				//8.8.1 退栈
				stack.pop();
				//8.8.2 当前点变为栈顶元素
				currentPos = stack.getTop();
			}
			break;
		}

		printMap(map, currentPos);
		drawMap(map, currentPos);


		//找到终点  循环结束
		if (currentPos.row == endPos.row &&
			currentPos.col == endPos.col){
			isFindEnd = true;
			break;
		}
		//栈为空:回到起点  循环结束
		if (stack.isEmpty())
			break;
	}
	//9 打印整个路径
	if (isFindEnd){
		printf("path:");
		while (!stack.isEmpty()){
			//9.1 打印栈顶元素
			printf("(%d,%d)\n", stack.getTop().row, stack.getTop().col);
			//9.2 退栈
			stack.pop();
		}
	}


	LOGFONT font = { 0 };
	font.lfHeight = 25;
	font.lfWeight = 10;
	settextstyle(&font);
	outtextxy((COLS*SPACE - 110) / 2, (ROWS*SPACE - 25) / 2, L"恭喜你通关!");




	while (1);
	return 0;
}

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){//人
				printf("人");
			}
			else if (map[i][j] == 1){//障碍
				printf("墙");
			}
			else{//路
				printf("  ");
			}
		}
		printf("\n");
	}
	Sleep(500);
}

void initDraw(){
	initgraph(COLS*SPACE, ROWS*SPACE, SHOWCONSOLE);
	loadimage(&g_wall, L"wall.jpg", SPACE, SPACE, true);
	loadimage(&g_road, L"road.jpg", SPACE, SPACE, true);
	loadimage(&g_people, L"people.jpg", SPACE, SPACE, true);
}

void drawMap(int map[ROWS][COLS], MyPoint pos){
	cleardevice();//清屏
	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, &g_people);
			}
			else if (map[i][j] == 1){//障碍
				putimage(j*SPACE, i*SPACE, &g_wall);
			}
			else{//路
				putimage(j*SPACE, i*SPACE, &g_road);
			}
		}
	}
}

 

推荐阅读