// A is node type, B is link type
sclass BreadthFirstPathFinder_withLinkType implements Steppable {
new LinkedList queue;
new MultiMap> links; // backwards (child -> parent)
IF1>> getChildren; // must set
*() {}
*(IF1>> *getChildren) {}
*(IF1>> *getChildren, A startNode) { add(startNode); }
void add(A a) {
add(a, null, null);
}
void add(A a, A prev, B linkType) {
if (!links.containsKey(a)) {
links.put(a, prev == null ?: pair(prev, linkType));
queue.add(a);
}
}
public bool step() {
ping();
if (empty(queue)) false;
A a = popFirst(queue);
fOr (Pair link : getChildren.get(a))
add(link.a, a, link.b);
true;
}
bool nodeReached(A a) {
ret links.containsKey(a);
}
Cl getBackLinks(A a) {
ret pairsA(links.get(a));
}
Cl> getBackLinksWithTypes(A a) {
ret links.get(a);
}
LPair examplePathWithTypes(A start, A dest) {
new LPair path;
A node = dest;
path.add(pair(node, null)); // dest node has no link type
while ping (node != start) {
Pair link = first(getBackLinksWithTypes(node));
ifdef BreadthFirstPathFinder_debug
printVars_str examplePathWithTypes(+node, +link);
endifdef
if (link == null) null; // no path found
path.add(link);
node = link.a;
}
ret reversed(path);
}
}