added shortest path finder with dijkstras alg

This commit is contained in:
Ksan 2025-07-24 00:16:59 +02:00
parent 69676c68b1
commit ae113856d0
9 changed files with 332 additions and 61 deletions

View File

@ -1,22 +1,37 @@
import java.util.ArrayList;
import java.util.List;
public class City { public class City {
private String name; private String name;
private Station trainStation; private Station trainStation;
private Station busStation; private Station busStation;
private int row; private Location location;
private int col;
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.name = name;
this.trainStation = new Station(TransportType.TRAIN, train); this.trainStation = new Station(TransportType.TRAIN, train);
this.busStation = new Station(TransportType.BUS, bus); 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.name = name;
this.trainStation = train; this.trainStation = train;
this.busStation = bus; this.busStation = bus;
this.row = row; this.location = new Location(row, col);
this.col = col; }
public List<Departure> getDestinations() {
List<Departure> departures = new ArrayList<>();
for (Departure dep : busStation.getDepartures()) {
departures.add(dep);
}
for (Departure dep : trainStation.getDepartures()) {
departures.add(dep);
}
return departures;
} }
public String getName() { public String getName() {
@ -43,20 +58,8 @@ public class City {
this.busStation = busStation; this.busStation = busStation;
} }
public int getRow() { public Location getLocation() {
return row; return this.location;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
} }
@Override @Override

14
src/CityManager.java Normal file
View File

@ -0,0 +1,14 @@
import java.util.HashMap;
import java.util.Map;
public class CityManager {
private static Map<String, City> cities = new HashMap<>();
public static void addCity(City city) {
cities.put(city.getName(), city);
}
public static City getCityByName(String cityName) {
return cities.get(cityName);
}
}

View File

@ -27,6 +27,11 @@ public class Departure {
this.minTransferTime = minTransferTime; this.minTransferTime = minTransferTime;
} }
public City getDestinationCity() {
return CityManager.getCityByName(to);
}
public TransportType getType() { public TransportType getType() {
return type; return type;
} }
@ -70,6 +75,6 @@ public class Departure {
+ price + price
+ ", minTransferTime=" + ", minTransferTime="
+ minTransferTime + minTransferTime
+ '}'; + "}";
} }
} }

89
src/Graph.java Normal file
View File

@ -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<City> cities = JsonParser.parseCities("transport_data.json", "stations");
List<Departure> 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<Location, Double> result =
graph.calculateShortestPath(cities.getFirst(), cities.get(3), "price");
System.out.println(
cities.getLast().getName() + " = " + result.get(cities.get(3).getLocation()));
}
public Map<Location, Double> calculateShortestPath(City startCity, City endCity, String type) {
int n = matrix.length;
int m = matrix[0].length;
Map<Location, Double> 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<City> 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()];
}
}

View File

