美文网首页
简单路径查询

简单路径查询

作者: 记忆中风景 | 来源:发表于2019-04-01 18:15 被阅读0次

应用场景

          棋盘类的路径选择。     

作用效果  

        从棋盘上随机或指定位置中选择一个起点,按照规定好的数量和方向(例如:上、下、左、右)去随机的选择相邻的模块,每个模块只会选择一次,如果数量未达到指定要求时返回找到的最大的路线。

实现原理

        主要用栈的方法实现

        选择好第一个节点后,节点进栈,

        按照规定好的方向去搜索下一个节点,

                找到后进栈,删除来时方向,标记为不可选,加入到备选返回队列中

                未找到,栈内元素出栈,检查栈是否为空,

                        不为空,栈顶元素搜索下一节点

                        空,将此次遍历的所有节点置为不可选,从新选择开始节点,如无开始节点结束查找。


 代码实现

var Utils = require('geoUtils');

/**

* createMap函数将返回这样的数据类型的二维数组

* @param {*} item

* @param {*} canSelect

* @param {*} directions //此数据将在选择路径时再赋值    createMap时不进行赋值

*/

function MapInformation(item, canSelect, position, directions) {

    this.item = item;

    this.canSelect = canSelect;

    this.position = position;

    this.directions = directions;

}

