From ae113856d02c93019ee4187aaa4fcb0be7dbe7f1 Mon Sep 17 00:00:00 2001 From: Ksan Date: Thu, 24 Jul 2025 00:16:59 +0200 Subject: [PATCH] added shortest path finder with dijkstras alg --- src/City.java | 43 ++++++----- src/CityManager.java | 14 ++++ src/Departure.java | 7 +- src/Graph.java | 89 ++++++++++++++++++++++ src/JsonParser.java | 127 ++++++++++++++++++++++---------- src/Location.java | 41 +++++++++++ src/Station.java | 20 +++++ src/TransportDataGenerator.java | 4 +- src/User.java | 48 ++++++++++++ 9 files changed, 332 insertions(+), 61 deletions(-) create mode 100644 src/CityManager.java create mode 100644 src/Graph.java create mode 100644 src/Location.java create mode 100644 src/User.java diff --git a/src/City.java b/src/City.java index cfc2036..b1f3d36 100644 --- a/src/City.java +++ b/src/City.java @@ -1,22 +1,37 @@ +import java.util.ArrayList; +import java.util.List; + public class City { private String name; private Station trainStation; private Station busStation; - private int row; - private int col; + private Location location; - City(String name, String train, String bus, int row, int col) { + City(String name, String bus, String train, int row, int col) { this.name = name; this.trainStation = new Station(TransportType.TRAIN, train); this.busStation = new Station(TransportType.BUS, bus); + this.location = new Location(row, col); } - City(String name, Station train, Station bus, int row, int col) { + City(String name, Station bus, Station train, int row, int col) { this.name = name; this.trainStation = train; this.busStation = bus; - this.row = row; - this.col = col; + this.location = new Location(row, col); + } + + public List getDestinations() { + List departures = new ArrayList<>(); + + for (Departure dep : busStation.getDepartures()) { + departures.add(dep); + } + for (Departure dep : trainStation.getDepartures()) { + departures.add(dep); + } + + return departures; } public String getName() { @@ -43,20 +58,8 @@ public class City { this.busStation = busStation; } - public int getRow() { - return row; - } - - public void setRow(int row) { - this.row = row; - } - - public int getCol() { - return col; - } - - public void setCol(int col) { - this.col = col; + public Location getLocation() { + return this.location; } @Override diff --git a/src/CityManager.java b/src/CityManager.java new file mode 100644 index 0000000..f4e333b --- /dev/null +++ b/src/CityManager.java @@ -0,0 +1,14 @@ +import java.util.HashMap; +import java.util.Map; + +public class CityManager { + private static Map cities = new HashMap<>(); + + public static void addCity(City city) { + cities.put(city.getName(), city); + } + + public static City getCityByName(String cityName) { + return cities.get(cityName); + } +} diff --git a/src/Departure.java b/src/Departure.java index 4871177..7525189 100644 --- a/src/Departure.java +++ b/src/Departure.java @@ -27,6 +27,11 @@ public class Departure { this.minTransferTime = minTransferTime; } + public City getDestinationCity() { + + return CityManager.getCityByName(to); + } + public TransportType getType() { return type; } @@ -70,6 +75,6 @@ public class Departure { + price + ", minTransferTime=" + minTransferTime - + '}'; + + "}"; } } diff --git a/src/Graph.java b/src/Graph.java new file mode 100644 index 0000000..d223d93 --- /dev/null +++ b/src/Graph.java @@ -0,0 +1,89 @@ +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; + +public class Graph { + private City[][] matrix; + + public static void main(String[] args) { + List cities = JsonParser.parseCities("transport_data.json", "stations"); + List departures = JsonParser.getDeparturesList("transport_data.json", "departures"); + cities = JsonParser.loadDepartures(cities, departures); + City[][] map = JsonParser.loadMap("transport_data.json", "countryMap", cities); + + Graph graph = new Graph(map); + cities = JsonParser.loadDepartures(cities, departures); + System.out.println(cities.getFirst().getName() + " do " + cities.getLast().getName()); + for (City city : cities) { + CityManager.addCity(city); + } + Map result = + graph.calculateShortestPath(cities.getFirst(), cities.get(3), "price"); + System.out.println( + cities.getLast().getName() + " = " + result.get(cities.get(3).getLocation())); + } + + public Map calculateShortestPath(City startCity, City endCity, String type) { + int n = matrix.length; + int m = matrix[0].length; + + Map distances = new HashMap<>(); + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + distances.put(new Location(i, j), Double.MAX_VALUE); + } + } + + distances.put(startCity.getLocation(), 0.0); + + PriorityQueue pq = + new PriorityQueue<>(Comparator.comparingDouble(city -> distances.get(city.getLocation()))); + pq.add(startCity); + + while (!pq.isEmpty()) { + City current = pq.poll(); + + // If we reached the end city, we can stop early + if (current == endCity) { + break; + } + + for (Departure dep : current.getDestinations()) { + City neighborCity = dep.getDestinationCity(); + Location neighborLocation = neighborCity.getLocation(); + + double newCost = 0.0; + if (type.equals("price")) { + newCost = distances.get(current.getLocation()) + dep.getPrice(); + } else if (type.equals("time")) { + newCost = distances.get(current.getLocation()) + dep.getDuration(); + } + + if (newCost < distances.get(neighborLocation)) { + distances.put(neighborLocation, newCost); + pq.add(neighborCity); + } + } + } + + return distances; + } + + public Graph(City[][] matrix) { + this.matrix = matrix; + } + + public void updateMatrix(City[][] matrix) { + this.matrix = matrix; + } + + public City[][] getMatrix() { + return matrix; + } + + public City getCity(Location loc) { + return matrix[loc.getX()][loc.getY()]; + } +} diff --git a/src/JsonParser.java b/src/JsonParser.java index e73be1b..cf3d8da 100644 --- a/src/JsonParser.java +++ b/src/JsonParser.java @@ -2,20 +2,26 @@ import java.io.BufferedReader; import java.io.FileReader; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class JsonParser { + /* + public static void main(String[] args) { + String[][] map = JsonParser.parseCountryMap("transport_data.json", "countryMap"); + List cities = JsonParser.parseCities("transport_data.json", "stations"); + List departures = JsonParser.getDeparturesList("transport_data.json", "departures"); - public static void main(String[] args) { - // String[][] map = JsonParser.parseCountryMap("transport_data.json", "countryMap"); - // JsonParser.parseCities("transport_data.json", "stations"); - JsonParser.getDeparturesList("transport_data.json", "departures"); - } - + cities = JsonParser.loadDepartures(cities, departures); + for (City city : cities) { + System.out.println(city); + } + } + */ public static String getValue(String fileName, String key) { StringBuilder json = new StringBuilder(); - try { - BufferedReader reader = new BufferedReader(new FileReader(fileName)); + try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) { String line; while ((line = reader.readLine()) != null) { json.append(line.trim()); @@ -39,6 +45,17 @@ public class JsonParser { return jsonString.substring(startIndex, endIndex); } + public static City[][] loadMap(String fileName, String key, List cities) { + String[][] cityMap = parseCountryMap(fileName, key); + City[][] map = new City[cityMap.length][cityMap[0].length]; + + for (City city : cities) { + map[city.getLocation().getX()][city.getLocation().getY()] = city; + } + + return map; + } + public static String[][] parseCountryMap(String fileName, String key) { String mapData = getValue(fileName, key); @@ -55,9 +72,6 @@ public class JsonParser { .map(s -> s.replaceAll("\"", "").trim()) .filter(s -> !s.isEmpty()) .toArray(String[]::new); - for (String city : cities) { - System.out.println(city); - } if (cities.length > 0) matrixList.add(cities); } String[][] result = new String[matrixList.size()][]; @@ -65,13 +79,13 @@ public class JsonParser { result[i] = matrixList.get(i); } - - for (int i = 0; i < result.length; i++) { - for (int j = 0; j < result[i].length; j++) { - System.out.println("result[" + i + "][" + j + "] = " + result[i][j]); - } - } - + /* + for (int i = 0; i < result.length; i++) { + for (int j = 0; j < result[i].length; j++) { + System.out.println("result[" + i + "][" + j + "] = " + result[i][j]); + } + } + */ return result; } @@ -79,7 +93,6 @@ public class JsonParser { List departures = new ArrayList<>(); String departuresJson = getValue(fileName, key); - System.out.println(departuresJson); String res = departuresJson @@ -91,8 +104,6 @@ public class JsonParser { "type:\\s|\\sfrom:\\s|\\sto:\\s|\\sdepartureTime:\\s|\\sduration:\\s|\\sprice:\\s|\\sminTransferTime:\\s", ""); - System.out.println(res); - String[] arr = res.split("\\|"); for (String a : arr) { String[] temp = a.split(","); @@ -105,16 +116,13 @@ public class JsonParser { Integer.parseInt(temp[4]), Double.parseDouble(temp[5]), Integer.parseInt(temp[6]))); - System.out.println(a); } - for (Departure dep : departures) System.out.println(dep); return departures; } public static List parseCities(String fileName, String key) { String cityData = getValue(fileName, key); - System.out.println(cityData); String res = cityData .replaceAll("[\\[\\]]+", "") @@ -130,38 +138,82 @@ public class JsonParser { String[] temp = arr[i].split(","); list.add(temp); } - int i = 0; List temp = new ArrayList<>(); List formatedList = new ArrayList<>(); for (String[] a : list) { temp.clear(); formatedList.clear(); - System.out.println(i); - i++; for (String b : a) { temp.add(b); } for (String item : temp) { item = (item.replaceAll("\\\"[a-zA-Z]+\\\":\\s", "").trim().replaceAll("\\\"", "")); - System.out.println(item); } for (int j = 0; j < temp.size(); j++) { formatedList.add( temp.get(j).replaceAll("\\\"[a-zA-Z]+\\\":\\s", "").trim().replaceAll("\\\"", "")); - System.out.println(formatedList.get(j)); } - cities.add( - new City( - formatedList.get(0), - formatedList.get(1), - formatedList.get(2), - Integer.parseInt(String.valueOf(formatedList.get(0).charAt(2))), - Integer.parseInt(String.valueOf(formatedList.get(0).charAt(4))))); + String[] parts = formatedList.get(0).split("_"); + String name = formatedList.get(0); + String bus = formatedList.get(1); + String train = formatedList.get(2); + int x = Integer.parseInt(parts[1]); + int y = Integer.parseInt(parts[2]); + cities.add(new City(name, bus, train, x, y)); } + return cities; + } + + // Way to slow for big sets of data because it has O(n*m) + public static List loadDeparturesOld(List cities, List departures) { + + for (Departure dep : departures) { + + for (City city : cities) { + + if (dep.getType() == TransportType.BUS) { + if (dep.getFrom().equals(city.getBusStation().getName())) { + city.getBusStation().addDeparture(dep); + } + } else if (dep.getType() == TransportType.TRAIN) { + + if (dep.getFrom().equals(city.getTrainStation().getName())) { + city.getTrainStation().addDeparture(dep); + } + } + } + } + return cities; + } + + public static List loadDepartures(List cities, List departures) { + + Map stationToCityMap = new HashMap(); + for (City city : cities) { - System.out.println(city); + if (city.getBusStation() != null) { + stationToCityMap.put(city.getBusStation().getName(), city); + } + if (city.getBusStation() != null) { + stationToCityMap.put(city.getTrainStation().getName(), city); + } + } + + for (Departure dep : departures) { + City city = stationToCityMap.get(dep.getFrom()); + + if (city != null) { + if (dep.getType() == TransportType.BUS + && city.getBusStation().getName().equals(dep.getFrom())) { + + city.getBusStation().addDeparture(dep); + } else if (dep.getType() == TransportType.TRAIN + && city.getTrainStation().getName().equals(dep.getFrom())) { + city.getTrainStation().addDeparture(dep); + } + } } return cities; } @@ -169,7 +221,6 @@ public class JsonParser { private static int findPair(String str, int startIndex) { char open = str.charAt(startIndex); - System.out.println(open); char closed = (open == '[') ? ']' : '}'; int depth = 0; diff --git a/src/Location.java b/src/Location.java new file mode 100644 index 0000000..8c0b3e6 --- /dev/null +++ b/src/Location.java @@ -0,0 +1,41 @@ +import java.util.Objects; + +public class Location { + + private int x; + private int y; + + public Location(int x, int y) { + this.x = x; + this.y = y; + } + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Location location = (Location) o; + return x == location.x && y == location.y; + } + + @Override + public int hashCode() { + return Objects.hash(x, y); + } +} diff --git a/src/Station.java b/src/Station.java index 95ed8a5..61b8f66 100644 --- a/src/Station.java +++ b/src/Station.java @@ -13,4 +13,24 @@ public class Station { this.type = type; this.name = name; } + + public TransportType getType() { + return type; + } + + public String getName() { + return name; + } + + public List getDepartures() { + return departures; + } + + public void addDeparture(Departure departure) { + departures.add(departure); + } + @Override + public String toString() { + return "Station{" + "type=" + type + ", name=" + name + ", departures=" + departures; + } } diff --git a/src/TransportDataGenerator.java b/src/TransportDataGenerator.java index 651649f..d9ef64c 100644 --- a/src/TransportDataGenerator.java +++ b/src/TransportDataGenerator.java @@ -7,11 +7,11 @@ public class TransportDataGenerator { private int n; private int m; - private static final int DEPARTURES_PER_STATION = 3; + private static final int DEPARTURES_PER_STATION = 1; private static final Random random = new Random(); public static void main(String[] args) { - TransportDataGenerator generator = new TransportDataGenerator(3, 4); + TransportDataGenerator generator = new TransportDataGenerator(2, 2); TransportData data = generator.generateData(); generator.saveToJson(data, "transport_data.json"); System.out.println("Podaci su generisani i sacuvani kao transport_data.json"); diff --git a/src/User.java b/src/User.java new file mode 100644 index 0000000..1bc7e78 --- /dev/null +++ b/src/User.java @@ -0,0 +1,48 @@ +public class User { + private String name; + private int id; + private Location location; + private Location destination; + + private static int idCounter = 1; + // :TODO: + private static final String ID_FILE = "id_counter.txt"; + + public User(String name) { + this.name = name; + this.id = idCounter++; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getId() { + return id; + } + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } + + public Location getDestination() { + return destination; + } + + public void setDestination(Location destination) { + this.destination = destination; + } + + @Override + public String toString() { + return "User{id=" + id + ", name='" + name + "'}"; + } +}