• micropather实现A*算法


    MicroPather is a path finder and A* solver (astar or a-star) written in platform independent C++ that can be easily integrated into existing code. MicroPather focuses on being a path finding engine for video games but is a generic A* solver.

    There is plenty of pathing code out there, but most if it seems to focus on teaching somewhat how to write an A* solver, rather than being utility code for pathing. MicroPather is firmly aimed at providing functionality, not at being a tutorial.

    MicroPather's primary goal is to be easy to use:

    1. An easy API
    2. No requirements on the host program to change its data structures or objects
    3. No library or 'make' - just add 1 .cpp and 1 .h file to your project.

    Enjoy, and thanks for checking out MicroPather!


    官方网站可以下载其sdk和demo。

    demo1的代码如下:

    dungeon.cpp

    #define USE_PATHER
    
    #include <ctype.h>
    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    
    #include <vector>
    #include <iostream>
    
    #ifdef USE_PATHER
    
    #include "micropather.h"
    using namespace micropather;
    #endif
    
    
    const int MAPX = 30;
    const int MAPY = 10;
    const char gMap[MAPX*MAPY+1] =
    //"012345678901234567890123456789"
    "     |      |                |"
    "     |      |----+    |      +"
    "---+ +---DD-+      +--+--+    "
    "   |                     +-- +"
    "        +----+  +---+         "
    "---+ +  D    D            |   "
    "   | |  +----+    +----+  +--+"
    "   D |            |    |      "
    "   | +-------+  +-+    |--+   "
    "---+                   |     +";
    
    class Dungeon
    #ifdef USE_PATHER
    	: public Graph
    #endif
    {
    private:
    	Dungeon( const Dungeon& );
    	void operator=( const Dungeon& );
    
    	// 寻路的起始点位置
    	int playerX, playerY;
    
    	// 寻路的最终路径
    	std::vector<void*> path;
    
    	// 门是否打开
    	bool doorsOpen;
    	// 
    	bool showConsidered;
    
    	MicroPather* pather;
    
    public:
    	Dungeon() : playerX( 0 ), playerY( 0 ), doorsOpen( false ), showConsidered( false ), pather( 0 )
    	{
    		// this : The "map" that implements the Graph callbacks. 
    		// 20 : How many states should be internally allocated at a time. 
    		// This can be hard to get correct. The higher the value, 
    		// the more memory MicroPather will use.
    		pather = new MicroPather( this, 20 );	// Use a very small memory block to stress the pather
    	}
    
    	virtual ~Dungeon() 
    	{
    		delete pather;
    	}
    
    	int X()	{ return playerX; }
    	int Y() { return playerY; }
    
    	// 校验和,用于debug
    	unsigned Checksum() { return pather->Checksum(); }
    
    	void ClearPath()
    	{
    #ifdef USE_PATHER
    		path.resize( 0 );
    #endif
    	}
    
    	// 
    	void ToggleTouched() 
    	{ 	
    		showConsidered = !showConsidered; 
    		// Reset() Should be called whenever the cost between states or 
    		// the connection between states changes. 
    		// Also frees overhead memory used by MicroPather, 
    		// and calling will free excess memory. 
    		pather->Reset();					 
    	}
    
    	// 打开或者关闭Door
    	void ToggleDoor() 
    	{ 
    		doorsOpen = !doorsOpen; 
    #ifdef USE_PATHER
    		pather->Reset();
    #endif	
    	}
    
    	// 目标点(nx, ny)是否可到达(" "或者"D")
    	int Passable( int nx, int ny ) 
    	{
    		if ( nx >= 0 && nx < MAPX 
    			&& ny >= 0 && ny < MAPY )
    		{
    			int index = ny * MAPX + nx;
    			char c = gMap[index];
    			if ( c == ' ' )
    				return 1;
    			else if ( c == 'D' )
    				return 2;
    		}		
    		return 0;
    	}
    
    	// 计算起始位置到(nx,ny)的路径及其代价
    	int SetPos( int nx, int ny ) 
    	{
    		int result = 0;
    		if ( Passable( nx, ny ) == 1 )
    		{
    #ifdef USE_PATHER
    			float totalCost;
    			if ( showConsidered )
    				pather->Reset();
    			/*
    			int micropather::MicroPather::Solve  
    			( void * startState,  
    			  void *  endState,  
    			  std::vector< void * > *  path,  
    			  float *  totalCost   
    			) 
    			Solve for the path from start to end.
    			Parameters:
    			startState:  Input, the starting state for the path.  
    			endState:  Input, the ending state for the path.  
    			path:  Output, a vector of states that define the path. Empty if not found.  
    			totalCost:  Output, the cost of the path, if found.  
    
    			Returns:
    			Success or failure, expressed as SOLVED, NO_SOLUTION, or START_END_SAME. 
    			*/
    			result = pather->Solve( XYToNode( playerX, playerY ), XYToNode( nx, ny ), &path, &totalCost );
    
    			if ( result == MicroPather::SOLVED ) 
    			{
    				// 将玩家位置设置为(nx, ny)
    				playerX = nx;
    				playerY = ny;
    			}
    			printf( "Pather returned %d\n", result );
    #else
    			playerX = nx;
    			playerY = ny;
    #endif
    		}
    		return result;
    	}
    
    	void Print() 
    	{
    		char buf[ MAPX + 1 ];
    		std::vector<void*> stateVec;
    
    		if ( showConsidered )
    			pather->StatesInPool(&stateVec);
    		printf(" doors %s\n", doorsOpen ? "open" : "closed");
    		printf(" 0         10        20\n");
    		printf(" 012345678901234567890123456789\n");
    		for( int j=0; j<MAPY; ++j ) 
    		{
    			// 按行复制, 并输出
    			memcpy(buf, &gMap[MAPX * j], MAPX + 1);
    			buf[MAPX] = 0;
    #ifdef USE_PATHER
    			unsigned k;
    			// Wildly inefficient demo code.
    			for( k=0; k<path.size(); ++k )
    			{
    				int x, y;
    				NodeToXY( path[k], &x, &y );
    				if ( y == j )
    					buf[x] = '0' + k % 10;
    			}
    			if ( showConsidered )
    			{
    				for( k=0; k<stateVec.size(); ++k ) 
    				{
    					int x, y;
    					NodeToXY( stateVec[k], &x, &y );
    					if ( y == j )
    						buf[x] = 'x';
    				}     
    			}  		
    #endif
    			// Insert the player
    			if ( j == playerY )
    				buf[playerX] = 'i';
    			printf( "%d%s\n", j % 10, buf );
    		}
    	}
    
    #ifdef USE_PATHER
    	void NodeToXY( void* node, int* x, int* y ) 
    	{
    		int index = (int)node;
    		*y = index / MAPX;
    		*x = index - *y * MAPX;
    	}
    
    	void* XYToNode( int x, int y )
    	{
    		return (void*) ( y*MAPX + x );
    	}
    
    	// 最小代价
    	virtual float LeastCostEstimate( void* nodeStart, void* nodeEnd ) 
    	{
    		int xStart, yStart, xEnd, yEnd;
    		NodeToXY( nodeStart, &xStart, &yStart );
    		NodeToXY( nodeEnd, &xEnd, &yEnd );
    
    		/* Compute the minimum path cost using distance measurement. It is possible
    		to compute the exact minimum path using the fact that you can move only 
    		on a straight line or on a diagonal, and this will yield a better result.
    		*/
    		int dx = xStart - xEnd;
    		int dy = yStart - yEnd;
    		return (float) sqrt( (double)(dx*dx) + (double)(dy*dy) );
    	}
    
    	// Return the exact cost from the given state to all its neighboring states. 
    	// This may be called multiple times, or cached by the solver.
    	virtual void AdjacentCost( void* node, std::vector< StateCost > *neighbors ) 
    	{
    		int x, y;
    		// 在X,Y轴上8个方向   E   SE  S   SW     W    NW  N   NE
    		const int dx[8] =     { 1,  1,  0, -1,    -1,  -1,  0,  1 };
    		const int dy[8] =     { 0,  1,  1,  1,     0,  -1, -1, -1 };
    		// X,Y轴上8个方向的代价
    		const float cost[8] = { 1.0f, 1.41f, 1.0f, 1.41f, 1.0f, 1.41f, 1.0f, 1.41f };
    
    		NodeToXY( node, &x, &y );
    
    		// 得到与该点相邻的8个方向的点的坐标;计算是否可通过;将代价push到vector中
    		for( int i=0; i<8; ++i ) 
    		{
    			int nx = x + dx[i];
    			int ny = y + dy[i];
    
    			int pass = Passable( nx, ny );
    			if ( pass > 0 ) 
    			{
    				if ( pass == 1 || doorsOpen ) 
    				{
    					// Normal floor
    					StateCost nodeCost = 
    					{ 
    						// (nx, ny)点的索引号
    						XYToNode( nx, ny ), 
    						// node到该点的代价
    						cost[i] 
    					};
    					neighbors->push_back( nodeCost );
    				}
    				else 
    				{
    					// 若不可pass则代价为FLT_MAX
    					StateCost nodeCost = { XYToNode( nx, ny ), FLT_MAX };
    					neighbors->push_back( nodeCost );
    				}
    			}
    		}
    	}
    
    	virtual void PrintStateInfo( void* node ) 
    	{
    		int x, y;
    		NodeToXY( node, &x, &y );
    		printf( "(%d,%d)", x, y );
    	}
    
    #endif
    };
    
    int main( int /*argc*/, const char** /*argv*/ )
    {
    	{
    		Dungeon test;
    		const int NUM_TEST = 5;
    		int tx[NUM_TEST]	= {	24,	25,	10,	6,	0	};	// x of test
    		int ty[NUM_TEST]	= {	9,	9,	5,	5,	0	};	// y of test
    		int door[NUM_TEST]	= {	0,	0,	0,	1,	0	};	// toggle door? (before move)
    		unsigned check[NUM_TEST] = { 139640, 884, 0, 129313, 2914 };
    		for( int i=0; i<NUM_TEST; ++i )
    		{
    			// (25,9)到(10, 5)时, (10, 5)正好被不通路包围的中心,这个不通路有2扇门,
    			// 此时2扇门没打开,所以(25,9)到(10, 5)不通!
    			// (10,5)到(6,5)之间正好有一扇门,若门关闭则此路不通,门打开则可以通
    			if ( door[i] )
    				test.ToggleDoor();
    			int _result = test.SetPos( tx[i], ty[i] );
    			if ( _result == MicroPather::SOLVED ) 
    			{
    				// Return the "checksum" of the last path returned by Solve(). 
    				// Useful for debugging, and a quick way to see if 2 paths are the same. 
    				unsigned checkNum = test.Checksum();
    
    				if ( checkNum == check[i] )
    					printf( "Test %d to (%d,%d) ok\n", i, tx[i], ty[i] );
    				else
    					printf( "Test %d to (%d,%d) BAD CHECKSUM\n", i, tx[i], ty[i] );
    			}
    			else if (_result == MicroPather::NO_SOLUTION)
    			{
    				printf( "Test %d to (%d,%d) no solution\n", i, tx[i], ty[i] );
    			}
    			else if (_result == MicroPather::START_END_SAME)
    			{
    				printf( "Test %d to (%d,%d) start end same\n", i, tx[i], ty[i] );
    			}
    		}
    	}
    
    	Dungeon dungeon;
    	bool done = false;
    	char buf[ 256 ];
    	while ( !done ) 
    	{
    		dungeon.Print();
    
    		printf( "\n# # to move, q to quit, r to redraw, d to toggle doors, t for touched\n" );
    		std::cin.getline( buf, 256 );
    		if ( *buf )
    		{
    			if ( buf[0] == 'q' ) 
    				done = true;
    			else if ( buf[0] == 'd' ) 
    			{
    				dungeon.ToggleDoor();
    				dungeon.ClearPath();
    			}
    			else if ( buf[0] == 't' ) 
    				dungeon.ToggleTouched();      
    			else if ( buf[0] == 'r' ) 
    				dungeon.ClearPath();
    			else if ( isdigit( buf[0] ) ) 
    			{
    				int x, y;
    				sscanf( buf, "%d %d", &x, &y );	// sleazy, I know
    				dungeon.SetPos( x, y );
    			} 
    		}
    		else			
    			dungeon.ClearPath();
    	}
    	return 0;
    }
    

      


  • 相关阅读:
    截取小数位数(准确四舍五入及直接截取)
    水印
    用心整理的 献丑啦 一些关于http url qs fs ...模块的方法
    html禁止清除input文本输入缓存的两种方法
    flink写入elasticsearch报错!OOM内存溢出!连接异常关闭!
    实现网格建造系统
    AcWing 1064. 小国王
    AcWing 1052. 设计密码
    KMP 模板
    AcWing 1058. 股票买卖 V
  • 原文地址:https://www.cnblogs.com/kex1n/p/2256571.html
Copyright © 2020-2023  润新知