diff --git a/Dijkstra/.classpath b/Dijkstra/.classpath new file mode 100644 index 0000000..f7d6ef1 --- /dev/null +++ b/Dijkstra/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/Dijkstra/.project b/Dijkstra/.project new file mode 100644 index 0000000..e92c65a --- /dev/null +++ b/Dijkstra/.project @@ -0,0 +1,17 @@ + + + Dijkstra + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/Dijkstra/.settings/org.eclipse.jdt.core.prefs b/Dijkstra/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..bb35fa0 --- /dev/null +++ b/Dijkstra/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/Dijkstra/Lab4-en.pdf b/Dijkstra/Lab4-en.pdf new file mode 100644 index 0000000..dcee21a Binary files /dev/null and b/Dijkstra/Lab4-en.pdf differ diff --git a/Dijkstra/TestFile1 b/Dijkstra/TestFile1 new file mode 100644 index 0000000..549326a --- /dev/null +++ b/Dijkstra/TestFile1 @@ -0,0 +1,20 @@ +Digraph { +A -> B [label="10,90"]; +A -> C [label="8,80"]; +C -> B [label="1,50"]; +B -> D [label="7,60"]; +C -> D [label="6,80"]; +D -> E [label="4,90"]; +E -> F [label="2,130"]; +D -> F [label="5,130"]; +F -> G [label="5,120"]; +G -> H [label="5,100"]; +A [label="A,5"]; +B [label="B,4"]; +C [label="C,3"]; +D [label="D,2"]; +E [label="E,1"]; +F [label="F,6"]; +G [label="G,7"]; +H [label="H,8"]; +} \ No newline at end of file diff --git a/Dijkstra/TestFile2 b/Dijkstra/TestFile2 new file mode 100644 index 0000000..5075eaa --- /dev/null +++ b/Dijkstra/TestFile2 @@ -0,0 +1,16 @@ +Digraph { +A -> B [label="3,100"]; +A -> F [label="16,80"]; +B -> C [label="5,80"]; +C -> D [label="4,80"]; +C -> E [label="7,100"]; +D -> E [label="2,40"]; +D -> F [label="8,30"]; +E -> F [label="4,60"]; +A [label="A,0"]; +B [label="B,2"]; +C [label="C,3"]; +D [label="D,1"]; +E [label="E,1"]; +F [label="F,2"]; +} \ No newline at end of file diff --git a/Dijkstra/src/frame/AllTests.java b/Dijkstra/src/frame/AllTests.java new file mode 100644 index 0000000..74504fb --- /dev/null +++ b/Dijkstra/src/frame/AllTests.java @@ -0,0 +1,279 @@ +package frame; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import lab.Navigation; + +public class AllTests { + + private enum OutputFormat { + Distance, Time + }; + + @Nested + @DisplayName("Dijkstra TestFile1") + class TestFile1 { + + @Test + @DisplayName("Test Distance from A to C") + public final void testFile1_A_C_Distance() { + assertEquals(8, testDistance("TestFile1", "A", "C"), "From A to C: "); + } + + @Test + @DisplayName("Test Distance from A to G") + public final void testFile1_A_G_Distance() { + assertEquals(24, testDistance("TestFile1", "A", "G"), "From A to G: "); + } + + @Test + @DisplayName("Test Time from A to D") + public final void testFile1_A_D_Time() { + assertEquals(14, testTime("TestFile1", "A", "D"), "From A to D: "); + } + + @Test + @DisplayName("Test Time from A to F") + public final void testFile1_A_F_Time() { + assertEquals(18, testTime("TestFile1", "A", "F"), "From A to F: "); + } + + @Test + @DisplayName("Test Shortest Route from A to E") + public final void testfile1_Route_A_E_Distance() { + ArrayList route = new ArrayList(); + Navigation nav = new Navigation("TestFile1"); + // Build the route we expect to find + route.add("A\\s*->\\s*C"); + route.add("C\\s*->\\s*D"); + route.add("D\\s*->\\s*E"); + assertTrue(testRoute(nav.findShortestRoute("A", "E"), route), "Route not correct"); + } + + @Test + @DisplayName("Test Fastest Route from A to F") + public final void testfile1_Route_A_F_Time() { + ArrayList route = new ArrayList(); + Navigation nav = new Navigation("TestFile1"); + // Build the route we expect to find + route.add("A\\s*->\\s*C"); + route.add("C\\s*->\\s*D"); + route.add("D\\s*->\\s*F"); + assertTrue(testRoute(nav.findFastestRoute("A", "F"), route), "Route not correct"); + } + + } + + @Nested + @DisplayName("Dijkstra TestFile2") + class TestFile2 { + + @Test + @DisplayName("Test Distance from A to C") + public final void testFile2_A_C_Distance() { + assertEquals(8, testDistance("TestFile2", "A", "C"), "From A to C: "); + } + + @Test + @DisplayName("Test Distance from A to D") + public final void testFile2_A_D_Distance() { + assertEquals(12, testDistance("TestFile2", "A", "D"), "From A to D: "); + } + + @Test + @DisplayName("Test Distance from A to F") + public final void testFile2_A_F_Distance() { + assertEquals(16, testDistance("TestFile2", "A", "F"), "From A to F: "); + } + + @Test + @DisplayName("Test Time from A to C") + public final void testFile2_A_C_Time() { + assertEquals(8, testTime("TestFile2", "A", "C"), "From A to C: "); + } + + @Test + @DisplayName("Test Time from A to E") + public final void testFile2_A_E_Time() { + assertEquals(15, testTime("TestFile2", "A", "E"), "From A to E: "); + } + + @Test + @DisplayName("Test Time from A to F") + public final void testFile2_A_F_Time() { + assertEquals(12, testTime("TestFile2", "A", "F"), "From A to F: "); + } + + @Test + @DisplayName("Test Number of Vertices on Shortest Route from A to B") + public final void testFile2_Size() { + Navigation nav = new Navigation("TestFile2"); + assertEquals(16, nav.findShortestRoute("A", "B").size(), "Number of entries in output map: "); + } + + @Test + @DisplayName("Test Missing vertex G") + public final void testFile2_Negative() { + Navigation nav = new Navigation("TestFile2"); + assertEquals(-2, nav.findShortestDistance("A", "G"), "Test non-existing vertex: "); + } + + @Test + @DisplayName("Test Shortest Route from A to E") + public final void testfile2_Route_A_E_Distance() { + ArrayList route = new ArrayList(); + Navigation nav = new Navigation("TestFile2"); + // Build the route we expect to find + route.add("A\\s*->\\s*B"); + route.add("B\\s*->\\s*C"); + route.add("C\\s*->\\s*D"); + route.add("D\\s*->\\s*E"); + assertTrue(testRoute(nav.findShortestRoute("A", "E"), route), "Route not correct"); + } + + @Test + @DisplayName("Test Fastest Route from A to E") + public final void testfile2_Route_A_E_Time() { + ArrayList route = new ArrayList<>(); + Navigation nav = new Navigation("TestFile2"); + // Build the route we expect to find + route.add("A\\s*->\\s*B"); + route.add("B\\s*->\\s*C"); + route.add("C\\s*->\\s*E"); + assertTrue(testRoute(nav.findFastestRoute("A", "E"), route), "Route not correct"); + } + + } + + /** + * This method returns the shortest distance from start to stop on the map + * stored in filename. + * + * It also writes the output map to a file. The file name follows the following + * format: + * + * output_[filename]_from[start]to[stop]Distance.txt + * + * @param filename + * The name of the file storing the map + * @param start + * Source node + * @param stop + * Destination node + * @return The shortest distance between start and stop in km + */ + private final int testDistance(String filename, String start, String stop) { + Navigation nav = new Navigation(filename); + ArrayList returnMap = new ArrayList(); + + returnMap = nav.findShortestRoute(start, stop); + writeGraphToFile(returnMap, filename, start, stop, OutputFormat.Distance); + return nav.findShortestDistance(start, stop); + } + + /** + * This method returns the fastest route from start to stop on the map stored in + * filename. + * + * It also writes the output map to a file. The file name follows the following + * format: + * + * output_[filename]_from[start]to[stop]Time.txt + * + * @param filename + * The name of the file storing the map + * @param start + * Source node + * @param stop + * Destination node + * @return Fastest route in minutes + */ + private final int testTime(String filename, String start, String stop) { + Navigation nav = new Navigation(filename); + ArrayList returnMap = new ArrayList(); + + returnMap = nav.findFastestRoute(start, stop); + writeGraphToFile(returnMap, filename, start, stop, OutputFormat.Time); + return nav.findFastestTime(start, stop); + } + + /** + * This method tests wether the edges contained in boldEdges are present and + * marked as bold in map + * + * @param map + * The map to check, in dot format + * @param boldEdges + * The edges to find + * @return True if all edges in boldEdges are marked bold in map + */ + private final boolean testRoute(ArrayList map, ArrayList boldEdges) { + boolean correct = true; + int matches = 0; + for (String edge : boldEdges) { // for all edges we're looking for + for (String line : map) { // for all lines in the map + if (line.matches(".*" + edge + ".*")) { // if the edge is there + correct = correct && line.matches(".*bold.*"); // check if it is bold + matches++; // Count the number of bold lines correctly found + } + } + } + // Check if we found all of them + correct = correct && (matches == boldEdges.size()); + return correct; + } + + /** + * This method writes a map to file + * + * The format of the filename of the file created depends on the last four + * parameters: + * + * if format = OutputFormat.Time: output_[filename]_from[start]to[stop]Time.txt + * if format = OutputFormat.Distance: + * output_[filename]_from[start]to[stop]Distance.txt + * + * @param map + * @param filename + * @param start + * @param stop + * @param format + */ + public final void writeGraphToFile(ArrayList map, String filename, String start, String stop, + OutputFormat format) { + try { + String typeString = null; + switch (format) { + case Distance: + typeString = "distance"; + break; + case Time: + typeString = "time"; + break; + } + + FileWriter fw = new FileWriter("output_" + filename + "_from" + start + "to" + stop + typeString + ".txt"); + BufferedWriter bw = new BufferedWriter(fw); + + for (String element : map) { + bw.write(element); + bw.newLine(); + } + bw.flush(); + bw.close(); + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/Dijkstra/src/lab/Navigation.java b/Dijkstra/src/lab/Navigation.java new file mode 100644 index 0000000..1995972 --- /dev/null +++ b/Dijkstra/src/lab/Navigation.java @@ -0,0 +1,129 @@ +package lab; + +import java.util.ArrayList; + +/** + * The class Navigation finds the shortest (and/or) path between points on a map + * using the Dijkstra algorithm + */ +public class Navigation { + /** + * Return codes: -1 if the source is not on the map -2 if the destination is + * not on the map -3 if both source and destination points are not on the + * map -4 if no path can be found between source and destination + */ + + public static final int SOURCE_NOT_FOUND = -1; + public static final int DESTINATION_NOT_FOUND = -2; + public static final int SOURCE_DESTINATION_NOT_FOUND = -3; + public static final int NO_PATH = -4; + + /** + * The constructor takes a filename as input, it reads that file and fill + * the nodes and edges Lists with corresponding node and edge objects + * + * @param filename + * name of the file containing the input map + */ + public Navigation(String filename) { + //TODO Add you code here + + } + + /** + * This methods finds the shortest route (distance) between points A and B + * on the map given in the constructor. + * + * If a route is found the return value is an object of type + * ArrayList, where every element is a String representing one line + * in the map. The output map is identical to the input map, apart from that + * all edges on the shortest route are marked "bold". It is also possible to + * output a map where all shortest paths starting in A are marked bold. + * + * The order of the edges as they appear in the output may differ from the + * input. + * + * @param A + * Source + * @param B + * Destinaton + * @return returns a map as described above if A or B is not on the map or + * if there is no path between them the original map is to be + * returned. + */ + public ArrayList findShortestRoute(String A, String B) { + //TODO Add you code here + + return new ArrayList<>(); // dummy, replace + } + + /** + * This methods finds the fastest route (in time) between points A and B on + * the map given in the constructor. + * + * If a route is found the return value is an object of type + * ArrayList, where every element is a String representing one line + * in the map. The output map is identical to the input map, apart from that + * all edges on the shortest route are marked "bold". It is also possible to + * output a map where all shortest paths starting in A are marked bold. + * + * The order of the edges as they appear in the output may differ from the + * input. + * + * @param A + * Source + * @param B + * Destinaton + * @return returns a map as described above if A or B is not on the map or + * if there is no path between them the original map is to be + * returned. + */ + public ArrayList findFastestRoute(String A, String B) { + //TODO Add you code here + + return new ArrayList<>(); // dummy, replace + } + + /** + * Finds the shortest distance in kilometers between A and B using the + * Dijkstra algorithm. + * + * @param A + * the start point A + * @param B + * the destination point B + * @return the shortest distance in kilometers rounded upwards. + * SOURCE_NOT_FOUND if point A is not on the map + * DESTINATION_NOT_FOUND if point B is not on the map + * SOURCE_DESTINATION_NOT_FOUND if point A and point B are not on + * the map NO_PATH if no path can be found between point A and point + * B + */ + public int findShortestDistance(String A, String B) { + //TODO Add you code here + int sd = 0; + + return sd; + } + + /** + * Find the fastest route between A and B using the dijkstra algorithm. + * + * @param A + * Source + * @param B + * Destination + * @return the fastest time in minutes rounded upwards. SOURCE_NOT_FOUND if + * point A is not on the map DESTINATION_NOT_FOUND if point B is not + * on the map SOURCE_DESTINATION_NOT_FOUND if point A and point B + * are not on the map NO_PATH if no path can be found between point + * A and point B + */ + public int findFastestTime(String pointA, String pointB) { + //TODO Add you code here + int ft = 0; + + return ft; + } + +}