Last active
December 17, 2015 02:19
-
-
Save TomTasche/5534850 to your computer and use it in GitHub Desktop.
EinStern is a mixture of routing algorithms like depth-first and dijkstra. it is able to find a path between "things" - points without any distance or similar between each other. Blog post about it: http://blog.tomtasche.at/2013/05/routing-things-and-stuff.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.HashMap; | |
import java.util.LinkedList; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* some kind of depth-first and dijkstra mixture. this little code snippet is | |
* able to find a path between "things" - points without any distance or similar | |
* between each other | |
* | |
* @author Thomas Taschauer | |
* | |
*/ | |
public abstract class EinStern { | |
/** | |
* @return all the Things which should be considered for routing | |
*/ | |
public abstract Thing[] getAllTheThings(); | |
/** | |
* @return the Thing we want to start routing from | |
*/ | |
public abstract Thing getStart(); | |
/** | |
* @return the Thing we want to route to | |
*/ | |
public abstract Thing getDestination(); | |
/* | |
* maps the names of a thing to its connected Things. | |
*/ | |
private Map<String, List<Thing>> graph; | |
/* | |
* prevents endless-loops by remembering all previously visited / inspected | |
* / "closed" Things. we won't inspect closed Things a second time. | |
*/ | |
private List<String> closedThings; | |
/* | |
* holds the shortest path currently known to the algorithm. whenever we | |
* find a shorter one we replace this with the shorter one. | |
*/ | |
private List<Thing> currentShortestKnownPath; | |
public EinStern() { | |
buildGraph(); | |
Thing fromThing = getStart(); | |
Thing toThing = getDestination(); | |
closedThings = new LinkedList<String>(); | |
currentShortestKnownPath = new LinkedList<Thing>(); | |
// remembers the path we were "walking" so far. if we get stuck, we go | |
// back step by step until there is a new possible path to walk on | |
List<Thing> currentPath = new LinkedList<Thing>(); | |
discover(currentPath, fromThing.getName(), toThing.getName()); | |
// this is the path you're looking for. congratulations! | |
List<Thing> shortestPath = currentShortestKnownPath; | |
System.out.println("shortest path takes " + shortestPath.size() | |
+ " hops"); | |
} | |
private void buildGraph() { | |
Thing[] things = getAllTheThings(); | |
graph = new HashMap<String, List<Thing>>(); | |
for (Thing thing : things) { | |
String name = thing.getName(); | |
List<Thing> connectedThings = graph.get(name); | |
if (connectedThings == null) { | |
connectedThings = new LinkedList<Thing>(); | |
graph.put(name, connectedThings); | |
} | |
connectedThings.add(thing); | |
} | |
// now you can get all the Things connected to a Thing only by its name | |
} | |
private void discover(List<Thing> currentPath, String fromThing, | |
String toThing) { | |
// we're now inspecting this Thing, so we close it because we don't want | |
// to inspect it another time later on | |
closedThings.add(fromThing); | |
List<Thing> things = graph.get(fromThing); | |
for (Thing thing : things) { | |
String toDevice = thing.getName(); | |
if (toThing.equals(toDevice)) { | |
currentPath.add(thing); | |
System.out.println("found path with " + currentPath.size() | |
+ " hops"); | |
if (currentShortestKnownPath.isEmpty() | |
|| currentPath.size() < currentShortestKnownPath.size()) { | |
currentShortestKnownPath.clear(); | |
currentShortestKnownPath.addAll(currentPath); | |
} | |
} else { | |
String newFrom = thing.getName(); | |
if (!closedThings.contains(newFrom)) { | |
currentPath.add(thing); | |
discover(currentPath, newFrom, toThing); | |
currentPath.remove(thing); | |
} | |
} | |
} | |
} | |
/** | |
* this is by far not the best object for representing a point in a graph, | |
* but it's approximately what i had to deal with when creating this. using | |
* this class there can be multiple instances of the class representing just | |
* a single Thing (one instance represents the Thing and the connection to | |
* Thing-A, another instance might represent the same Thing but the | |
* connection to Thing-B, etc). | |
* | |
* if you can, you should use a class which is able to represent a Thing and | |
* *all* its connections to other Things. this would save you from the | |
* buildGraph()-method too. | |
* | |
*/ | |
public class Thing { | |
String name; | |
Thing connectedTo; | |
public String getName() { | |
return name; | |
} | |
public Thing getConnectedTo() { | |
return connectedTo; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment