From f8f580283bfde48503be11bbd8a6274580be6076 Mon Sep 17 00:00:00 2001 From: Martin Crawford Date: Sat, 13 Nov 2021 13:56:41 -0500 Subject: [PATCH] feat: add blocked paths function --- a-star/a-greedy-star.js | 8 ++++++++ a-star/a-star.js | 8 ++++++++ a-star/defaultSettings.js | 5 +++++ package-lock.json | 1 + test/a-star.js | 43 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+) diff --git a/a-star/a-greedy-star.js b/a-star/a-greedy-star.js index 05e0c35..4f8cb53 100644 --- a/a-star/a-greedy-star.js +++ b/a-star/a-greedy-star.js @@ -40,6 +40,9 @@ function aStarBi(graph, options) { // whether traversal should be considered over oriented graph. var oriented = options.oriented; + var blocked = options.blocked; + if (!blocked) blocked = defaultSettings.blocked; + var heuristic = options.heuristic; if (!heuristic) heuristic = defaultSettings.heuristic; @@ -182,6 +185,11 @@ function aStarBi(graph, options) { return; } + if (blocked(otherSearchState.node, cameFrom.node, link)) { + // Path is blocked. Ignore this route + return; + } + if (canExit(otherSearchState, cameFrom)) { // this node was opened by alternative opener. The sets intersect now, // we found an optimal path, that goes through *this* node. However, there diff --git a/a-star/a-star.js b/a-star/a-star.js index 190a2a4..6a3b4e3 100644 --- a/a-star/a-star.js +++ b/a-star/a-star.js @@ -38,6 +38,9 @@ function aStarPathSearch(graph, options) { // whether traversal should be considered over oriented graph. var oriented = options.oriented; + var blocked = options.blocked; + if (!blocked) blocked = defaultSettings.blocked; + var heuristic = options.heuristic; if (!heuristic) heuristic = defaultSettings.heuristic; @@ -112,6 +115,11 @@ function aStarPathSearch(graph, options) { otherSearchState.open = 1; } + if (blocked(otherNode, cameFrom.node, link)) { + // Path is blocked. Ignore this route + return; + } + var tentativeDistance = cameFrom.distanceToSource + distance(otherNode, cameFrom.node, link); if (tentativeDistance >= otherSearchState.distanceToSource) { // This would only make our path longer. Ignore this route. diff --git a/a-star/defaultSettings.js b/a-star/defaultSettings.js index d8ddb5d..e2c4ba2 100644 --- a/a-star/defaultSettings.js +++ b/a-star/defaultSettings.js @@ -7,6 +7,7 @@ module.exports = { // Path search settings heuristic: blindHeuristic, distance: constantDistance, + blocked: neverBlocked, compareFScore: compareFScore, NO_PATH: NO_PATH, @@ -29,6 +30,10 @@ function constantDistance(/* a, b */) { return 1; } +function neverBlocked(/* a, b, c */) { + return false; +} + function compareFScore(a, b) { var result = a.fScore - b.fScore; // TODO: Can I improve speed with smarter ties-breaking? diff --git a/package-lock.json b/package-lock.json index ee8d9ef..f2cab16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "requires": true, "packages": { "": { + "name": "ngraph.path", "version": "1.3.1", "license": "MIT", "devDependencies": { diff --git a/test/a-star.js b/test/a-star.js index 5793fb8..b61edf4 100644 --- a/test/a-star.js +++ b/test/a-star.js @@ -27,6 +27,49 @@ test('it can find weighted', t => { t.end(); }); +test('A* does not follow blocked paths', t => { + let graph = createGraph(); + + graph.addLink('a', 'b', {blocked: true}); + graph.addLink('a', 'c', {blocked: false}); + graph.addLink('c', 'd', {blocked: false}); + graph.addLink('b', 'd', {blocked: false}); + + + var pathFinder = aStar(graph, { + blocked(a, b, link) { + return link.data.blocked; + } + }); + let path = pathFinder.find('a', 'd'); + + t.equal(path[0].id, 'd', 'd is here'); + t.equal(path[1].id, 'c', 'c is here'); + t.equal(path[2].id, 'a', 'a is here'); + t.end(); +}); + +test('A* greedy does not follow blocked paths', t => { + let graph = createGraph(); + + graph.addLink('a', 'b', {blocked: true}); + graph.addLink('a', 'c', {blocked: false}); + graph.addLink('c', 'd', {blocked: false}); + graph.addLink('b', 'd', {blocked: false}); + + var pathFinder = aGreedy(graph, { + blocked(a, b, link) { + return link.data.blocked; + } + }); + let path = pathFinder.find('a', 'd'); + + t.equal(path[2].id, 'd', 'd is here'); + t.equal(path[1].id, 'c', 'c is here'); + t.equal(path[0].id, 'a', 'a is here'); + t.end(); +}); + test('A* can find directed path', t => { let graph = createGraph();