|
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; |
|
|