// 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); } }