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 = ({
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 );
let steps = 0;
while( openSet.size() > 0 ){
popFromOpenSet();
steps++;
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
};
}
closedSetIds[ cMinId ] = true;
let vwEdges = cMin._private.edges;
for( let i = 0; i < vwEdges.length; i++ ){
let e = vwEdges[ i ];
if( !this.hasElementWithId( e.id() ) ){ continue; }
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();
if( !this.hasElementWithId( wid ) ){ continue; }
if( closedSetIds[ wid ] ){
continue;
}
let tempScore = gScore[ cMinId ] + weight( e );
if( !isInOpenSet(wid) ){
gScore[ wid ] = tempScore;
fScore[ wid ] = tempScore + heuristic( w );
addToOpenSet( w, wid );
cameFrom[ wid ] = cMin;
cameFromEdge[ wid ] = e;
continue;
}
if( tempScore < gScore[ wid ] ){
gScore[ wid ] = tempScore;
fScore[ wid ] = tempScore + heuristic( w );
cameFrom[ wid ] = cMin;
cameFromEdge[ wid ] = e;
}
}
}
return {
found: false,
distance: undefined,
path: undefined,
steps: steps
};
}
});
export default elesfn;