1. 程式人生 > >《演算法七》(深度尋路演算法)

《演算法七》(深度尋路演算法)

深度尋路演算法:
  二維地圖:二維陣列
  二維陣列上標識特定數值作為地圖上物件
  應用於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);
			}
		}
	}
}

&n