@ -2,20 +2,26 @@ import java.io.BufferedReader;
import java.io.FileReader; import java.io.FileReader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
public class JsonParser { public class JsonParser {
/*
public static void main(String[] args) { public static void main(String[] args) {
// String[][] map = JsonParser.parseCountryMap("transport_data.json", "countryMap"); String[][] map = JsonParser.parseCountryMap("transport_data.json", "countryMap");
// JsonParser.parseCities("transport_data.json", "stations"); List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
JsonParser.getDeparturesList("transport_data.json", "departures"); List<Departure> departures = 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) { public static String getValue(String fileName, String key) {
StringBuilder json = new StringBuilder(); StringBuilder json = new StringBuilder();
try { try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
BufferedReader reader = new BufferedReader(new FileReader(fileName));
String line; String line;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
json.append(line.trim()); json.append(line.trim());
@ -39,6 +45,17 @@ public class JsonParser {
return jsonString.substring(startIndex, endIndex); return jsonString.substring(startIndex, endIndex);
} }
public static City[][] loadMap(String fileName, String key, List<City> 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) { public static String[][] parseCountryMap(String fileName, String key) {
String mapData = getValue(fileName, key); String mapData = getValue(fileName, key);
@ -55,9 +72,6 @@ public class JsonParser {
.map(s -> s.replaceAll("\"", "").trim()) .map(s -> s.replaceAll("\"", "").trim())
.filter(s -> !s.isEmpty()) .filter(s -> !s.isEmpty())
.toArray(String[]::new); .toArray(String[]::new);
for (String city : cities) {
System.out.println(city);
}
if (cities.length > 0) matrixList.add(cities); if (cities.length > 0) matrixList.add(cities);
} }
String[][] result = new String[matrixList.size()][]; String[][] result = new String[matrixList.size()][];
@ -65,13 +79,13 @@ public class JsonParser {
result[i] = matrixList.get(i); result[i] = matrixList.get(i);
} }
/*
for (int i = 0; i < result.length; i++) { for (int i = 0; i < result.length; i++) {
for (int j = 0; j < result[i].length; j++) { for (int j = 0; j < result[i].length; j++) {
System.out.println("result[" + i + "][" + j + "] = " + result[i][j]); System.out.println("result[" + i + "][" + j + "] = " + result[i][j]);
} }
} }
*/
return result; return result;
} }
@ -79,7 +93,6 @@ public class JsonParser {
List<Departure> departures = new ArrayList<>(); List<Departure> departures = new ArrayList<>();
String departuresJson = getValue(fileName, key); String departuresJson = getValue(fileName, key);
System.out.println(departuresJson);
String res = String res =
departuresJson departuresJson
@ -91,8 +104,6 @@ public class JsonParser {
"type:\\s|\\sfrom:\\s|\\sto:\\s|\\sdepartureTime:\\s|\\sduration:\\s|\\sprice:\\s|\\sminTransferTime:\\s", "type:\\s|\\sfrom:\\s|\\sto:\\s|\\sdepartureTime:\\s|\\sduration:\\s|\\sprice:\\s|\\sminTransferTime:\\s",
""); "");
System.out.println(res);
String[] arr = res.split("\\|"); String[] arr = res.split("\\|");
for (String a : arr) { for (String a : arr) {
String[] temp = a.split(","); String[] temp = a.split(",");
@ -105,16 +116,13 @@ public class JsonParser {
Integer.parseInt(temp[4]), Integer.parseInt(temp[4]),
Double.parseDouble(temp[5]), Double.parseDouble(temp[5]),
Integer.parseInt(temp[6]))); Integer.parseInt(temp[6])));
System.out.println(a);
} }
for (Departure dep : departures) System.out.println(dep);
return departures; return departures;
} }
public static List<City> parseCities(String fileName, String key) { public static List<City> parseCities(String fileName, String key) {
String cityData = getValue(fileName, key); String cityData = getValue(fileName, key);
System.out.println(cityData);
String res = String res =
cityData cityData
.replaceAll("[\\[\\]]+", "") .replaceAll("[\\[\\]]+", "")
@ -130,38 +138,82 @@ public class JsonParser {
String[] temp = arr[i].split(","); String[] temp = arr[i].split(",");
list.add(temp); list.add(temp);
} }
int i = 0;
List<String> temp = new ArrayList<>(); List<String> temp = new ArrayList<>();
List<String> formatedList = new ArrayList<>(); List<String> formatedList = new ArrayList<>();
for (String[] a : list) { for (String[] a : list) {
temp.clear(); temp.clear();
formatedList.clear(); formatedList.clear();
System.out.println(i);
i++;
for (String b : a) { for (String b : a) {
temp.add(b); temp.add(b);
} }
for (String item : temp) { for (String item : temp) {
item = (item.replaceAll("\\\"[a-zA-Z]+\\\":\\s", "").trim().replaceAll("\\\"", "")); item = (item.replaceAll("\\\"[a-zA-Z]+\\\":\\s", "").trim().replaceAll("\\\"", ""));
System.out.println(item);
} }
for (int j = 0; j < temp.size(); j++) { for (int j = 0; j < temp.size(); j++) {
formatedList.add( formatedList.add(
temp.get(j).replaceAll("\\\"[a-zA-Z]+\\\":\\s", "").trim().replaceAll("\\\"", "")); temp.get(j).replaceAll("\\\"[a-zA-Z]+\\\":\\s", "").trim().replaceAll("\\\"", ""));
System.out.println(formatedList.get(j));
} }
cities.add( String[] parts = formatedList.get(0).split("_");
new City( String name = formatedList.get(0);
formatedList.get(0), String bus = formatedList.get(1);
formatedList.get(1), String train = formatedList.get(2);
formatedList.get(2), int x = Integer.parseInt(parts[1]);
Integer.parseInt(String.valueOf(formatedList.get(0).charAt(2))), int y = Integer.parseInt(parts[2]);
Integer.parseInt(String.valueOf(formatedList.get(0).charAt(4))))); 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<City> loadDeparturesOld(List<City> cities, List<Departure> departures) {
for (Departure dep : departures) {
for (City city : cities) { for (City city : cities) {
System.out.println(city);
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<City> loadDepartures(List<City> cities, List<Departure> departures) {
Map<String, City> stationToCityMap = new HashMap();
for (City city : cities) {
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; return cities;
} }
@ -169,7 +221,6 @@ public class JsonParser {
private static int findPair(String str, int startIndex) { private static int findPair(String str, int startIndex) {
char open = str.charAt(startIndex); char open = str.charAt(startIndex);
System.out.println(open);
char closed = (open == '[') ? ']' : '}'; char closed = (open == '[') ? ']' : '}';
int depth = 0; int depth = 0;

41
src/Location.java Normal file
View File

@ -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);
}
}

View File

@ -13,4 +13,24 @@ public class Station {
this.type = type; this.type = type;
this.name = name; this.name = name;
} }
public TransportType getType() {
return type;
}
public String getName() {
return name;
}
public List<Departure> getDepartures() {
return departures;
}
public void addDeparture(Departure departure) {
departures.add(departure);
}
@Override
public String toString() {
return "Station{" + "type=" + type + ", name=" + name + ", departures=" + departures;
}
} }

View File

@ -7,11 +7,11 @@ public class TransportDataGenerator {
private int n; private int n;
private int m; 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(); private static final Random random = new Random();
public static void main(String[] args) { public static void main(String[] args) {
TransportDataGenerator generator = new TransportDataGenerator(3, 4); TransportDataGenerator generator = new TransportDataGenerator(2, 2);
TransportData data = generator.generateData(); TransportData data = generator.generateData();
generator.saveToJson(data, "transport_data.json"); generator.saveToJson(data, "transport_data.json");
System.out.println("Podaci su generisani i sacuvani kao transport_data.json"); System.out.println("Podaci su generisani i sacuvani kao transport_data.json");

48
src/User.java Normal file
View File

@ -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 + "'}";
}
}