// A is node type, B is link type sclass BreadthFirstPathFinderWithLinkTypes implements Steppable { new LinkedList queue; new MultiMap> links; 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 (A b : getChildren.get(a)) add(b, a); 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); } L> examplePath(A start, A dest) { new L path; A node = dest; path.add(pair(node, null)); // dest node has no link type do { Pair link = first(getBackLinks(node)); if (link == null) null; // no path found path.add(link); node = link.a; } while (node != start); ret reversed(path); } }