package graph; import java.awt.*; import java.util.ArrayList; import java.util.List; public class ExampleGraphs { public DirectedGraph example1() { /* * Beispiel 1 zeigt ein Gitter aus Knoten und Kanten, bei dem jeder Knoten mit * seinen horizontal und vertikal benachbarten Knoten verbunden ist. Alle Kanten * haben die gleiche Gewichtung. Der Startknoten befindet sich in einer Ecke * des Gitters und der Zielknoten in der gegenüberliegenden Ecke. * * Ziel: * Demonstrieren, wie der A*-Algorithmus durch gezieltere Suche effizienter ist * als der Dijkstra-Algorithmus in einem strukturierten Gittergraphen. * * Startknoten: A * Endknoten: Y */ DirectedGraph example1 = new DirectedGraph<>(); int size = 5; MarkedVertex[][] vertices = new MarkedVertex[size][size]; // Knoten erstellen und zum Graph hinzufügen for (int row = 0; row < size; row++) { for (int col = 0; col < size; col++) { String name = String.valueOf((char) ('A' + row * size + col)); if (name.equals("A")) { name = "Start"; } else if (name.equals("Y")) { name = "Ende"; } vertices[row][col] = new MarkedVertex<>(50 + col * 100, 50 + row * 100, name, null, null); example1.addVertex(vertices[row][col]); } } // Kanten horizontal und vertikal verbinden for (int row = 0; row < size; row++) { for (int col = 0; col < size; col++) { if (col < size - 1) { addBidirectionalEdge(example1, vertices[row][col], vertices[row][col + 1], new EdgeWeightMarking(1)); } if (row < size - 1) { addBidirectionalEdge(example1, vertices[row][col], vertices[row + 1][col], new EdgeWeightMarking(1)); } } } return example1; } private void addBidirectionalEdge(DirectedGraph graph, MarkedVertex from, MarkedVertex to, EdgeWeightMarking weight) { MarkedEdge forwardEdge = new MarkedEdge<>("edge" + from.getName() + "_" + to.getName(), from, to, weight); MarkedEdge backwardEdge = new MarkedEdge<>("edge" + to.getName() + "_" + from.getName(), to, from, weight); graph.addEdge(forwardEdge); graph.addEdge(backwardEdge); } public DirectedGraph example2() { DirectedGraph example2 = new DirectedGraph<>(); /* * Beispiel 2 zeigt zwei Wege von einem Startknoten zu einem Zielknoten mit unterschiedlichen Eigenschaften: * Ein Weg (oben) hat wenige Knoten mit Kanten geringer Gewichtung, außer der letzten Kante, die hohe Gewichtung hat. * Der andere Weg (unten) hat mehr Knoten mit höherer Gewichtung der Kanten. Der Algorithmus sollte zuerst den oberen * Weg erkunden, bis er die hohe Gewichtung der letzten Kante des unteren Wegs berücksichtigt. * * Startknoten: A * Endknoten: E */ MarkedVertex A = new MarkedVertex<>(100, 100, "Start", null, null); MarkedVertex B = new MarkedVertex<>(250, 50, "B", null, null); MarkedVertex C = new MarkedVertex<>(400, 100, "C", null, null); MarkedVertex D = new MarkedVertex<>(550, 50, "D", null, null); MarkedVertex E = new MarkedVertex<>(700, 100, "Ende", null, null); MarkedVertex F = new MarkedVertex<>(250, 200, "F", null, null); MarkedVertex G = new MarkedVertex<>(550, 200, "G", null, null); example2.addVertex(A); example2.addVertex(B); example2.addVertex(C); example2.addVertex(D); example2.addVertex(E); example2.addVertex(F); example2.addVertex(G); example2.addEdge(new MarkedEdge<>("AB", A, B, new EdgeWeightMarking(1))); example2.addEdge(new MarkedEdge<>("BC", B, C, new EdgeWeightMarking(1))); example2.addEdge(new MarkedEdge<>("CD", C, D, new EdgeWeightMarking(10))); example2.addEdge(new MarkedEdge<>("DE", D, E, new EdgeWeightMarking(1))); example2.addEdge(new MarkedEdge<>("AF", A, F, new EdgeWeightMarking(5))); example2.addEdge(new MarkedEdge<>("FG", F, G, new EdgeWeightMarking(5))); example2.addEdge(new MarkedEdge<>("GE", G, E, new EdgeWeightMarking(5))); return example2; } public DirectedGraph example3() { /* * Beispiel 3 zeigt ein Labyrinth mit vier horizontalen Wegen, die jeweils aus vier Knoten bestehen. * Jeder Weg führt zum Endpunkt E1, E2, E3 bzw. E4. Ziel ist es zu zeigen, dass die Algorithmen auch * potenziell falsche Wege erkunden können, bevor sie den richtigen Endpunkt erreichen. * * Startknoten: A * Endknoten: E2 */ DirectedGraph example3 = new DirectedGraph<>(); // Startpunkt A in der Mitte der Y-Koordinate MarkedVertex A = new MarkedVertex<>(100, 250, "Start", null, null); // Erster Weg MarkedVertex B1 = new MarkedVertex<>(200, 100, "B1", null, null); MarkedVertex C1 = new MarkedVertex<>(300, 100, "C1", null, null); MarkedVertex D1 = new MarkedVertex<>(400, 100, "D1", null, null); MarkedVertex E1 = new MarkedVertex<>(500, 100, "E1", null, null); // Endpunkt des ersten Weges // Zweiter Weg MarkedVertex B2 = new MarkedVertex<>(200, 200, "B2", null, null); MarkedVertex C2 = new MarkedVertex<>(300, 200, "C2", null, null); MarkedVertex D2 = new MarkedVertex<>(400, 200, "D2", null, null); MarkedVertex E2 = new MarkedVertex<>(500, 200, "E2", null, null); // Endpunkt des zweiten Weges // Dritter Weg MarkedVertex B3 = new MarkedVertex<>(200, 300, "B3", null, null); MarkedVertex C3 = new MarkedVertex<>(300, 300, "C3", null, null); MarkedVertex D3 = new MarkedVertex<>(400, 300, "D3", null, null); MarkedVertex E3 = new MarkedVertex<>(500, 300, "E3", null, null); // Endpunkt des dritten Weges // Vierter Weg MarkedVertex B4 = new MarkedVertex<>(200, 400, "B4", null, null); MarkedVertex C4 = new MarkedVertex<>(300, 400, "C4", null, null); MarkedVertex D4 = new MarkedVertex<>(400, 400, "D4", null, null); MarkedVertex E4 = new MarkedVertex<>(500, 400, "Ende", null, null); // Endpunkt des vierten Weges example3.addVertex(A); example3.addVertex(B1); example3.addVertex(C1); example3.addVertex(D1); example3.addVertex(B2); example3.addVertex(C2); example3.addVertex(D2); example3.addVertex(B3); example3.addVertex(C3); example3.addVertex(D3); example3.addVertex(B4); example3.addVertex(C4); example3.addVertex(D4); example3.addVertex(E1); example3.addVertex(E2); example3.addVertex(E3); example3.addVertex(E4); example3.addEdge(new MarkedEdge<>("AB1", A, B1, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("AB2", A, B2, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("AB3", A, B3, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("AB4", A, B4, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("B1C1", B1, C1, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("B2C2", B2, C2, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("B3C3", B3, C3, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("B4C4", B4, C4, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("C1D1", C1, D1, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("C2D2", C2, D2, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("C3D3", C3, D3, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("C4D4", C4, D4, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("D1E1", D1, E1, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("D2E2", D2, E2, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("D3E3", D3, E3, new EdgeWeightMarking(1))); example3.addEdge(new MarkedEdge<>("D4E4", D4, E4, new EdgeWeightMarking(1))); return example3; } public DirectedGraph example4() { /** * Erstellt einen Beispielgraphen (Beispiel 4), der sich ideal für die Demonstration der Funktionsweise * des Dijkstra- und A*-Algorithmus eignet. Der Graph enthält eine Vielzahl von Knoten, die durch * gewichtete Kanten verbunden sind. Dies ermöglicht es, den kürzesten Weg von einem Startknoten zu einem * Zielknoten effizient zu berechnen und die Unterschiede zwischen den beiden Algorithmen in der * Pfadfindung zu veranschaulichen. * * Startknoten: A * Zielknoten: H * */ DirectedGraph example4 = new DirectedGraph<>(); // Erstellung der Knoten mit Koordinaten MarkedVertex A = new MarkedVertex<>(50, 250, "Start", null, null); MarkedVertex B = new MarkedVertex<>(150, 150, "B", null, null); MarkedVertex C = new MarkedVertex<>(150, 350, "C", null, null); MarkedVertex D = new MarkedVertex<>(250, 100, "D", null, null); MarkedVertex E = new MarkedVertex<>(250, 250, "E", null, null); MarkedVertex F = new MarkedVertex<>(350, 200, "F", null, null); MarkedVertex G = new MarkedVertex<>(450, 300, "G", null, null); MarkedVertex H = new MarkedVertex<>(450, 100, "Ende", null, null); // Hinzufügen der Knoten zum Graphen example4.addVertex(A); example4.addVertex(B); example4.addVertex(C); example4.addVertex(D); example4.addVertex(E); example4.addVertex(F); example4.addVertex(G); example4.addVertex(H); // Erstellung der Kanten mit Gewichtungen example4.addEdge(new MarkedEdge<>("AB", A, B, new EdgeWeightMarking(4))); example4.addEdge(new MarkedEdge<>("AC", A, C, new EdgeWeightMarking(2))); example4.addEdge(new MarkedEdge<>("BC", B, C, new EdgeWeightMarking(5))); example4.addEdge(new MarkedEdge<>("BD", B, D, new EdgeWeightMarking(10))); example4.addEdge(new MarkedEdge<>("CD", C, D, new EdgeWeightMarking(3))); example4.addEdge(new MarkedEdge<>("CE", C, E, new EdgeWeightMarking(7))); example4.addEdge(new MarkedEdge<>("DE", D, E, new EdgeWeightMarking(2))); example4.addEdge(new MarkedEdge<>("DF", D, F, new EdgeWeightMarking(2))); example4.addEdge(new MarkedEdge<>("EF", E, F, new EdgeWeightMarking(5))); example4.addEdge(new MarkedEdge<>("EG", E, G, new EdgeWeightMarking(10))); example4.addEdge(new MarkedEdge<>("FG", F, G, new EdgeWeightMarking(3))); example4.addEdge(new MarkedEdge<>("FH", F, H, new EdgeWeightMarking(6))); example4.addEdge(new MarkedEdge<>("GH", G, H, new EdgeWeightMarking(1))); return example4; } }