UNPKG

zoomla

Version:

16年专业研发|中文alexa排名第一的CMS品牌-基于dotNET core、功能强大,集成站群、微信开发、小程序与ERP及OA办公系统,支持国际语言和多民族语言,世界五百强与大型门户专用高端网站内核CMS系统

196 lines (161 loc) 6.82 kB
/* 结点对象 */ var point = function(options) { this.x = options.x; this.y = options.y; this.parent = options.parent; this.G = options.G; this.H = options.H; this.value = options.value; } point.prototype = { /* 获取通过当前所选结点到该结点的G值 */ caculateG: function(point) { point.G = point.G || 0; if (point.x != this.x && point.y != this.y) { return point.G + 14; //在所选点斜方向,耗散值加14 } else { return point.G + 10; //在所选点垂直方向,耗散值加10 } }, /* 根据结束结点计算该点的H值 */ updateH: function(endPoint) { this.H = (Math.abs(endPoint.x - this.x) + Math.abs(endPoint.y - this.y)) * 10; }, /* 根据G和H值计算该点的F值 */ updateF: function() { this.F = this.G + this.H; } } var aStarManager = (function() { var openArr = []; var closeArr = []; var path = []; var isInOpen = function(point) { for (var i = 0, len = openArr.length; i < len; i++) { if (openArr[i] == point) { return true; } } return false; } var isInClose = function(point) { for (var i = 0, len = closeArr.length; i < len; i++) { if (closeArr[i] == point) { return true; } } return false; } /* 获取开始列表中F值最小的结点 */ var getPointWithMinF = function() { var minPoint; for (var i = 0, len = openArr.length; i < len; i++) { if (!minPoint || openArr[i].F < minPoint.F) { minPoint = openArr[i]; } } return minPoint; } var addToClose = function(point) { if (isInOpen(point)) {//如果在开始列表中,则把结点从开始列表中删除,再添加到关闭列表中 deleteFromOpen(point); } closeArr.push(point); } var deleteFromOpen = function(point) { for (var i = 0, len = openArr.length; i < len; i++) { if (openArr[i] == point) { openArr.splice(i, 1); break; } } } /* 保存路径 */ var savePath = function(point) { path.unshift(point); if (point.parent) { arguments.callee(point.parent); } } /* 判断该点是否围墙 */ var isWall = function(point, wallValueArr) { for (var i = 0, len = wallValueArr.length; i < len; i++) { if (wallValueArr[i] == point.value) { return true; } } return false; } /* 开始寻路 */ var handle = function(point) { var beginX = point.x - 1; var beginY = point.y - 1; var endX = point.x + 1; var endY = point.y + 1; var pointsArr = this.pointsArr; addToClose(point); //把传入的当前结点放进关闭列表 for (var i = beginY; i <= endY; i++) {//遍历传入结点的四周的结点 for (var j = beginX; j <= endX; j++) { if (pointsArr[i] && pointsArr[i][j] && !isInClose(pointsArr[i][j])) {//如果该位置结点存在并且不是传入的结点 if (!isWall(pointsArr[i][j], this.wallValueArr)) {//不是障碍物 if (isWall(pointsArr[i][point.x], this.wallValueArr) || isWall(pointsArr[point.y][j], this.wallValueArr)) {//拐角规则,如果检测某点四周的点时,该点和四周上某点之间隔着一个障碍物,则忽略该点,暂不添加到开始列表 continue; } var G = pointsArr[i][j].caculateG(point); if (isInOpen(pointsArr[i][j])) {//如果在开始列表,则根据传入的指定点计算是否改变G值 if (pointsArr[i][j].G > G) {//如果该结点的G值大于由传入结点计算出的G值,则该结点父指针指向传入结点 pointsArr[i][j].G = G; pointsArr[i][j].updateF(); pointsArr[i][j].parent = point; } } else if (!isInClose(pointsArr[i][j])) {//如果不在开始列表也不在关闭列表,则根据传入的指定点计算该点G值,并把该结点父节点指针指向传入结点 pointsArr[i][j].G = G; pointsArr[i][j].updateH(this.endPoint); pointsArr[i][j].updateF(); pointsArr[i][j].parent = point; openArr.push(pointsArr[i][j]); //添加到开始列表 } } else {//如果是障碍物,则添加到关闭列表 addToClose(pointsArr[i][j]); } } } } if (point != this.endPoint) {//如果被选中结点不是终点结点 var nextPoint = getPointWithMinF(); //获取开始列表中F值最小的结点 arguments.callee.call(this, nextPoint); //递归重复上述操作 } else { savePath(point); //如果当前结点是终点结点并且该结点被添加到关闭列表,则保存路径,寻路结束 } } return {//为墙的组 init: function(map, startPointPos, endPointPos, wallValueArr) { this.wallValueArr = wallValueArr; this.pointsArr = []; openArr = []; closeArr = []; path = []; for (var i = 0, len = map.length; i < len; i++) {//列 var row = map[i]; this.pointsArr[i] = []; for (var j = 0, len2 = row.length; j < len2; j++) {//行 this.pointsArr[i][j] = new point({ x: j, y: i, value: row[j] }); //初始化point对象数组 if (i == startPointPos[1] && j == startPointPos[0]) { this.startPoint = this.pointsArr[i][j]; } else if (i == endPointPos[1] && j == endPointPos[0]) { this.endPoint = this.pointsArr[i][j]; } } } }, getPath: function() { handle.call(this, this.startPoint); return path; } } })();