From 09e7ad051c329ad7bc11599702ba58f7f01132b2 Mon Sep 17 00:00:00 2001 From: CheezBarger Date: Fri, 21 Dec 2018 12:34:38 +0100 Subject: [PATCH] 21.12.2018 General Work --- DefaultConditions/README.md | 2 +- Pathfinders/ASTAR.js | 1 + Pathfinders/DLITE/DLITE.js | 1 + Pathfinders/DLITE/DLITEReturnState.js | 40 +++++++++++++-------------- Pathfinders/DLITE/UDLITE.js | 1 + Pathfinders/README.md | 34 ++++++++++++++++++++--- README.md | 21 ++++++++++++-- index.js | 12 +++++--- 8 files changed, 80 insertions(+), 32 deletions(-) diff --git a/DefaultConditions/README.md b/DefaultConditions/README.md index 787cac4..8df197e 100644 --- a/DefaultConditions/README.md +++ b/DefaultConditions/README.md @@ -1 +1 @@ -#Default Condition \ No newline at end of file +# Default Condition \ No newline at end of file diff --git a/Pathfinders/ASTAR.js b/Pathfinders/ASTAR.js index 8e42e62..8bef7a0 100644 --- a/Pathfinders/ASTAR.js +++ b/Pathfinders/ASTAR.js @@ -1,3 +1,4 @@ +'use strict'; const Heap = require('fastpriorityqueue'); function State(p) diff --git a/Pathfinders/DLITE/DLITE.js b/Pathfinders/DLITE/DLITE.js index 206f34e..69cbac8 100644 --- a/Pathfinders/DLITE/DLITE.js +++ b/Pathfinders/DLITE/DLITE.js @@ -1,3 +1,4 @@ +'use strict'; const Path = require('path'); const DLITEReturnState = require(Path.resolve(__dirname, 'DLITEReturnState.js')); diff --git a/Pathfinders/DLITE/DLITEReturnState.js b/Pathfinders/DLITE/DLITEReturnState.js index 4eec6e9..e559c70 100644 --- a/Pathfinders/DLITE/DLITEReturnState.js +++ b/Pathfinders/DLITE/DLITEReturnState.js @@ -1,3 +1,4 @@ +'use strict'; const Heap = require('fastpriorityqueue'); module.exports = function DLITEReturnState(bot, sp, ep, UpdateVertex, ComputeShortestPath) @@ -57,7 +58,7 @@ module.exports = function DLITEReturnState(bot, sp, ep, UpdateVertex, ComputeSho Object.defineProperty(this, 'U', {value: U, enumerable: false}); Object.defineProperty(this, 'S', {value: S, enumerable: false}); - State = function(p) + const State = function(p) { if (S.check(p)) return S[p.x >>> 0][p.y >>> 0][p.z >>> 0]; @@ -75,8 +76,7 @@ module.exports = function DLITEReturnState(bot, sp, ep, UpdateVertex, ComputeSho Object.defineProperty(this, 'State', {value: State, enumerable: false}); - // Algorithm - Initialize.call(this, bot, sp, ep, UpdateVertex, ComputeShortestPath); + // Path functions const R = this; this.path = {}; @@ -89,6 +89,7 @@ module.exports = function DLITEReturnState(bot, sp, ep, UpdateVertex, ComputeSho let minState; let minCost = Number.POSITIVE_INFINITY; + // Get successors according to stored state. const successors = bot.pathfinder.getSuccessors(R.S.start.p); for (let n = 0, len = successors.length; n < len; n++) { @@ -122,6 +123,9 @@ module.exports = function DLITEReturnState(bot, sp, ep, UpdateVertex, ComputeSho } else return undefined; }; + + // Algorithm + Initialize.call(this, bot, sp, ep, UpdateVertex, ComputeShortestPath); }; function Initialize(bot, sp, ep, UpdateVertex, ComputeShortestPath) @@ -143,23 +147,19 @@ function Initialize(bot, sp, ep, UpdateVertex, ComputeShortestPath) { // ComputeShortestPath has to be run initially const MainPromise = this.ComputeShortestPath(); - MainPromise - .then(function(ReturnState) + MainPromise.then(function(ReturnState) + { + R.ENUMStatus = ReturnState.ENUMStatus; + R.ClosestPoint = ReturnState.State.p; + if (ReturnState.ENUMStatus === bot.pathfinder.ENUMStatus.Incomplete) { - R.ENUMStatus = ReturnState.ENUMStatus; - // Should the path be incomplete, sets the start point to the closest point to the intended - // start point, to which a replan can be attempted using a different algorithm. - if (ReturnState.ENUMStatus === bot.pathfinder.ENUMStatus.Incomplete) - { - console.warn( - 'WARNING Pathfinder: Did not find path in allowed MAX_EXPANSIONS, returned closest valid start point', - 'Use another algorithm to reach the valid start point before attempting D*Lite' - ); - R.S.start = ReturnState.State; - } - - Callback(R); - }); + console.warn( + 'WARNING Pathfinder: Did not find path in allowed MAX_EXPANSIONS, returned closest valid start point', + 'Use another algorithm to reach the valid start point before attempting D*Lite' + ); + } + }); + MainPromise.then(function() {Callback(R);}); }; }; @@ -172,4 +172,4 @@ function floatEqual(f1, f2) { if (f1 === Number.POSITIVE_INFINITY && f2 === Number.POSITIVE_INFINITY) return true; return Math.abs(f1 - f2) < Number.EPSILON; -} +} \ No newline at end of file diff --git a/Pathfinders/DLITE/UDLITE.js b/Pathfinders/DLITE/UDLITE.js index e350af5..0f4af03 100644 --- a/Pathfinders/DLITE/UDLITE.js +++ b/Pathfinders/DLITE/UDLITE.js @@ -1,3 +1,4 @@ +'use strict'; const Path = require('path'); const DLITEReturnState = require(Path.resolve(__dirname, 'DLITEReturnState.js')); diff --git a/Pathfinders/README.md b/Pathfinders/README.md index d22cf66..2465cf6 100644 --- a/Pathfinders/README.md +++ b/Pathfinders/README.md @@ -1,4 +1,19 @@ # Algorithm Documentation + +## Table of Contents +- [Algorithm Documentation](#algorithm-documentation) + - [Table of Contents](#table-of-contents) + - [A* Pathfinding](#a-pathfinding) + - [ASTARReturnState](#astarreturnstate) + - [ASTARReturnState.on( Callback)](#astarreturnstateon-callback) + - [D* Lite Pathfinding](#d-lite-pathfinding) + - [DLITEReturnState](#dlitereturnstate) + - [ASTARReturnState.on( Callback)](#astarreturnstateon-callback-1) + - [ASTARReturnState.path.pop()](#astarreturnstatepathpop) + - [ASTARReturnState.path.peek()](#astarreturnstatepathpeek) + - [ASTARReturnState.path.replan([startPoint, endPoint]) [Not implemented]](#astarreturnstatepathreplanstartpoint-endpoint-not-implemented) + - [JPS A* Pathfinding [Not implemented]](#jps-a-pathfinding-not-implemented) + ## A* Pathfinding Standard A* algorithim as per Peter E. Hart, Nils J. Nilsson, Bertram Raphael, 1968. Should you want to learn how the algorithm works: https://en.wikipedia.org/wiki/A*_search_algorithm @@ -13,6 +28,9 @@ Provides a function to be executed when the path search has completed * `Callback` - Function to be executed once the path search has completed, `ASTARReturnState` passed as argument. +### ASTARReturnState.ENUMState +Set when algorithim completes path search, equal to one of `bot.pathfinder.ENUMStatus` depending on whether the path search was successfull or not. + ## D* Lite Pathfinding D* Lite as per S. Koenig, 2002. @@ -30,22 +48,30 @@ Object with the following properties: * `ENUMStatus` - Provides the respective `bot.pathfinder.ENUMStatus` based on the outcome of the path search. * `path` - See `DLITEReturnState.path` -#### ASTARReturnState.on( Callback) +#### DLITEReturnState.on( Callback) Provides a function to be executed when the path search has completed * `Callback` - Function to be executed once the path search has completed, `DLITEReturnState` passed as argument. -#### ASTARReturnState.path.pop() +### DLITEReturnState.ENUMState +Set when algorithim completes path search, equal to one of `bot.pathfinder.ENUMStatus` depending on whether the path search was successfull or not. + +### DLITEReturnState.ClosestPoint +Set when algorithim completes path search, equal to the closest point from which a path from the end point to the start could be found. + +If `DLITEReturnState.ENUMState` is incomplete, it is recommended to use a different method to navigate the bot to the `DLITEReturnState.ClosestPoint` before attempting pathfinding using D* Lite again. + +#### DLITEReturnState.path.pop() As the path is determined while the bot moves across it, pop must be used to determine the next location to move to. Returns position vector. -#### ASTARReturnState.path.peek() +#### DLITEReturnState.path.peek() Determines which path element will be popped next. Returns position vector. -#### ASTARReturnState.path.replan([startPoint, endPoint]) /[Not implemented] +#### DLITEReturnState.path.replan([startPoint, endPoint]) \[Not implemented] ## JPS A* Pathfinding \[Not implemented] diff --git a/README.md b/README.md index dd92775..c30104f 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,30 @@ # Mineflayer-Pathfinder Fast, promise based, 3D pathfinding library using A* and D*Lite algorithms, for Mineflayer found under: [https://github.com/superjoe30/mineflayer/](https://github.com/superjoe30/mineflayer/) -## Features +## Table of Contents +- [Mineflayer-Pathfinder](#mineflayer-pathfinder) + - [Features](#features) + - [Table of Contents](#table-of-contents) + - [Basic Usage](#basic-usage) + - [Advanced Usage](#advanced-usage) + - [Documentation](#documentation) + - [bot.pathfinder.to( startPoint, endPoint [, ENUMPathfinder])](#botpathfinderto-startpoint-endpoint--enumpathfinder) + - [bot.pathfinder.getSuccessors( position)](#botpathfindergetsuccessors-position) + - [bot.pathfinder.getPredecessors( position)](#botpathfindergetpredecessors-position) + - [bot.pathfinder.getBlock( position)](#botpathfindergetblock-position) + - [bot.pathfinder.MAX_EXPANSIONS](#botpathfindermax_expansions) + - [bot.pathfinder.HEURISTIC( startPoint, EndPoint)](#botpathfinderheuristic-startpoint-endpoint) + - [bot.pathfinder.COST](#botpathfindercost) + - [bot.pathfinder.ENUMPathfinder](#botpathfinderenumpathfinder) + - [bot.pathfinder.ENUMStatus](#botpathfinderenumstatus) + - [Algorithm Documentation](#algorithm-documentation) +## Features * Provides high level API for determining paths between two points * Multiple algorithms for pathfinding, A* and D*Lite * Exposed internal functions to allow easier user replacement * Based solely on a promise based API -## Table of Contents - ## Basic Usage To get started just paste this code into your bot: ```js diff --git a/index.js b/index.js index 8836d07..7a29084 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,5 @@ -EventEmitter = require('events').EventEmitter; +'use strict'; +const EventEmitter = require('events').EventEmitter; const Vec3 = require('vec3'); const Path = require('path'); @@ -15,10 +16,13 @@ module.exports = function(bot) bot.pathfinder = new EventEmitter(); bot.pathfinder.ENUMPathfinder = {ASTAR: 0, DLITE: 1, UDLITE: 2}; - bot.pathfinder.ENUMStatus = {Complete: 0, Incomplete: 1}; + bot.pathfinder.ENUMStatus = {Complete: 0, Incomplete: 1, Replan: 2}; - bot.pathfinder.getSuccessors = gMS.bind(undefined, require(Path.resolve(__dirname, 'DefaultConditions/successorConditions.json'))); - bot.pathfinder.getPredecessors = gMS.bind(undefined, require(Path.resolve(__dirname, 'DefaultConditions/predecessorConditions.json'))); + Object.defineProperty(bot.pathfinder, 'defaultSuccessors', {value: require(Path.resolve(__dirname, 'DefaultConditions/successorConditions.json')), enumerable: false}); + Object.defineProperty(bot.pathfinder, 'defaultPredecessors', {value: require(Path.resolve(__dirname, 'DefaultConditions/predecessorConditions.json')), enumerable: false}); + + bot.pathfinder.getSuccessors = gMS.bind(undefined, bot.pathfinder.defaultSuccessors); + bot.pathfinder.getPredecessors = gMS.bind(undefined, bot.pathfinder.defaultPredecessors); // Native getBlock implementation too slow for this case let blocks;