diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java b/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java new file mode 100644 index 0000000..f07b850 --- /dev/null +++ b/src/main/java/fr/u_paris/gla/project/itinerary/Finder.java @@ -0,0 +1,91 @@ +package fr.u_paris.gla.project.itinerary; + +import java.util.*; + +public class Finder { + private Graph graph; + public Finder(Graph graph) { + this.graph = graph; + } + + public List findPath(Stop startNode, Stop goalNode) { + PriorityQueue openSet = new PriorityQueue<>(Comparator.comparingDouble(GraphNode::getF)); + HashSet closedSet = new HashSet<>(); + HashMap cameFrom = new HashMap<>(); + HashMap gScore = new HashMap<>(); + HashMap fScore = new HashMap<>(); + + // Initialize scores for all nodes to infinity + for (Stop node : graph.getNodes()) { + gScore.put(node, Double.POSITIVE_INFINITY); + fScore.put(node, Double.POSITIVE_INFINITY); + } + + // The cost of going from start to start is zero + gScore.put(startNode, 0.0); + // For the first node, fScore = gScore + heuristic + fScore.put(startNode, startNode.getHeuristicCost(goalNode)); + openSet.add(startNode); + + while (!openSet.isEmpty()) { + Stop current = openSet.poll(); + //System.out.println(current); + //System.out.println(graph.getConnections(current)); + + if (current.equals(goalNode)) { + return reconstructPath(cameFrom, current); + } + + closedSet.add(current); + + if(graph.getConnections(current) == null) { + continue; + } + + for (Connection connection : graph.getConnections(current) ) { + Stop neighbor = connection.getStop(); + if (closedSet.contains(neighbor)) { + continue; // Ignore the neighbor which is already evaluated. + } + + double tentativeGScore = gScore.get(current) + connection.getDistance(); + + if (!openSet.contains(neighbor)) { + openSet.add(neighbor); + } else if (tentativeGScore >= gScore.get(neighbor)) { + continue; // This is not a better path. + } + + // This path is the best until now. Record it! + cameFrom.put(neighbor, current); + gScore.put(neighbor, tentativeGScore); + fScore.put(neighbor, tentativeGScore + neighbor.getHeuristicCost(goalNode)); + neighbor.setF(fScore.get(neighbor)); + } + } + + // If we reach here, it means there's no path from start to goal + return null; + } + + private List reconstructPath(HashMap cameFrom, Stop current) { + List totalPath = new ArrayList<>(); + totalPath.add(current); + + while (cameFrom.containsKey(current)) { + current = cameFrom.get(current); + totalPath.add(0, current); // Add to the beginning of the list to maintain order + } + + return totalPath; + } + + //TODO: + public List findPath(double longitude, double latitude){ + return null; + } + + +} + + diff --git a/src/main/java/fr/u_paris/gla/project/itinerary/GraphNode.java b/src/main/java/fr/u_paris/gla/project/itinerary/GraphNode.java new file mode 100644 index 0000000..175db6e --- /dev/null +++ b/src/main/java/fr/u_paris/gla/project/itinerary/GraphNode.java @@ -0,0 +1,14 @@ +package fr.u_paris.gla.project.itinerary; + +import java.util.List; +import java.util.Set; + +public interface GraphNode { + int getId(); + double getHeuristicCost(Stop goalNode); + + Set getNeighbors(); + double getCost(Stop neighbor); + double getF(); + void setF(double value); +} diff --git a/src/main/java/fr/u_paris/gla/project/utils/CSVTools.java b/src/main/java/fr/u_paris/gla/project/utils/CSVTools.java new file mode 100644 index 0000000..dd41636 --- /dev/null +++ b/src/main/java/fr/u_paris/gla/project/utils/CSVTools.java @@ -0,0 +1,96 @@ +/** + * + */ +package fr.u_paris.gla.project.utils; + +import java.io.*; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import com.opencsv.CSVParserBuilder; +import com.opencsv.CSVReader; +import com.opencsv.CSVReaderBuilder; +import com.opencsv.CSVWriterBuilder; +import com.opencsv.ICSVParser; +import com.opencsv.ICSVWriter; +import com.opencsv.exceptions.CsvValidationException; + +/** A CSV tool class. + * + * @author Emmanuel Bigeon */ +public final class CSVTools { + + /** Hidden constructor of tool class */ + private CSVTools() { + // Tool class + } + + private static void readCSVFromInputStream(InputStream is, Consumer contentLineConsumer) + throws IOException { + ICSVParser parser = new CSVParserBuilder().withSeparator(';').build(); + try (Reader reader = new BufferedReader( + new InputStreamReader(is, StandardCharsets.UTF_8))) { + CSVReaderBuilder csvBuilder = new CSVReaderBuilder(reader) + .withCSVParser(parser); + try (CSVReader csv = csvBuilder.build()) { + String[] line = csv.readNextSilently(); // Eliminate header + while (csv.peek() != null) { + line = csv.readNext(); + contentLineConsumer.accept(line); + } + } + } catch (CsvValidationException e) { + throw new IOException("Invalid csv file", e); //$NON-NLS-1$ + } + } + + public static void readCSVFromFile(String filename, Consumer contentLineConsumer) + throws IOException { + File file = new File(filename); + readCSVFromInputStream(new FileInputStream(file), contentLineConsumer); + } + + /** get a CSV file from a URL, download and parse it, and keep values in memory + * @param url the address of the CSV file + * @param contentLineConsumer the variable used to store the data + * @throws IOException if it's impossible to download the file + */ + public static void readCSVFromURL(String url, Consumer contentLineConsumer) + throws IOException { + readCSVFromInputStream(new URL(url).openStream(), contentLineConsumer); + } + + /** Save our current CSV variable's data into an actual file + * @param filename the saved file's name and path + * @param contentLineConsumer our data variable + * @throws IOException if we can't write the data into the file + */ + public static void writeCSVToFile(String filename, + Stream contentLinesConsumer) throws IOException { + try (FileWriter writer = new FileWriter(filename, StandardCharsets.UTF_8)) { + CSVWriterBuilder wBuilder = new CSVWriterBuilder(writer).withSeparator(';'); + try (ICSVWriter csv = wBuilder.build()) { + contentLinesConsumer.forEachOrdered(csv::writeNext); + } + } + } + + // /** Save our current CSV variable's data into an actual file + // * @param filename the saved file's name and path + // * @param contentLineConsumer our data variable + // * @throws IOException if we can't write the data into the file + // */ + // public static void writeCSVToFile(String filename, + // Stream contentLinesConsumer) throws IOException { + // try (FileWriter writer = new FileWriter(filename, StandardCharsets.UTF_8)) { + // CSVWriterBuilder wBuilder = new CSVWriterBuilder(writer).withSeparator(';'); + // try (ICSVWriter csv = wBuilder.build()) { + // contentLinesConsumer.forEachOrdered(line -> Arrays.stream(line).forEach(csv::writeNext)); + // } + // } + // } + +}