A*搜索算法随想

本文介绍了一种基于ActionScript的A*寻路算法实现,包括Node和FindPath两个核心类的设计。通过设置不同的g(n)和h(n)函数,可以实现从深度优先搜索到Dijkstra算法的变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

随感通过这篇文章http://blog.youkuaiyun.com/v_july_v/article/details/6093380

顺手用as亲自实现一个A*寻路算法,g(n),h(n) 函数暂且随意用距离表示,可优化

Node.as

package AStar
{
	/**
	 *节点 
	 * @author lake
	 * 地图为 平面正方形
	 */	
	public class Node
	{
		/**
		 * 行索引
		 */		
		public var mRowIndex		:int;
		/**
		 *列索引 
		 */		
		public var mColIndex		:int;
		/**
		 *是否阻拦 
		 */		
		public var isBlock			:Boolean = false;
		
		public var g :Number = 0;
		
		public var h :Number = 0;
		
		public function Node()
		{
		}
		
		public function get f():Number
		{
			return g + h;
		}
		
		public function get x():Number
		{
			return mColIndex * 20;
		}
		
		public function get y():Number
		{
			return mRowIndex * 20;
		}
	}
}

FindPath.as

package AStar
{
	import flash.geom.Point;
	/**
	 *寻路 
	 * @author lake
	 * 
	 */
	public class FindPath
	{
		/**
		 * 开放列表节点
		 */		
		public var openList 	:Array = [];
		/**
		 * 关闭列表节点
		 */		
		public var closeList	:Array = [];
		/**
		 *所有节点列表 
		 */		
		public var allNodeList :Array = [];
		/**
		 *表示从起始搜索点到当前点的代价(通常用某结点在搜索树中的深度来表示)
		 */		
		public var gValue		:Number;
		/**
		 *表示启发式搜索中最为重要的一部分,即当前结点到目标结点的估值 
		 */		
		public var hValue		:Number;
		/**
		 * 地图宽度
		 */		
		public var mapWidth		:int;
		/**
		 * 地图高度
		 */		
		public var mapHeight	:int;
		/**
		 * 格子宽度
		 */		
		public var gridWidth	:int;
		/**
		 * 格子高度
		 */		
		public var gridHeight	:int;
		/**
		 *行数 
		 */		
		public var mapRow		:int;
		/**
		 * 列数
		 */		
		public var mapCol		:int;
		/**
		 * 起始
		 */		
		public var startNode :Node;
		/**
		 * 终点
		 */		
		public var endNode	  :Node; 
		
		public function FindPath()
		{
			
		}
		/**
		 *初始化 
		 * @param mapWidth
		 * @param mapHeight
		 * @param gridWidth
		 * @param gridHeight
		 * 
		 */		
		public function initPaths(mapWidth:int,mapHeight:int,gridWidth:int,gridHeight:int):void
		{
			allNodeList = [];
			this.mapWidth = mapWidth;
			this.mapHeight = mapHeight;
			this.gridWidth = gridWidth;
			this.gridHeight = gridHeight;
			var i:int,j:int;
			mapRow = mapHeight / gridHeight;
			mapCol = mapWidth / gridWidth;
			var node :Node;
			for(i = 0;i<=mapRow;i++)
			{
				allNodeList.push([]);
				for(j = 0;j<=mapCol;j++)
				{
					node = new Node();
					node.mRowIndex = i;
					node.mColIndex = j;
					allNodeList[i][j] = node;
				}
			}
		}
		/**
		 * 寻路
		 * @param startPoint
		 * @param endPoint
		 * @return 
		 * 
		 */		
		public function findPathByPoint(startPoint:Point,endPoint:Point):Array
		{
			var fres :Array = [];
			var startNode :Node = allNodeList[int(startPoint.y / gridHeight)][int(startPoint.x / gridWidth)];
			var endNode	  :Node = allNodeList[int(endPoint.y / gridHeight)][int(endPoint.x / gridWidth)];
			this.startNode = startNode;
			this.endNode = endNode;
			var isEnd:Boolean=false;
			
			var thisNode:Node = startNode;
			while (!isEnd)
			{
				var checkList:Array=getNearNodeList(thisNode);
				//开始检测当前节点周围
				var len:int=checkList.length;
				for (var i:int=0; i < len; i++)
				{
					//周围的每一个节点
					var nearNode:Node=checkList[i];
					//判断是否是目的地
					if (nearNode == endNode)
					{
						isEnd=true;
						closeList.push(thisNode);
						closeList.push(endNode);
						break;
					}
					//是否可通行
					if (nearNode.isBlock == false)
					{
						countNode(nearNode);
					}
				}
				if (!isEnd)
				{
					//如果未找到目的地
					if (openList.length > 0)
					{
						//开发列表不为空,找出F值最小的做为下一个循环的当前节点
						closeList.push(thisNode);
						openList.sortOn(["f"],[Array.NUMERIC]);
						thisNode = openList.splice(0,1)[0];
					}
					else
					{
						//开发列表为空,寻路失败
						return [];
					}
				}
			}
			fres = closeList;
			return fres;
		}
		/**
		 *寻找周围节点 (八方向) 
		 * @param node
		 * @return 
		 * 
		 */		
		public function getNearNodeList(node :Node):Array
		{
			var nodeList :Array = [];
			var leftIndex :int = (node.mColIndex - 1)<0?0:(node.mColIndex - 1);
			var topIndex :int = (node.mRowIndex - 1)<0?0:(node.mRowIndex - 1);
			var rightIndex :int = (node.mColIndex + 1)>mapCol?mapCol:(node.mColIndex + 1);
			var downIndex :int = (node.mRowIndex + 1)>mapRow?mapRow:(node.mRowIndex + 1);
			var targetNode :Node;
			for(;topIndex<=downIndex;topIndex++)
			{
				for(var tLeftIndex :int = leftIndex;tLeftIndex <= rightIndex;tLeftIndex++)
				{
					targetNode = allNodeList[topIndex][tLeftIndex];
					if(targetNode != node)
					{
						nodeList.push(targetNode);
					}
				}
			}
			return nodeList;
		}
		/**
		 * 计算节点权值
		 * @param node
		 * 
		 */		
		private function countNode(node :Node):void
		{
			node.g = g(node);
			node.h = h(node);
			if(closeList.indexOf(node) == -1)
			{
				openList.push(node);
			}
		}
		
		private function g(node :Node):Number
		{
			var value :Number = 0;
			//value = -Math.sqrt(Math.pow(node.mRowIndex - startNode.mRowIndex,2)+ Math.pow(node.mColIndex - startNode.mColIndex,2));
			return value;
		}
		
		private function h(node :Node):Number
		{
			var value :Number = 0;
			value = Math.sqrt(Math.pow(node.mRowIndex - endNode.mRowIndex,2)+ Math.pow(node.mColIndex - endNode.mColIndex,2));
			return value;
		}
	}
}