var MapUtils = {

    DirectionEnum: {

        UP: { x: -1, y: 0 },

        DOWN: { x: 1, y: 0 },

        LEFT: { x: 0, y: -1 },

        RIGHT: { x: 0, y: 1 },

        UPPER_LEFT: { x: -1, y: -1 },

        UPPER_RIGHT: { x: -1, y: 1 },

        LOWER_LEFT: { x: 1, y: -1 },

        LOWER_RIGHT: { x: 1, y: 1 },

    },

    /**

    * 根据给定的道具集合,创建二维数据集

    * @param {*} items 道具集合(1维)

    * @param {*} numCols 行数

    * @param {*} numVols 列数

    * @returns 返回包装了items的二维数据集,用于搜索功能。

    */

    createMap(items, numCols, numVols) {

        //将要返回的对象

        var ret = {

            //用于探索的二维数组

            array: [],

            //用于记录步数不足maxSteps的item的数组

            notEnough: [],

        };

        //记录数组items当前位置的变量

        var index = 0;

        for (var i = 0; i < numCols; i++) {

            ret.array.push([]);

            for (var j = 0; j < numVols; j++) {

                //获得item  同时index更新

                var item = items[index++];

                var mapObj = new MapInformation(item, true, { x: i, y: j });

                ret.array[i].push(mapObj);

            }

        }

        return ret;

    },

    /**

    *

    * @param {*} map createMap函数返回的对象

    * @param {*} directions 可以选择的方向

    * @param {*} maxSteps 想要走几步

    * @param {*} useStrict 当步数不足maxSteps时是否返回选到的其它的最大步数

    * @param {*} start 起点对象数组[{col:0,vol:0},{col:1,vol:1}]

    * @example

    * var result = MapUtils.serachMap(map,

        *  [MapUtils.DirectionEnum.up, MapUtils.DirectionEnum.down],

        *  2, true);

        */

    searchMap(map, directions, maxSteps, useStrict, start) {

        var mapObjArray = this._localSearchMap(map, directions, maxSteps, useStrict, start);

        var itemArray = this._mapObjArrayToItemArray(mapObjArray);

        return itemArray;

    },

    /**

    *

    * @param {*} map

    * @param {*} PreinstallObjs [{directions:dir,maxSteps:num,useStrict,start:{}},{directions:dir,maxSteps:num,start:{}}]

    */

    searchMapByPreinstall(map, PreinstallObjs) {

        var pObj = Utils.array.random(PreinstallObjs, 1, true)[0];

        return this.searchMap(map, pObj.directions, pObj.maxSteps, pObj.useStrict, pObj.start);

    },

    /**

    *

    * @param {*} map createMap函数返回的对象

    * @param {*} directions 可以选择的方向

    * @param {*} maxSteps 想要走几步

    * @param {*} useStrict 当步数不足maxSteps时是否返回选到的其它的最大步数

    * @example

    * var result = MapUtils.serachMap(map,

    *  [MapUtils.DirectionEnum.up, MapUtils.DirectionEnum.down],

    *  2, true);

    */

    _localSearchMap(map, directions, maxSteps, useStrict, start) {

        var ret = [];

        //记录本次便利未达到指定步数的路线

        var notEnough = [];

        //用于判断item的栈

        var storehouse = new Array(maxSteps);

        //栈指针 指向栈顶元素

        var s = -1;

        //用于记录当前已经选择的mapObj的数组

        var selectMapObj = [];

        //添加可选择的方向

        this._addDirections(map.array, directions);

        var canSelectMapObjs = this._getCanSelectObj(map.array, start);

        do {

            //每次循环前清空数组

            selectMapObj = [];

            //回复数据记录

            this._recoverNotEnough(notEnough);

            this._addDirections(notEnough, directions);

            // notEnough = [];

            //选择第一个节点

            var firstMapObj = this._selectFirstObj(canSelectMapObjs);

            if (firstMapObj == false)

                break;

            //入栈

            storehouse[++s] = firstMapObj;

            //加入选择队列

            selectMapObj.push(firstMapObj);

            var lastMapObj = firstMapObj;

            for (var i = 0; i < maxSteps - 1; i++) {

                lastMapObj = this._selectNextObj(map.array, lastMapObj);

                if (lastMapObj != null) {

                    //入栈

                    storehouse[++s] = lastMapObj;

                    //加入选择队列

                    selectMapObj.push(lastMapObj);

                }

                else {

                    //栈内元素为空本次寻找结束  将当前记录的item数组添加到notEnough中

                    if (--s < 0) {

                        notEnough.push(selectMapObj);

                        break;

                    }

                    //栈不为空 栈顶元素出栈 新的栈顶元素继续寻找

                    lastMapObj = storehouse[s];

                    //本次未选到mapObj  i-- 保证总量达到maxSteps

                    i--;

                }

            }

            if (selectMapObj.length == maxSteps) {

                ret = selectMapObj;

                break;

            }

        } while (canSelectMapObjs.length > 0);

        if (ret.length == 0 && useStrict == true) {

            ret = this._findLongestArrayInNotEnough(notEnough);

        }

        this._recoverNotEnough(notEnough);

        return ret;

    },

    /**

    * 撤销本次查找的不足路线的canSelect

    * @param {*} notEnough

    */

    _recoverNotEnough(notEnough) {

        notEnough.forEach(notEnoughArray => {

            notEnoughArray.forEach(element => {

                element.canSelect = true;

            });

        });

    },

    /**

    * 添加方向

    * @param {*} mapArray

    * @param {*} directions

    */

    _addDirections(mapArray, directions) {

        mapArray.forEach(mapObjArray => {

            mapObjArray.forEach(mapIns => {

                mapIns.directions = directions.concat();

            });

        });

    },

    /**

    * 获得map中可以选择的所有mapObj

    * @param {*} mapArray

    */

    _getCanSelectObj(mapArray, start) {

        //获得可选择的obj

        var ret = [];

        if (start == null) {

            var numCols = mapArray.length;

            var numVols = mapArray[0].length;

            for (var i = 0; i < numCols; i++) {

                for (var j = 0; j < numVols; j++) {

                    var mapObj = mapArray[i][j];

                    if (mapObj.canSelect == true) {

                        ret.push(mapObj);

                    }

                }

            }

        }

        else {

            var mapObj = mapArray[start.col][start.vol];

            if (mapObj.canSelect == true) {

                ret.push(mapObj);

            }

        }

        return ret;

    },

    /**

    * 随机选择一个item为初始节点

    * @param {*} canSelectMapObjs

    */

    _selectFirstObj(canSelectMapObjs) {

        if (canSelectMapObjs.length == 0)

            return false;

        var firstMapObj = Utils.array.random(canSelectMapObjs, 1, true)[0];

        firstMapObj.canSelect = false;

        return firstMapObj;

    },

    /**

    * 根据lastMapObj中记录的directions选择下一个mapObj选择失败返回null

    * @param {*} mapArray

    * @param {*} lastMapObj

    */

    _selectNextObj(mapArray, lastMapObj) {

        for (var i = 0; i < lastMapObj.directions.length;) {

            //随机选择一个方向并且删除使用过的方向

            var d = Utils.array.random(lastMapObj.directions, 1, true)[0];

            var nextX = lastMapObj.position.x + d.x;

            var nextY = lastMapObj.position.y + d.y;

            //判断是否出界

            if (nextX >= 0 && nextY >= 0 && nextX < mapArray.length && nextY < mapArray[0].length) {

                var mapObj = mapArray[nextX][nextY];

                //判断是否可选

                if (mapObj.canSelect == true) {

                    mapObj.canSelect = false;

                    //删除来时的方向

                    this._removeDirection(mapObj.directions, { x: -d.x, y: -d.y });

                    return mapObj;

                }

            }

        }

        return null;

    },

    /**

    * 第一个参数是对象数组objArray

    * 第二个参数是自己定义的对象obj

    * 删除对象数组中属性值等于obj中的属性值的对象

    * 例如    objArray[{a:1,b:1,c:1},{a:1,b:2,c:1}]

    *        obj{b:1}

    * 函数运行完毕后objArray[{a:1,b:2,c:1}]

    * @param {*} directions

    * @param {*} dir

    */

    _removeDirection(directions, dir) {

        for (var i = 0; i < directions.length; i++) {

            var element = directions[i];

            var isRemove = true;

            for (var attr in dir) {

                if (element[attr] != dir[attr]) {

                    isRemove = false;

                    break;

                }

            }

            if (isRemove) {

                directions.splice(i, 1);

                return true;

            }

        }

    },

    /**

    * 返回notEnough数组中的最长的一项

    * @param {*} notEnough

    */

    _findLongestArrayInNotEnough(notEnough) {

        var ret = [];

        for (var i = 0; i < notEnough.length; i++) {

            if (notEnough[i].length > ret.length) {

                ret = notEnough[i];

            }

        }

        Utils.array.remove(notEnough, ret);

        return ret;

    },

    _mapObjArrayToItemArray(mapObjArray) {

        var ret = [];

        mapObjArray.forEach(element => {

            ret.push(element.item);

        });

        return ret;

    },

};

