This commit is contained in:
joachimschmidt557 2019-02-14 16:43:10 +01:00
commit da6aabcdb0

View file

@ -1,125 +1,148 @@
package base; package base;
import java.util.*; import java.util.*;
/** /**
* Abstrakte generische Klasse um Wege zwischen Knoten in einem Graph zu finden. * Abstrakte generische Klasse um Wege zwischen Knoten in einem Graph zu finden.
* Eine implementierende Klasse ist beispielsweise {@link game.map.PathFinding} * Eine implementierende Klasse ist beispielsweise {@link game.map.PathFinding}
* @param <T> Die Datenstruktur des Graphen * @param <T> Die Datenstruktur des Graphen
*/ */
public abstract class GraphAlgorithm<T> { public abstract class GraphAlgorithm<T> {
/** /**
* Innere Klasse um {@link Node} zu erweitern, aber nicht zu verändern * Innere Klasse um {@link Node} zu erweitern, aber nicht zu verändern
* Sie weist jedem Knoten einen Wert und einen Vorgängerknoten zu. * Sie weist jedem Knoten einen Wert und einen Vorgängerknoten zu.
* @param <T> * @param <T>
*/ */
private static class AlgorithmNode<T> { private static class AlgorithmNode<T> {
private Node<T> node; private Node<T> node;
private double value; private double value;
private AlgorithmNode<T> previous; private AlgorithmNode<T> previous;
AlgorithmNode(Node<T> parentNode, AlgorithmNode<T> previousNode, double value) { AlgorithmNode(Node<T> parentNode, AlgorithmNode<T> previousNode, double value) {
this.node = parentNode; this.node = parentNode;
this.previous = previousNode; this.previous = previousNode;
this.value = value; this.value = value;
} }
} }
private Graph<T> graph; private Graph<T> graph;
// Diese Liste enthält alle Knoten, die noch nicht abgearbeitet wurden // Diese Liste enthält alle Knoten, die noch nicht abgearbeitet wurden
private List<Node<T>> availableNodes; private List<Node<T>> availableNodes;
// Diese Map enthält alle Zuordnungen // Diese Map enthält alle Zuordnungen
private Map<Node<T>, AlgorithmNode<T>> algorithmNodes; private Map<Node<T>, AlgorithmNode<T>> algorithmNodes;
/** /**
* Erzeugt ein neues GraphAlgorithm-Objekt mit dem dazugehörigen Graphen und dem Startknoten. * Erzeugt ein neues GraphAlgorithm-Objekt mit dem dazugehörigen Graphen und dem Startknoten.
* @param graph der zu betrachtende Graph * @param graph der zu betrachtende Graph
* @param sourceNode der Startknoten * @param sourceNode der Startknoten
*/ */
public GraphAlgorithm(Graph<T> graph, Node<T> sourceNode) { public GraphAlgorithm(Graph<T> graph, Node<T> sourceNode) {
this.graph = graph; this.graph = graph;
this.availableNodes = new LinkedList<>(graph.getNodes()); this.availableNodes = new LinkedList<>(graph.getNodes());
this.algorithmNodes = new HashMap<>(); this.algorithmNodes = new HashMap<>();
for(Node<T> node : graph.getNodes()) for(Node<T> node : graph.getNodes())
this.algorithmNodes.put(node, new AlgorithmNode<>(node, null, -1)); this.algorithmNodes.put(node, new AlgorithmNode<>(node, null, -1));
this.algorithmNodes.get(sourceNode).value = 0; this.algorithmNodes.get(sourceNode).value = 0;
} }
/** /**
* Diese Methode gibt einen Knoten mit dem kleinsten Wert, der noch nicht abgearbeitet wurde, zurück und entfernt ihn aus der Liste {@link #availableNodes}. * Diese Methode gibt einen Knoten mit dem kleinsten Wert, der noch nicht abgearbeitet wurde, zurück und entfernt ihn aus der Liste {@link #availableNodes}.
* Sollte kein Knoten gefunden werden, wird null zurückgegeben. * Sollte kein Knoten gefunden werden, wird null zurückgegeben.
* Verbindliche Anforderung: Verwenden Sie beim Durchlaufen der Liste Iteratoren * Verbindliche Anforderung: Verwenden Sie beim Durchlaufen der Liste Iteratoren
* @return Der nächste abzuarbeitende Knoten oder null * @return Der nächste abzuarbeitende Knoten oder null
*/ */
private AlgorithmNode<T> getSmallestNode() { private AlgorithmNode<T> getSmallestNode() {
// TODO: GraphAlgorithm<T>#getSmallestNode() // TODO: GraphAlgorithm<T>#getSmallestNode()
return null; if(availableNodes.isEmpty())
} {
return null;
/** }
* Diese Methode startet den Algorithmus. Dieser funktioniert wie folgt: Iterator<Node<T>> iter = availableNodes.iterator();
* 1. Suche den Knoten mit dem geringsten Wert (siehe {@link #getSmallestNode()}) Iterator<Node<T>> iterMinElem = iter;
* 2. Für jede angrenzende Kante: AlgorithmNode<T> MinElem;
* 2a. Überprüfe ob die Kante passierbar ist ({@link #isPassable(Edge)}) AlgorithmNode<T> tempElem;
* 2b. Berechne den Wert des Knotens, in dem du den aktuellen Wert des Knotens und den der Kante addierst if(iter.hasNext())
* 2c. Ist der alte Wert nicht gesetzt (-1) oder ist der neue Wert kleiner, setze den neuen Wert und den Vorgängerknoten {
* 3. Wiederhole solange, bis alle Knoten abgearbeitet wurden MinElem = algorithmNodes.get(iter.next());
while (iter.hasNext())
* Nützliche Methoden: {
* @see #getSmallestNode() tempElem = algorithmNodes.get(iter.next());
* @see #isPassable(Edge) if(tempElem.value < MinElem.value)
* @see Graph#getEdges(Node) {
* @see Edge#getOtherNode(Node) iterMinElem = iter;
*/ MinElem = tempElem;
public void run() { }
// TODO: GraphAlgorithm<T>#run() }
} iter.remove();
return MinElem;
/** }
* Diese Methode gibt eine Liste von Kanten zurück, die einen Pfad zu dem angegebenen Zielknoten representiert. return null;
* Dabei werden zuerst beginnend mit dem Zielknoten alle Kanten mithilfe des Vorgängerattributs {@link AlgorithmNode#previous} zu der Liste hinzugefügt. }
* Zum Schluss muss die Liste nur noch umgedreht werden. Sollte kein Pfad existieren, geben Sie null zurück.
* @param destination Der Zielknoten des Pfads /**
* @return eine Liste von Kanten oder null * Diese Methode startet den Algorithmus. Dieser funktioniert wie folgt:
*/ * 1. Suche den Knoten mit dem geringsten Wert (siehe {@link #getSmallestNode()})
public List<Edge<T>> getPath(Node<T> destination) { * 2. Für jede angrenzende Kante:
// TODO: GraphAlgorithm<T>#getPath(Node<T>) * 2a. Überprüfe ob die Kante passierbar ist ({@link #isPassable(Edge)})
return null; * 2b. Berechne den Wert des Knotens, in dem du den aktuellen Wert des Knotens und den der Kante addierst
} * 2c. Ist der alte Wert nicht gesetzt (-1) oder ist der neue Wert kleiner, setze den neuen Wert und den Vorgängerknoten
* 3. Wiederhole solange, bis alle Knoten abgearbeitet wurden
/**
* Gibt den betrachteten Graphen zurück * Nützliche Methoden:
* @return der zu betrachtende Graph * @see #getSmallestNode()
*/ * @see #isPassable(Edge)
protected Graph<T> getGraph() { * @see Graph#getEdges(Node)
return this.graph; * @see Edge#getOtherNode(Node)
} */
public void run() {
/** // TODO: GraphAlgorithm<T>#run()
* Gibt den Wert einer Kante zurück. }
* Diese Methode ist abstrakt und wird in den implementierenden Klassen definiert um eigene Kriterien für Werte zu ermöglichen.
* @param edge Eine Kante /**
* @return Ein Wert, der der Kante zugewiesen wird * Diese Methode gibt eine Liste von Kanten zurück, die einen Pfad zu dem angegebenen Zielknoten representiert.
*/ * Dabei werden zuerst beginnend mit dem Zielknoten alle Kanten mithilfe des Vorgängerattributs {@link AlgorithmNode#previous} zu der Liste hinzugefügt.
protected abstract double getValue(Edge<T> edge); * Zum Schluss muss die Liste nur noch umgedreht werden. Sollte kein Pfad existieren, geben Sie null zurück.
* @param destination Der Zielknoten des Pfads
/** * @return eine Liste von Kanten oder null
* Gibt an, ob eine Kante passierbar ist. */
* @param edge Eine Kante public List<Edge<T>> getPath(Node<T> destination) {
* @return true, wenn die Kante passierbar ist. // TODO: GraphAlgorithm<T>#getPath(Node<T>)
*/ return null;
protected abstract boolean isPassable(Edge<T> edge); }
/** /**
* Gibt an, ob eine Knoten passierbar ist. * Gibt den betrachteten Graphen zurück
* @param node Eine Knoten * @return der zu betrachtende Graph
* @return true, wenn der Knoten passierbar ist. */
*/ protected Graph<T> getGraph() {
protected abstract boolean isPassable(Node<T> node); return this.graph;
} }
/**
* Gibt den Wert einer Kante zurück.
* Diese Methode ist abstrakt und wird in den implementierenden Klassen definiert um eigene Kriterien für Werte zu ermöglichen.
* @param edge Eine Kante
* @return Ein Wert, der der Kante zugewiesen wird
*/
protected abstract double getValue(Edge<T> edge);
/**
* Gibt an, ob eine Kante passierbar ist.
* @param edge Eine Kante
* @return true, wenn die Kante passierbar ist.
*/
protected abstract boolean isPassable(Edge<T> edge);
/**
* Gibt an, ob eine Knoten passierbar ist.
* @param node Eine Knoten
* @return true, wenn der Knoten passierbar ist.
*/
protected abstract boolean isPassable(Node<T> node);
}