File size: 3,942 Bytes
bc20498 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
import Heap from '../../heap';
import Set from '../../set';
import { defaults } from '../../util';
const aStarDefaults = defaults({
root: null,
goal: null,
weight: edge => 1,
heuristic: edge => 0,
directed: false
});
let elesfn = ({
// Implemented from pseudocode from wikipedia
aStar: function( options ){
let cy = this.cy();
let { root, goal, heuristic, directed, weight } = aStarDefaults(options);
root = cy.collection(root)[0];
goal = cy.collection(goal)[0];
let sid = root.id();
let tid = goal.id();
let gScore = {};
let fScore = {};
let closedSetIds = {};
let openSet = new Heap( (a, b) => fScore[a.id()] - fScore[b.id()] );
let openSetIds = new Set();
let cameFrom = {};
let cameFromEdge = {};
let addToOpenSet = (ele, id) => {
openSet.push(ele);
openSetIds.add(id);
};
let cMin, cMinId;
let popFromOpenSet = () => {
cMin = openSet.pop();
cMinId = cMin.id();
openSetIds.delete(cMinId);
};
let isInOpenSet = id => openSetIds.has(id);
addToOpenSet(root, sid);
gScore[ sid ] = 0;
fScore[ sid ] = heuristic( root );
// Counter
let steps = 0;
// Main loop
while( openSet.size() > 0 ){
popFromOpenSet();
steps++;
// If we've found our goal, then we are done
if( cMinId === tid ){
let path = [];
let pathNode = goal;
let pathNodeId = tid;
let pathEdge = cameFromEdge[pathNodeId];
for( ;; ){
path.unshift(pathNode);
if( pathEdge != null ){
path.unshift(pathEdge);
}
pathNode = cameFrom[pathNodeId];
if( pathNode == null ){ break; }
pathNodeId = pathNode.id();
pathEdge = cameFromEdge[pathNodeId];
}
return {
found: true,
distance: gScore[ cMinId ],
path: this.spawn( path ),
steps
};
}
// Add cMin to processed nodes
closedSetIds[ cMinId ] = true;
// Update scores for neighbors of cMin
// Take into account if graph is directed or not
let vwEdges = cMin._private.edges;
for( let i = 0; i < vwEdges.length; i++ ){
let e = vwEdges[ i ];
// edge must be in set of calling eles
if( !this.hasElementWithId( e.id() ) ){ continue; }
// cMin must be the source of edge if directed
if( directed && e.data('source') !== cMinId ){ continue; }
let wSrc = e.source();
let wTgt = e.target();
let w = wSrc.id() !== cMinId ? wSrc : wTgt;
let wid = w.id();
// node must be in set of calling eles
if( !this.hasElementWithId( wid ) ){ continue; }
// if node is in closedSet, ignore it
if( closedSetIds[ wid ] ){
continue;
}
// New tentative score for node w
let tempScore = gScore[ cMinId ] + weight( e );
// Update gScore for node w if:
// w not present in openSet
// OR
// tentative gScore is less than previous value
// w not in openSet
if( !isInOpenSet(wid) ){
gScore[ wid ] = tempScore;
fScore[ wid ] = tempScore + heuristic( w );
addToOpenSet( w, wid );
cameFrom[ wid ] = cMin;
cameFromEdge[ wid ] = e;
continue;
}
// w already in openSet, but with greater gScore
if( tempScore < gScore[ wid ] ){
gScore[ wid ] = tempScore;
fScore[ wid ] = tempScore + heuristic( w );
cameFrom[ wid ] = cMin;
cameFromEdge[ wid ] = e;
}
} // End of neighbors update
} // End of main loop
// If we've reached here, then we've not reached our goal
return {
found: false,
distance: undefined,
path: undefined,
steps: steps
};
}
}); // elesfn
export default elesfn;
|