Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add blocked() to NBA path finder. add documentation of feature #39

Merged
merged 3 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,47 @@ let pathFinder = aStar(graph, {
});
```

## blocked paths

In scenarios where a path might be temporarily blocked between two nodes a `blocked()` function
may be supplied to resolve blocked routes during path finding.

For example, train routes with service disruptions could be modelled as follows:

``` js
let createGraph = require('ngraph.graph');
let graph = createGraph();

// Our graph has cities:
graph.addNode('NYC');
graph.addNode('Philadelphia');
graph.addNode('Baltimore');
graph.addNode('Pittsburgh');
graph.addNode('Washington');

// and railroads:
graph.addLink('NYC', 'Philadelphia', { disruption: false });
graph.addLink('Philadelphia', 'Baltimore', { disruption: true });
graph.addLink('Philadelphia', 'Pittsburgh', { disruption: false });
graph.addLink('Pittsburgh', 'Washington', { disruption: false });
graph.addLink('Baltimore', 'Washington', { disruption: false });
```

While the Philadelphia to Baltimore route is facing a service disruption, the alternative
route to Washington is via Pittsburgh. The following is an example `blocked()` function implementation
that may be supplied to yield this result:

``` js
let path = require('ngraph.path');

let pathFinder = path.aStar(graph, {
blocked(fromNode, toNode, link) {
return link.data.disruption;
},
});
let result = pathFinder.find('NYC', 'Washington');
```

## available finders

The library implements a few A* based path finders:
Expand Down
3 changes: 3 additions & 0 deletions a-star/a-greedy-star.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ module.exports.l1 = heuristics.l1;
* @param {ngraph.graph} graph instance. See https://github.com/anvaka/ngraph.graph
*
* @param {Object} options that configures search
* @param {Function(a, b, link)} options.blocked - a function that returns `true` if the link between
* nodes `a` and `b` are blocked paths. This function is useful for temporarily blocking routes
* while allowing the graph to be reused without rebuilding.
* @param {Function(a, b)} options.heuristic - a function that returns estimated distance between
* nodes `a` and `b`. Defaults function returns 0, which makes this search equivalent to Dijkstra search.
* @param {Function(a, b)} options.distance - a function that returns actual distance between two
Expand Down
3 changes: 3 additions & 0 deletions a-star/a-star.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ module.exports.l1 = heuristics.l1;
*
* @param {ngraph.graph} graph instance. See https://github.com/anvaka/ngraph.graph
* @param {Object} options that configures search
* @param {Function(a, b, link)} options.blocked - a function that returns `true` if the link between
* nodes `a` and `b` are blocked paths. This function is useful for temporarily blocking routes
* while allowing the graph to be reused without rebuilding.
* @param {Function(a, b)} options.heuristic - a function that returns estimated distance between
* nodes `a` and `b`. This function should never overestimate actual distance between two
* nodes (otherwise the found path will not be the shortest). Defaults function returns 0,
Expand Down
10 changes: 10 additions & 0 deletions a-star/nba/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ module.exports.l1 = heuristics.l1;
*
* @param {ngraph.graph} graph instance. See https://github.com/anvaka/ngraph.graph
* @param {Object} options that configures search
* @param {Function(a, b, link)} options.blocked - a function that returns `true` if the link between
* nodes `a` and `b` are blocked paths. This function is useful for temporarily blocking routes
* while allowing the graph to be reused without rebuilding.
* @param {Function(a, b)} options.heuristic - a function that returns estimated distance between
* nodes `a` and `b`. This function should never overestimate actual distance between two
* nodes (otherwise the found path will not be the shortest). Defaults function returns 0,
Expand All @@ -37,6 +40,9 @@ function nba(graph, options) {
var oriented = options.oriented;
var quitFast = options.quitFast;

var blocked = options.blocked;
if (!blocked) blocked = defaultSettings.blocked;

var heuristic = options.heuristic;
if (!heuristic) heuristic = defaultSettings.heuristic;

Expand Down Expand Up @@ -178,6 +184,8 @@ function nba(graph, options) {

if (otherSearchState.closed) return;

if (blocked(cameFrom.node, otherNode, link)) return;

var tentativeDistance = cameFrom.g1 + distance(cameFrom.node, otherNode, link);

if (tentativeDistance < otherSearchState.g1) {
Expand Down Expand Up @@ -206,6 +214,8 @@ function nba(graph, options) {

if (otherSearchState.closed) return;

if (blocked(cameFrom.node, otherNode, link)) return;

var tentativeDistance = cameFrom.g2 + distance(cameFrom.node, otherNode, link);

if (tentativeDistance < otherSearchState.g2) {
Expand Down
23 changes: 23 additions & 0 deletions test/nba.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,29 @@ test('it can find path', t => {
t.end();
});

test('it can find path with blocked links', 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 = nba(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('it can find directed path', t => {
let graph = createGraph();

Expand Down
Loading