首先来看看完成后的效果:

其中灰色代表路障,绿色是起点和移动路径,红色代表终点

 

// = openArray[i+1].F) {
minNode = openArray[i+1];
}
}
start = minNode;
//将新开始点加入关闭列表
close.push(start);

//将新开始点从开启列表中移除
for(i = 0; i ';
for(var j = -3; j '+j+','+i+'

';
} else {
html += ' '+j+','+i+'

';
}
}
html += '

';
}
t.innerHTML = html;
}

function addStone() {
var tdCollections = $('td');
for(var i = 0; i

为了继续学习,需要明白几个概念。

曼哈顿距离

曼哈顿距离的定义是,两个物体南北方向的距离与东西方向的距离之和。看起来就好像是直角三角形的两条边之和。

用代码表示出来就是:

/**
* 计算两点间的曼哈顿距离
* @param goalNode {Object} 终点坐标
* @param startNode {Object} 起点坐标
* @returns {number} 两点间的曼哈顿距离
*/
function Manhattan(goalNode,startNode) {
return Math.abs(goalNode.x - startNode.x) + Math.abs(goalNode.y - startNode.y);
}

公式F=G+H

G:从起点开始,沿着计算出的可能路径,移动到该路径上的移动消耗。

H:计算出的可能路径到终点的移动预估消耗。

F:G与H之和。

以下图来说明:

起点S周围有四个可选路径a、b、c、d(为简单起见,不考虑对角线也可行走的情况),先来看路径a。

从起点S到达a的移动耗费是1格,故G=1。而从a到达终点G的移动耗费估算是5格,故H=5。F是G与H的值相加,为6。

经过观察,a、b、c三个路径的F值是一样的。而d路径的F值为4。可见F值越小,到达终点的花费越少,因此应该选择d路径作为下一步。

到达d路径后,重复前面的过程,搜索周围的路径,找到F值最小的作为下一步,同时将这个路径作为新的起始点。因为接下来每个路径的F值

都是参照这个新起始点来计算的。

由上图可知,S通往G的最佳路径是d、e、f。

但是还有一种情况,比如下图(灰色表示路障,无法通行):

e和f的F值是一样的,这时候选择哪个呢?其实都可以,一般选择最后一个被计算出来的路径即可。

具体实现

上述方法虽然可行,但是如果不加以限制,会造成一些不良后果。当从起点S到达新路径d时,d仍需要对周围的路径进行探索,起点S也将包含其中,很显然这是不必要而且浪费的。对此,我们需要维护两个列表,一个称为路径开启列表,一个称为路径关闭列表。

var open = [];  //开启列表
var close = []; //关闭列表

open列表的职责是探索周围路径时,将可通行的路径(无路障的路径)加入列表中;

close列表则负责将各个新起点加入其中(相应的这些新起点也要从open列表中移除),下一次执行路径探索时,如果该路径存在这个列表中,则忽略它。

当终点G被包含在close列表中时,搜索结束。

需要注意的是,为每个新起点标记它的父结点,即它是从哪里过来的(比如d路径的父结点就是S,e的父结点是d),这样在到达终点G时,就能够根据它的父结点

一级一级地返回,从而找到这条“通路”的所有坐标,有点像链表这种数据结构。

完整代码:

html部分

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>a-star</title>
<style>
body{
margin: 0;
font-size:12px;
}
table{border-collapse: collapse;
width: 100%; table-layout: fixed}
table th,table td{border:1px solid #000}
#t{
width: 831px;
}
#t td{
width: 30px;
height: 30px;
text-align: center;
}
.start{background-color: #00fc5f}
.block{background-color:#cacaca}
.goal{background-color: #ff2211}
.visited{background-color: #009921;}
</style>
<script src="../jquery-2.1.3.js"></script>
</head>
<body>
<input id="start" type="button" value="开始寻路"/>
<script src="a-star.js"></script>
<script>
$('#start').bind('click',function() {
move(start,end);
});
</script>
</body>
</html>

js部分

 var open = [],  //开启列表
close = [], //关闭列表
start = {}, //起点坐标
end = {}; //终点坐标
var d = document; /**
* 检查待测坐标是否在坐标集合内
* @param toBeCheckNode {Object} 待检查坐标 {x,y}
* @param sourceNode {Array} 坐标集合
* @returns {boolean} 待测坐标是否在坐标集合内
*/
function isNodeExists(toBeCheckNode,sourceNode) {
for(var i in sourceNode) {
if (sourceNode.hasOwnProperty(i)) {
if (parseInt(toBeCheckNode.x) === sourceNode[i].x && parseInt(toBeCheckNode.y) === sourceNode[i].y) return true;
}
}
return false;
} /**
* 返回数组中的某个元素
* @param el 待返回元素
* @param arr 数组
* @returns {Object} 返回该元素
*/
function getElementInArray(el,arr) {
for(var i in arr) {
if(arr.hasOwnProperty(i)) {
if(parseInt(el.x) === arr[i].x && parseInt(el.y) === arr[i].y) {
return arr[i];
}
}
}
return null;
} /**
* 计算两点间的曼哈顿距离
* @param goalNode {Object} 终点坐标
* @param startNode {Object} 起点坐标
* @returns {number} 两点间的曼哈顿距离
*/
function Manhattan(goalNode,startNode) {
return Math.abs(goalNode.x - startNode.x) + Math.abs(goalNode.y - startNode.y);
} /**
* 选择最佳路径作为新起始点
* @param openArray {Array} 开启列表
* @returns {Object} 返回新起始点
*/
function selectNewStart(openArray) {
var minNode = openArray[0],i;
for(i = 0,len = openArray.length - 1; i < len; i++) {
if(minNode.F >= openArray[i+1].F) {
minNode = openArray[i+1];
}
}
start = minNode;
//将新开始点加入关闭列表
close.push(start); //将新开始点从开启列表中移除
for(i = 0; i < openArray.length; i++) {
if(minNode.x === openArray[i].x && minNode.y === openArray[i].y) {
openArray.splice(i,1);
break;
}
}
return start;
} /**
* 遍历周围节点并加入开启列表
* @param node {Object} 一个起始点
*/
function searchAround(node) {
for(var i = -1; i <= 1;i++) {
for(var j = -1; j <= 1; j++) {
var x = node.x + i,
y = node.y + j;
//判断是否为有效的路径点
var nodeExsits = findCurrentPositionInfo(x,y) != null;
if(!nodeExsits) continue;
var t = parseInt(findCurrentPositionInfo(x,y).getAttribute('type')); if(!(x !== node.x && y !== node.y)) {
if(x!== node.x || y !== node.y) {
var curNode = {x:x,y:y,type:t}; //如果该坐标无法通行,则加入关闭列表中
if(curNode.type === 4 ||
curNode.type === 0 ||
curNode.type === 44) {
if(isNodeExists(curNode,close)) continue;
close.push(curNode);
} //如果该坐标已在关闭列表中,略过
if(isNodeExists(curNode,close)) continue; //如果该坐标已在开启列表中,则重新计算它的G值
if(isNodeExists(curNode,open)) {
var new_GValue = Manhattan(curNode,start),
//在开启列表中取出这个元素
inOpenNode = getElementInArray(curNode,open),
//取出旧的G值
old_GValue = inOpenNode.G; //如果G值更小,则意味着当前到达它的路径比上一次的好,更新它的父结点
//以及G值,并重新计算它的F值
if(new_GValue < old_GValue) {
inOpenNode.parent = start;
inOpenNode.G = new_GValue;
inOpenNode.F = inOpenNode.G + inOpenNode.H;
}
continue;
} //设置父节点
curNode.parent = {x:node.x,y:node.y};
curNode.G = Manhattan(curNode,node);
curNode.H = Manhattan(end,curNode);
//估算值
curNode.F = curNode.G + curNode.H;
//将坐标加入开启列表中
open.push(curNode);
}
}
}
}
} function findCurrentPositionInfo(x, y) {
var tds = $('td'),
s = x + "," + y;
for(var i = 0; i < tds.length; i++) {
if(tds[i].innerHTML === s) return tds[i];
}
return null;
} function generateMap() {
var t = d.createElement('table');
t.id = 't';
d.body.appendChild(t); var html = '';
for(var i = -3; i < 10; i++) {
html += '<tr>';
for(var j = -3; j < 15; j++) {
if(i === 0 && j === 0) {
html += '<td class="start" type="1">'+j+','+i+'</td>';
} else {
html += '<td type="1">'+j+','+i+'</td>';
}
}
html += '</tr>';
}
t.innerHTML = html;
} function addStone() {
for(var i = 0; i < 50; i++) {
var r = Math.ceil(Math.random() * 233);
if(r === 57) continue;
var res = tdCollections.eq(r).addClass('block');
res.attr('type',0);
}
} function setGoal() {
var r = Math.ceil(Math.random() * 233);
if(r === 57 || tdCollections.eq(r).hasClass('block')) return setGoal();
var res = tdCollections.eq(r).addClass('goal'); //var res = tdCollections.eq(24).addClass('goal'); return {
x:res.html().split(',')[0],
y:res.html().split(',')[1]
}
} function setColor(start) {
var x = start.x,
y = start.y,
el = findCurrentPositionInfo(x,y); $(el).addClass('visited');
} function move(s,e) {
searchAround(s);
s = selectNewStart(open);
setColor(s);
if(!isNodeExists(e,close)) {
setTimeout(function() {
log();
return move(s,e);
},100);
}
} function init() {
open = [];
close = [];
start = {};
end = {};
} function log() {
console.log('当前起点:',start);
console.log('开启列表:',open);
console.log('关闭列表:',close);
} generateMap();
var tdCollections = $('td');
addStone();
end = setGoal();
start = {x:0,y:0,type:1};
close.push(start); //move(start,end);

//

对A-Star寻路算法的粗略研究的更多相关文章

  1. A*(也叫A star, A星)寻路算法Java版

    寻路算法有非常多种,A*寻路算法被公觉得最好的寻路算法. 首先要理解什么是A*寻路算法,能够參考这三篇文章: http://www.gamedev.net/page/resources/_/techn ...

  2. 算法:Astar寻路算法改进

    早前写了一篇<RCP:gef智能寻路算法(A star)> 出现了一点问题. 在AStar算法中,默认寻路起点和终点都是N x N的方格,但如果用在路由上,就会出现问题. 如果,需要连线的 ...

  3. A*寻路算法的探寻与改良(三)

    A*寻路算法的探寻与改良(三) by:田宇轩                                        第三分:这部分内容基于树.查找算法等对A*算法的执行效率进行了改良,想了解细 ...

  4. 无递归 A星寻路算法

    整理硬盘的时候,发现我早些年写的A星寻路算法.特放上来,待有缘人拿去,无递归噢,性能那是杠杠的. 码上伺候 public class Node { public int X { get; set; } ...

  5. [转] A*寻路算法C++简单实现

    参考文章: http://www.policyalmanac.org/games/aStarTutorial.htm   这是英文原文<A*入门>,最经典的讲解,有demo演示 http: ...

  6. 《C++游戏开发》十六 游戏中的寻路算法(二):迷宫&A*算法基础

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/10289253 作者:七十一雾央 新浪微博:http: ...

  7. 不再依赖A*,利用C++编写全新寻路算法

    一,说在前面的话 大概在半年前,看见一到信息竞赛题:在任意方格阵中设置障碍物,确定起始点后,求这两点之间路径.当时觉得蛮有意思的,但是没有时间去做,今天花了两个小时来实现它.据说有一个更高级的寻路算法 ...

  8. 一种高效的寻路算法 - B*寻路算法

    在此把这个算法称作B* 寻路算法(Branch Star 分支寻路算法,且与A*对应),本算法适用于游戏中怪物的自动寻路,其效率远远超过A*算法,经过测试,效率是普通A*算法的几十上百倍. 通过引入该 ...

  9. 数据结构和算法总结(三):A* 寻路算法

    前言 复习下寻路相关的东西,而且A star寻路在游戏开发中应用挺多的,故记录下. 正文 迪杰斯特拉算法 说起A*得先谈谈Dijkstra算法,它是在BFS基础上的一种带权值的两点最短寻路贪心算法. ...

随机推荐

  1. HDU——1003Max Sum(子序列最大和)

    Max Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Su ...

  2. Hadoop High Availability

    Hadoop High Availability HA(High Available), 高可用,是保证业务连续性的有效解决方案, 通常通过设置备用节点的方式实现; 一般分为执行业务的称为活动节点(A ...

  3. 刷题总结——date(ssoj)

    题目: 题目背景 SOURCE:NOIP2015-SHY-9 题目描述 小Y和小Z好不容易有机会相见啦,可是邪恶的小H却不想让他们相见.现在有一些城市,城市之间有双向路径相连,有路径相连的城市之间可以 ...

  4. ECharts学习总结(二)-----图表组件漏斗图(funnel)

    今天在学习ECharts时,想要在ECharts图表的原生态Demo中抠出漏斗图,却不知如何下手,经过一番研究,特总结如下: 首先我们需要这样做 1.拷贝出两个js文件:esl.js 和echarts ...

  5. COGS728. [网络流24题] 最小路径覆盖问题

    算法实现题8-3 最小路径覆盖问题(习题8-13) ´问题描述: 给定有向图G=(V,E).设P是G的一个简单路(顶点不相交)的集合.如果V中每个顶点恰好在P的一条路上,则称P是G的一个路径覆盖.P中 ...

  6. HDU1724 Ellipse

    Math is important!! Many students failed in 2+2’s mathematical test, so let's AC this problem to mou ...

  7. 学习javascript设计模式之发布-订阅(观察者)模式

    1.发布-订阅模式又叫观察者模式,它定义对象之间一种一对多的依赖关系. 2.如何实现发布-订阅模式 2-1.首先指定好发布者 2-2.给发布者添加一个缓冲列表,用户存放回调函数以便通知订阅者 2-3. ...

  8. LeetCode OJ——Climbing Stairs

    http://oj.leetcode.com/problems/climbing-stairs/ 走台阶的题目,转换出数学模型之后,就是Fibonacci数列.后一个数等于前两个数的和. 递归版本超时 ...

  9. python笔记1:python基础

    1.Python模块的标准文件模板: #!/usr/bin/env python #第1行注释可以让这个 .py 文件直接在Unix/Linux/Mac上运行 # -*- coding: utf-8 ...

  10. 微信小程序 之wx.getLocation()获取地理信息中的小坑

    提到wx.getLocation()这个方法,大家都知道是获取地理信息的 今天用这个方法获取定位经纬度后传给后台取得附近markers标记集合, 在开发工具上都正常有标记出现 ,但是在手机测试时,死活 ...