测试代码:(Flash builder 4.5 开发坏境)

FindPathTest.as

package
{
	import AStar.FindPath;
	import AStar.Node;
	
	import flash.display.Sprite;
	import flash.geom.Point;
	
	[SWF(width="800",height="600",backgroundColor="#cccccc",frameRate="25")]
	public class FindPathTest extends Sprite
	{
		public function FindPathTest()
		{
			var startPoint :Point = new Point(80,20);
			var endPoint  :Point = new Point(500,300);
			var fp :FindPath = new FindPath();
			fp.initPaths(800,600,20,20);
			drawGrid(800,600,20,20);
			this.graphics.beginFill(0xff0000);
			this.graphics.drawCircle(startPoint.x + 10,startPoint.y + 10,8);
			this.graphics.drawCircle(endPoint.x + 10,endPoint.y + 10,8);
			this.graphics.endFill();
			var paths :Array = fp.findPathByPoint(startPoint,endPoint);
			this.graphics.beginFill(0x00cc00);
			for each(var node :Node in paths)
			{
				this.graphics.drawCircle(node.x + 10,node.y + 10,3);
			}
			this.graphics.endFill();
		}
		
		private function drawGrid(mw:int,mh:int,gw:int,gh:int):void
		{
			var i:int,j:int;
			var mapRow :int = mh / gh;
			var mapCol :int = mw / gw;
			this.graphics.lineStyle(1,0x0000cc);
			for(i = 0;i<mapRow;i++)
			{
				this.graphics.moveTo(0,i * gh);
				this.graphics.lineTo(mw,i * gh);
			}
			for(j = 0;j<mapCol;j++)
			{
				this.graphics.moveTo(j * gw,0);
				this.graphics.lineTo(j * gw,mh);
			}
		}
	}
}

A*算法与广度、深度优先和Dijkstra 算法的联系就在于:当g(n)=0时,该算法类似于DFS,当h(n)=0时,该算法类似于BFS。且同时,如果h(n)为0,只需求出g(n),即求出起点到任意顶点n的最短路径,则转化为单源最短路径问题,即Dijkstra算法。这一点,可以通过上面的A*搜索树的具体过程中将h(n)设为0或将g(n)设为0而得到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值