module.exports = MapUtils;

            

    

相关文章

  • 简单路径查询

    应用场景 棋盘类的路径选择。 作用效果 从棋盘上随机或指定位置中选择一个起点,按照规定好的数...

  • mysql-查询优化处理

    下面是mysql查询的路径 下面简单的理解一下mysql服务器的查询过程 查询缓存 在解析一个查询语句之前,如果查...

  • MySQL查询操作

    一,查询的执行路径 二,查询路径中的组件 查询缓存,解析器,预处理器,优化器,查询执行引擎,存储引擎ps:mysq...

  • ReactTraining/history v4 类库源码注解(

    类型一览 路径 Pathname 路径名。 Search 查询。 Hash 哈希。 Path 路径。 路径是由路径...

  • odoo常用查询sql

    菜单查询(显示路径名)

  • SpringMVC接受请求参数

    数据传送到控制器的方法: 查询参数 表单参数 路径变量 获取查询路径中参数@PathVariable 在Reque...

  • SQL常用语法

    创建库: 创建表 修改表 简单查询1 简单查询2(通配符) 简单查询3 连接查询 外部连接查询: 嵌套查询1: 注...

  • 开启MySQL慢查询日志

    查询慢日志开关是否开启 打开慢查询日志开关 再次查询,发现开关打开了 查询mysql安装路径 慢查询日志默认是放在...

  • mongoose学习笔记

    首先是基础crud操作 查询简单查询条件查询 插入 更新 查询 简单查询 mongoose: 条件查询 (>) 大...

  • 快捷键

    Mac:文件根据路径查询:command + shift + g

网友评论

      本文标题:简单路径查询

      本文链接:https://www.haomeiwen.com/subject/ytzvbqtx.html