added comments for javadocs
This commit is contained in:
parent
5d39a70e5b
commit
28a07a76e6
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
transport_data.json
|
transport_data.json
|
||||||
ticket_counter.txt
|
ticket_counter.txt
|
||||||
|
docs/
|
||||||
todo
|
todo
|
||||||
receipts/
|
receipts/
|
||||||
target/
|
target/
|
||||||
|
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@ -1,6 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="JavadocGenerationManager">
|
||||||
|
<option name="OUTPUT_DIRECTORY" value="$PROJECT_DIR$/docs" />
|
||||||
|
</component>
|
||||||
<component name="MavenProjectsManager">
|
<component name="MavenProjectsManager">
|
||||||
<option name="originalFiles">
|
<option name="originalFiles">
|
||||||
<list>
|
<list>
|
||||||
|
@ -4,23 +4,53 @@ import java.io.FileWriter;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TransportDataGenerator class is responsible for generating and saving transportation data,
|
||||||
|
* including a map of cities, stations, and departure details (bus and train).
|
||||||
|
* The data is saved in a JSON file format.
|
||||||
|
*
|
||||||
|
* <p>This class can generate transportation data for a grid of cities, each with bus and train stations,
|
||||||
|
* and associated departure schedules. It also allows configuring the number of departures per station.
|
||||||
|
*/
|
||||||
public class TransportDataGenerator {
|
public class TransportDataGenerator {
|
||||||
|
|
||||||
|
// Default grid size
|
||||||
private static final int SIZE = 10;
|
private static final int SIZE = 10;
|
||||||
|
|
||||||
|
// Number of rows and columns in the generated map
|
||||||
private int n;
|
private int n;
|
||||||
private int m;
|
private int m;
|
||||||
|
|
||||||
|
// Default number of departures per station
|
||||||
private static final int DEPARTURES_DEFAULT = 3;
|
private static final int DEPARTURES_DEFAULT = 3;
|
||||||
private static int DEPARTURES_PER_STATION = DEPARTURES_DEFAULT;
|
private static int DEPARTURES_PER_STATION = DEPARTURES_DEFAULT;
|
||||||
|
|
||||||
|
// Random number generator for data generation
|
||||||
private static final Random random = new Random();
|
private static final Random random = new Random();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new transportation map with the default number of departures per station (3).
|
||||||
|
* The generated data is saved to a JSON file.
|
||||||
|
*
|
||||||
|
* @param n the number of rows in the generated grid (map)
|
||||||
|
* @param m the number of columns in the generated grid (map)
|
||||||
|
*/
|
||||||
public static void generateNewMap(int n, int m) {
|
public static void generateNewMap(int n, int m) {
|
||||||
DEPARTURES_PER_STATION= DEPARTURES_DEFAULT;
|
DEPARTURES_PER_STATION = DEPARTURES_DEFAULT;
|
||||||
TransportDataGenerator generator = new TransportDataGenerator(n, m);
|
TransportDataGenerator generator = new TransportDataGenerator(n, m);
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new transportation map with a specified number of departures per station.
|
||||||
|
* The generated data is saved to a JSON file.
|
||||||
|
*
|
||||||
|
* @param n the number of rows in the generated grid (map)
|
||||||
|
* @param m the number of columns in the generated grid (map)
|
||||||
|
* @param departures the number of departures per station
|
||||||
|
*/
|
||||||
public static void generateNewMap(int n, int m, int departures) {
|
public static void generateNewMap(int n, int m, int departures) {
|
||||||
TransportDataGenerator generator = new TransportDataGenerator(n, m);
|
TransportDataGenerator generator = new TransportDataGenerator(n, m);
|
||||||
DEPARTURES_PER_STATION = departures;
|
DEPARTURES_PER_STATION = departures;
|
||||||
@ -28,44 +58,79 @@ public class TransportDataGenerator {
|
|||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor for generating a default grid size (10x10).
|
||||||
|
*/
|
||||||
TransportDataGenerator() {
|
TransportDataGenerator() {
|
||||||
this.n = SIZE;
|
this.n = SIZE;
|
||||||
this.m = SIZE;
|
this.m = SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor to specify grid size as n x n.
|
||||||
|
*
|
||||||
|
* @param n the number of rows and columns in the generated grid (map)
|
||||||
|
*/
|
||||||
TransportDataGenerator(int n) {
|
TransportDataGenerator(int n) {
|
||||||
this.n = n;
|
this.n = n;
|
||||||
this.m = n;
|
this.m = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor to specify both grid size n x m.
|
||||||
|
*
|
||||||
|
* @param n the number of rows in the generated grid (map)
|
||||||
|
* @param m the number of columns in the generated grid (map)
|
||||||
|
*/
|
||||||
TransportDataGenerator(int n, int m) {
|
TransportDataGenerator(int n, int m) {
|
||||||
this.n = n;
|
this.n = n;
|
||||||
this.m = m;
|
this.m = m;
|
||||||
}
|
}
|
||||||
|
|
||||||
// struktura podataka koja sadrzi sve trazene ulazne podatke
|
/**
|
||||||
|
* A data structure that contains all the generated transport data:
|
||||||
|
* - A map of cities
|
||||||
|
* - A list of stations (bus and train stations)
|
||||||
|
* - A list of departure schedules (bus and train)
|
||||||
|
*/
|
||||||
public static class TransportData {
|
public static class TransportData {
|
||||||
public String[][] countryMap;
|
public String[][] countryMap;
|
||||||
public List<Station> stations;
|
public List<Station> stations;
|
||||||
public List<Departure> departures;
|
public List<Departure> departures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a station, which includes the city and the corresponding bus and train stations.
|
||||||
|
*/
|
||||||
public static class Station {
|
public static class Station {
|
||||||
public String city;
|
public String city;
|
||||||
public String busStation;
|
public String busStation;
|
||||||
public String trainStation;
|
public String trainStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a departure (bus or train) including:
|
||||||
|
* - The type of transport (bus or train)
|
||||||
|
* - Departure city and station
|
||||||
|
* - Destination city and station
|
||||||
|
* - Departure time, duration, price, and minimum transfer time
|
||||||
|
*/
|
||||||
public static class Departure {
|
public static class Departure {
|
||||||
public String type; // "autobus" ili "voz"
|
public String type; // "autobus" or "voz"
|
||||||
public String from;
|
public String from;
|
||||||
public String to;
|
public String to;
|
||||||
public String departureTime;
|
public String departureTime;
|
||||||
public int duration; // u minutama
|
public int duration; // in minutes
|
||||||
public int price;
|
public int price;
|
||||||
public int minTransferTime; // vrijeme potrebno za transfer (u minutama)
|
public int minTransferTime; // time needed for transfer (in minutes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the full transportation data, including country map, stations, and departures.
|
||||||
|
*
|
||||||
|
* @return the generated transportation data
|
||||||
|
*/
|
||||||
public TransportData generateData() {
|
public TransportData generateData() {
|
||||||
TransportData data = new TransportData();
|
TransportData data = new TransportData();
|
||||||
data.countryMap = generateCountryMap();
|
data.countryMap = generateCountryMap();
|
||||||
@ -74,7 +139,11 @@ public class TransportDataGenerator {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// generisanje gradova (G_X_Y)
|
/**
|
||||||
|
* Generates the country map as a 2D array of city names in the format "G_X_Y".
|
||||||
|
*
|
||||||
|
* @return the generated country map
|
||||||
|
*/
|
||||||
private String[][] generateCountryMap() {
|
private String[][] generateCountryMap() {
|
||||||
String[][] countryMap = new String[n][m];
|
String[][] countryMap = new String[n][m];
|
||||||
for (int x = 0; x < n; x++) {
|
for (int x = 0; x < n; x++) {
|
||||||
@ -85,7 +154,11 @@ public class TransportDataGenerator {
|
|||||||
return countryMap;
|
return countryMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
// generisanje autobuskih i zeljeznickih stanica
|
/**
|
||||||
|
* Generates the list of stations (bus and train) for each city in the grid.
|
||||||
|
*
|
||||||
|
* @return the list of generated stations
|
||||||
|
*/
|
||||||
private List<Station> generateStations() {
|
private List<Station> generateStations() {
|
||||||
List<Station> stations = new ArrayList<>();
|
List<Station> stations = new ArrayList<>();
|
||||||
for (int x = 0; x < n; x++) {
|
for (int x = 0; x < n; x++) {
|
||||||
@ -100,7 +173,12 @@ public class TransportDataGenerator {
|
|||||||
return stations;
|
return stations;
|
||||||
}
|
}
|
||||||
|
|
||||||
// generisanje vremena polazaka
|
/**
|
||||||
|
* Generates a list of departures (bus and train) for each station.
|
||||||
|
*
|
||||||
|
* @param stations the list of stations to generate departures for
|
||||||
|
* @return the list of generated departures
|
||||||
|
*/
|
||||||
private List<Departure> generateDepartures(List<Station> stations) {
|
private List<Departure> generateDepartures(List<Station> stations) {
|
||||||
List<Departure> departures = new ArrayList<>();
|
List<Departure> departures = new ArrayList<>();
|
||||||
|
|
||||||
@ -108,12 +186,12 @@ public class TransportDataGenerator {
|
|||||||
int x = Integer.parseInt(station.city.split("_")[1]);
|
int x = Integer.parseInt(station.city.split("_")[1]);
|
||||||
int y = Integer.parseInt(station.city.split("_")[2]);
|
int y = Integer.parseInt(station.city.split("_")[2]);
|
||||||
|
|
||||||
// generisanje polazaka autobusa
|
// Generate bus departures
|
||||||
for (int i = 0; i < DEPARTURES_PER_STATION; i++) {
|
for (int i = 0; i < DEPARTURES_PER_STATION; i++) {
|
||||||
departures.add(generateDeparture("autobus", station.busStation, x, y));
|
departures.add(generateDeparture("autobus", station.busStation, x, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
// generisanje polazaka vozova
|
// Generate train departures
|
||||||
for (int i = 0; i < DEPARTURES_PER_STATION; i++) {
|
for (int i = 0; i < DEPARTURES_PER_STATION; i++) {
|
||||||
departures.add(generateDeparture("voz", station.trainStation, x, y));
|
departures.add(generateDeparture("voz", station.trainStation, x, y));
|
||||||
}
|
}
|
||||||
@ -121,31 +199,48 @@ public class TransportDataGenerator {
|
|||||||
return departures;
|
return departures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a single departure (bus or train) with random data.
|
||||||
|
*
|
||||||
|
* @param type the type of transport (bus or train)
|
||||||
|
* @param from the departure station
|
||||||
|
* @param x the city x-coordinate
|
||||||
|
* @param y the city y-coordinate
|
||||||
|
* @return the generated departure
|
||||||
|
*/
|
||||||
private Departure generateDeparture(String type, String from, int x, int y) {
|
private Departure generateDeparture(String type, String from, int x, int y) {
|
||||||
Departure departure = new Departure();
|
Departure departure = new Departure();
|
||||||
departure.type = type;
|
departure.type = type;
|
||||||
departure.from = from;
|
departure.from = from;
|
||||||
|
|
||||||
// generisanje susjeda
|
// Generate neighboring cities
|
||||||
List<String> neighbors = getNeighbors(x, y);
|
List<String> neighbors = getNeighbors(x, y);
|
||||||
departure.to = neighbors.isEmpty() ? from : neighbors.get(random.nextInt(neighbors.size()));
|
departure.to = neighbors.isEmpty() ? from : neighbors.get(random.nextInt(neighbors.size()));
|
||||||
|
|
||||||
// generisanje vremena
|
// Generate departure time
|
||||||
int hour = random.nextInt(24);
|
int hour = random.nextInt(24);
|
||||||
int minute = random.nextInt(4) * 15; // 0, 15, 30, 45
|
int minute = random.nextInt(4) * 15; // 0, 15, 30, 45
|
||||||
departure.departureTime = String.format("%02d:%02d", hour, minute);
|
departure.departureTime = String.format("%02d:%02d", hour, minute);
|
||||||
|
|
||||||
// geneirsanje cijene
|
// Generate duration (in minutes)
|
||||||
departure.duration = 30 + random.nextInt(151);
|
departure.duration = 30 + random.nextInt(151);
|
||||||
|
|
||||||
|
// Generate price (in currency units)
|
||||||
departure.price = 100 + random.nextInt(901);
|
departure.price = 100 + random.nextInt(901);
|
||||||
|
|
||||||
// generisanje vremena transfera
|
// Generate minimum transfer time (in minutes)
|
||||||
departure.minTransferTime = 5 + random.nextInt(26);
|
departure.minTransferTime = 5 + random.nextInt(26);
|
||||||
|
|
||||||
return departure;
|
return departure;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pronalazak susjednih gradova
|
/**
|
||||||
|
* Finds neighboring cities based on the current city coordinates (x, y).
|
||||||
|
*
|
||||||
|
* @param x the current city x-coordinate
|
||||||
|
* @param y the current city y-coordinate
|
||||||
|
* @return the list of neighboring city names
|
||||||
|
*/
|
||||||
private List<String> getNeighbors(int x, int y) {
|
private List<String> getNeighbors(int x, int y) {
|
||||||
List<String> neighbors = new ArrayList<>();
|
List<String> neighbors = new ArrayList<>();
|
||||||
int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
|
int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
|
||||||
@ -160,13 +255,18 @@ public class TransportDataGenerator {
|
|||||||
return neighbors;
|
return neighbors;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cuvanje podataka u JSON mapu
|
/**
|
||||||
|
* Saves the generated transportation data to a JSON file.
|
||||||
|
*
|
||||||
|
* @param data the generated transport data
|
||||||
|
* @param filename the name of the file to save the data to
|
||||||
|
*/
|
||||||
private void saveToJson(TransportData data, String filename) {
|
private void saveToJson(TransportData data, String filename) {
|
||||||
try (FileWriter file = new FileWriter(filename)) {
|
try (FileWriter file = new FileWriter(filename)) {
|
||||||
StringBuilder json = new StringBuilder();
|
StringBuilder json = new StringBuilder();
|
||||||
json.append("{\n");
|
json.append("{\n");
|
||||||
|
|
||||||
// mapa drzave
|
// Add country map
|
||||||
json.append(" \"countryMap\": [\n");
|
json.append(" \"countryMap\": [\n");
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
json.append(" [");
|
json.append(" [");
|
||||||
@ -182,42 +282,42 @@ public class TransportDataGenerator {
|
|||||||
}
|
}
|
||||||
json.append(" ],\n");
|
json.append(" ],\n");
|
||||||
|
|
||||||
// stanice
|
// Add stations
|
||||||
json.append(" \"stations\": [\n");
|
json.append(" \"stations\": [\n");
|
||||||
for (int i = 0; i < data.stations.size(); i++) {
|
for (int i = 0; i < data.stations.size(); i++) {
|
||||||
Station s = data.stations.get(i);
|
Station s = data.stations.get(i);
|
||||||
json.append(" {\"city\": \"")
|
json.append(" {\"city\": \"")
|
||||||
.append(s.city)
|
.append(s.city)
|
||||||
.append("\", \"busStation\": \"")
|
.append("\", \"busStation\": \"")
|
||||||
.append(s.busStation)
|
.append(s.busStation)
|
||||||
.append("\", \"trainStation\": \"")
|
.append("\", \"trainStation\": \"")
|
||||||
.append(s.trainStation)
|
.append(s.trainStation)
|
||||||
.append("\"}");
|
.append("\"}");
|
||||||
if (i < data.stations.size() - 1)
|
if (i < data.stations.size() - 1)
|
||||||
json.append(",");
|
json.append(",");
|
||||||
json.append("\n");
|
json.append("\n");
|
||||||
}
|
}
|
||||||
json.append(" ],\n");
|
json.append(" ],\n");
|
||||||
|
|
||||||
// vremena polazaka
|
// Add departures
|
||||||
json.append(" \"departures\": [\n");
|
json.append(" \"departures\": [\n");
|
||||||
for (int i = 0; i < data.departures.size(); i++) {
|
for (int i = 0; i < data.departures.size(); i++) {
|
||||||
Departure d = data.departures.get(i);
|
Departure d = data.departures.get(i);
|
||||||
json.append(" {\"type\": \"")
|
json.append(" {\"type\": \"")
|
||||||
.append(d.type)
|
.append(d.type)
|
||||||
.append("\", \"from\": \"")
|
.append("\", \"from\": \"")
|
||||||
.append(d.from)
|
.append(d.from)
|
||||||
.append("\", \"to\": \"")
|
.append("\", \"to\": \"")
|
||||||
.append(d.to)
|
.append(d.to)
|
||||||
.append("\", \"departureTime\": \"")
|
.append("\", \"departureTime\": \"")
|
||||||
.append(d.departureTime)
|
.append(d.departureTime)
|
||||||
.append("\", \"duration\": ")
|
.append("\", \"duration\": ")
|
||||||
.append(d.duration)
|
.append(d.duration)
|
||||||
.append(", \"price\": ")
|
.append(", \"price\": ")
|
||||||
.append(d.price)
|
.append(d.price)
|
||||||
.append(", \"minTransferTime\": ")
|
.append(", \"minTransferTime\": ")
|
||||||
.append(d.minTransferTime)
|
.append(d.minTransferTime)
|
||||||
.append("}");
|
.append("}");
|
||||||
if (i < data.departures.size() - 1)
|
if (i < data.departures.size() - 1)
|
||||||
json.append(",");
|
json.append(",");
|
||||||
json.append("\n");
|
json.append("\n");
|
||||||
@ -230,4 +330,4 @@ public class TransportDataGenerator {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,27 +8,54 @@ import javafx.scene.Scene;
|
|||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TravelPathOptimizerApplication class is the entry point for the JavaFX application
|
||||||
|
* that provides a user interface for optimizing travel paths.
|
||||||
|
* It loads the main user interface (FXML) and sets up the application window.
|
||||||
|
*/
|
||||||
public class TravelPathOptimizerApplication extends Application {
|
public class TravelPathOptimizerApplication extends Application {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The start method is called when the application is launched.
|
||||||
|
* It sets up the main window of the application and loads the necessary resources.
|
||||||
|
*
|
||||||
|
* @param stage the primary stage for this application, onto which the scene will be set
|
||||||
|
* @throws IOException if an error occurs during FXML loading or resource fetching
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
|
// Load and initialize the ticket counter (profit and tickets sold)
|
||||||
TicketPrinter.loadCounter();
|
TicketPrinter.loadCounter();
|
||||||
System.out.println(TicketPrinter.getTotalProfit() + " " + TicketPrinter.getTicketsSoldNum());
|
System.out.println(TicketPrinter.getTotalProfit() + " " + TicketPrinter.getTicketsSoldNum());
|
||||||
FXMLLoader fxmlLoader =
|
|
||||||
new FXMLLoader(TravelPathOptimizerApplication.class.getResource("main.fxml"));
|
|
||||||
|
|
||||||
|
// Load the FXML layout for the main interface
|
||||||
|
FXMLLoader fxmlLoader = new FXMLLoader(TravelPathOptimizerApplication.class.getResource("main.fxml"));
|
||||||
|
|
||||||
|
// Load the application's CSS stylesheet
|
||||||
String css = this.getClass().getResource("application.css").toExternalForm();
|
String css = this.getClass().getResource("application.css").toExternalForm();
|
||||||
|
|
||||||
|
// Create the main scene with the loaded FXML layout
|
||||||
Scene scene = new Scene(fxmlLoader.load());
|
Scene scene = new Scene(fxmlLoader.load());
|
||||||
|
|
||||||
|
// Set the application's window icon
|
||||||
Image image = new Image(getClass().getResourceAsStream("/images/img1.jpg"));
|
Image image = new Image(getClass().getResourceAsStream("/images/img1.jpg"));
|
||||||
scene.getStylesheets().add(css);
|
scene.getStylesheets().add(css); // Add the CSS stylesheet to the scene
|
||||||
stage.getIcons().add(image);
|
stage.getIcons().add(image); // Set the application icon
|
||||||
|
|
||||||
|
// Set the window title
|
||||||
stage.setTitle("Hello!");
|
stage.setTitle("Hello!");
|
||||||
|
|
||||||
|
// Set the scene for the stage (window) and show the stage
|
||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.show();
|
stage.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main method serves as the entry point to launch the JavaFX application.
|
||||||
|
* It invokes the launch() method to start the JavaFX runtime.
|
||||||
|
*
|
||||||
|
* @param args the command line arguments
|
||||||
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch();
|
launch();
|
||||||
}
|
}
|
||||||
|
@ -41,26 +41,24 @@ import javafx.stage.FileChooser;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.graphstream.graph.Graph;
|
import org.graphstream.graph.Graph;
|
||||||
import org.graphstream.graph.implementations.MultiGraph;
|
import org.graphstream.graph.implementations.MultiGraph;
|
||||||
|
/**
|
||||||
|
* The MainController class is the controller for the JavaFX application
|
||||||
|
* that handles the transportation system, allowing users to select start
|
||||||
|
* and end cities, view paths, buy tickets, and interact with a grid map of cities.
|
||||||
|
* It handles pathfinding, data loading, graph visualization, and ticket purchasing.
|
||||||
|
*/
|
||||||
public class MainController {
|
public class MainController {
|
||||||
|
|
||||||
|
// UI Elements (FXML)
|
||||||
@FXML private HBox graphPane;
|
@FXML private HBox graphPane;
|
||||||
@FXML private GridPane map;
|
@FXML private GridPane map;
|
||||||
@FXML private Label welcomeText;
|
@FXML private Label welcomeText;
|
||||||
@FXML private Text selectedFileText;
|
@FXML private Text selectedFileText;
|
||||||
@FXML private Button mapSelectButton;
|
@FXML private Button mapSelectButton;
|
||||||
private City startCity = null;
|
|
||||||
private City endCity = null;
|
|
||||||
private boolean selectingStart = false;
|
|
||||||
private boolean selectingEnd = false;
|
|
||||||
@FXML private TextField startCityText;
|
@FXML private TextField startCityText;
|
||||||
@FXML private TextField endCityText;
|
@FXML private TextField endCityText;
|
||||||
@FXML private Button startCityButton;
|
@FXML private Button startCityButton;
|
||||||
@FXML private Button endCityButton;
|
@FXML private Button endCityButton;
|
||||||
private HashMap<Integer, Departure> departuresMap = new HashMap<>();
|
|
||||||
private GraphSimulation graphSimulation;
|
|
||||||
private City[][] cities;
|
|
||||||
private File selectedFile;
|
|
||||||
@FXML private Button openFileButton;
|
@FXML private Button openFileButton;
|
||||||
@FXML private TextField nTextField;
|
@FXML private TextField nTextField;
|
||||||
@FXML private TextField mTextField;
|
@FXML private TextField mTextField;
|
||||||
@ -69,8 +67,6 @@ public class MainController {
|
|||||||
@FXML private VBox mapSideBar;
|
@FXML private VBox mapSideBar;
|
||||||
@FXML private ChoiceBox categoryBox;
|
@FXML private ChoiceBox categoryBox;
|
||||||
@FXML private Button startButton;
|
@FXML private Button startButton;
|
||||||
|
|
||||||
// routeView
|
|
||||||
@FXML private HBox routeView;
|
@FXML private HBox routeView;
|
||||||
@FXML private Text totalTicketPriceText;
|
@FXML private Text totalTicketPriceText;
|
||||||
@FXML private Button buyButton;
|
@FXML private Button buyButton;
|
||||||
@ -81,10 +77,23 @@ public class MainController {
|
|||||||
@FXML private TableColumn<Departure, Double> tabCostCol;
|
@FXML private TableColumn<Departure, Double> tabCostCol;
|
||||||
@FXML private ChoiceBox<String> pathChoiceBox;
|
@FXML private ChoiceBox<String> pathChoiceBox;
|
||||||
|
|
||||||
|
// Private instance variables
|
||||||
|
private City startCity = null;
|
||||||
|
private City endCity = null;
|
||||||
|
private boolean selectingStart = false;
|
||||||
|
private boolean selectingEnd = false;
|
||||||
|
private HashMap<Integer, Departure> departuresMap = new HashMap<>();
|
||||||
|
private GraphSimulation graphSimulation;
|
||||||
|
private City[][] cities;
|
||||||
|
private File selectedFile;
|
||||||
private Graph graph = new MultiGraph("map");
|
private Graph graph = new MultiGraph("map");
|
||||||
private GraphVisualizer visualizer;
|
private GraphVisualizer visualizer;
|
||||||
private List<Departure> tempDepartureList = new ArrayList<>();
|
private List<Departure> tempDepartureList = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the visibility of the map and graph pane. If the map is visible, it hides the map
|
||||||
|
* and shows the graph pane, and vice versa. The method also adds the city nodes to the graph.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
void showGraph() {
|
void showGraph() {
|
||||||
graph.clear();
|
graph.clear();
|
||||||
@ -154,7 +163,10 @@ public class MainController {
|
|||||||
visualizer.showGraph();
|
visualizer.showGraph();
|
||||||
visualizer.highlightPath(tempDepartureList);
|
visualizer.highlightPath(tempDepartureList);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Initiates the ticket purchasing process by generating a ticket receipt based on the selected
|
||||||
|
* departures and the total cost. The receipt is printed using the TicketPrinter.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void buyTicket() {
|
private void buyTicket() {
|
||||||
|
|
||||||
@ -162,7 +174,11 @@ public class MainController {
|
|||||||
printer.generateTicketReceipt(
|
printer.generateTicketReceipt(
|
||||||
updateUiGetList(), Double.parseDouble(totalTicketPriceText.getText()));
|
updateUiGetList(), Double.parseDouble(totalTicketPriceText.getText()));
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Calculates and displays the top paths between the selected start and end cities based on the
|
||||||
|
* selected category (time, price, or hops). This method is run in a background task to avoid
|
||||||
|
* blocking the UI. Once the paths are calculated, they are displayed in the UI.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void findTopPaths() {
|
private void findTopPaths() {
|
||||||
graphSimulation.reset();
|
graphSimulation.reset();
|
||||||
@ -236,7 +252,13 @@ public class MainController {
|
|||||||
|
|
||||||
new Thread(task).start();
|
new Thread(task).start();
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Updates the UI with the selected list of departures based on the current path selection.
|
||||||
|
* It updates the route details, including departure times, arrival times, and prices, and
|
||||||
|
* calculates the total ticket price.
|
||||||
|
*
|
||||||
|
* @return An observable list of departures.
|
||||||
|
*/
|
||||||
private synchronized ObservableList<Departure> updateUiGetList() {
|
private synchronized ObservableList<Departure> updateUiGetList() {
|
||||||
|
|
||||||
ObservableList<Departure> departureList = FXCollections.observableArrayList();
|
ObservableList<Departure> departureList = FXCollections.observableArrayList();
|
||||||
@ -283,28 +305,37 @@ public class MainController {
|
|||||||
protected void onHelloButtonClick() {
|
protected void onHelloButtonClick() {
|
||||||
welcomeText.setText("Welcome to JavaFX Application!");
|
welcomeText.setText("Welcome to JavaFX Application!");
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Toggles the visibility of the "Route View" section, which shows the available paths and their details.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void showRouteView() {
|
private void showRouteView() {
|
||||||
boolean visible = routeView.isVisible();
|
boolean visible = routeView.isVisible();
|
||||||
routeView.setVisible(!visible);
|
routeView.setVisible(!visible);
|
||||||
routeView.setManaged(!visible);
|
routeView.setManaged(!visible);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Toggles the visibility of the random sidebar, tbh forgot this part.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
void showRandomSideBar() {
|
void showRandomSideBar() {
|
||||||
boolean visible = randomSideBar.isVisible();
|
boolean visible = randomSideBar.isVisible();
|
||||||
randomSideBar.setVisible(!visible);
|
randomSideBar.setVisible(!visible);
|
||||||
randomSideBar.setManaged(!visible);
|
randomSideBar.setManaged(!visible);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Toggles the visibility of the map sidebar, which contains options for selecting a map or file.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
void showMapSideBar() {
|
void showMapSideBar() {
|
||||||
boolean visible = mapSideBar.isVisible();
|
boolean visible = mapSideBar.isVisible();
|
||||||
mapSideBar.setVisible(!visible);
|
mapSideBar.setVisible(!visible);
|
||||||
mapSideBar.setManaged(!visible);
|
mapSideBar.setManaged(!visible);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Updates the map layout by re-generating the grid cells based on the current city locations.
|
||||||
|
* This method also updates the appearance of the grid to highlight the selected start and end cities.
|
||||||
|
*/
|
||||||
private void updateMap() {
|
private void updateMap() {
|
||||||
map.getChildren().clear();
|
map.getChildren().clear();
|
||||||
map.getRowConstraints().clear();
|
map.getRowConstraints().clear();
|
||||||
@ -378,21 +409,30 @@ public class MainController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Sets the start city for the pathfinding. The user can select a city from the map grid to
|
||||||
|
* set it as the start city.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void selectStart() {
|
private void selectStart() {
|
||||||
this.selectingEnd = false;
|
this.selectingEnd = false;
|
||||||
this.selectingStart = true;
|
this.selectingStart = true;
|
||||||
updateMap();
|
updateMap();
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Sets the end city for the pathfinding. The user can select a city from the map grid to
|
||||||
|
* set it as the end city.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
private void selectEnd() {
|
private void selectEnd() {
|
||||||
this.selectingStart = false;
|
this.selectingStart = false;
|
||||||
this.selectingEnd = true;
|
this.selectingEnd = true;
|
||||||
updateMap();
|
updateMap();
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Initializes the controller by setting up the UI components, event listeners, and default values.
|
||||||
|
* This method is called after the FXML file is loaded.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
visualizer = new GraphVisualizer(graph, graphPane);
|
visualizer = new GraphVisualizer(graph, graphPane);
|
||||||
@ -506,7 +546,13 @@ public class MainController {
|
|||||||
updateMap(); // Re-draw with highlight if matched
|
updateMap(); // Re-draw with highlight if matched
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Calculates the total cost for the list of selected departures. The total cost is the sum of
|
||||||
|
* the prices of all selected departures.
|
||||||
|
*
|
||||||
|
* @param depList The list of selected departures.
|
||||||
|
* @return The total cost of the selected departures.
|
||||||
|
*/
|
||||||
private double calculateTotalCost(ObservableList<Departure> depList) {
|
private double calculateTotalCost(ObservableList<Departure> depList) {
|
||||||
double totalCost = 0.0;
|
double totalCost = 0.0;
|
||||||
for (Departure dep : depList) {
|
for (Departure dep : depList) {
|
||||||
@ -514,7 +560,10 @@ public class MainController {
|
|||||||
}
|
}
|
||||||
return totalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Generates a new map based on user input for the number of rows, columns, and departures.
|
||||||
|
* If the departure field is empty, it generates a map with default number of departures.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
void generateNewMap() {
|
void generateNewMap() {
|
||||||
if (!nTextField.getText().isEmpty() && !mTextField.getText().isEmpty()) {
|
if (!nTextField.getText().isEmpty() && !mTextField.getText().isEmpty()) {
|
||||||
@ -532,7 +581,10 @@ public class MainController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Loads the transportation data from a JSON file, parses the cities, departures, and map grid,
|
||||||
|
* and updates the internal data structures with the loaded information.
|
||||||
|
*/
|
||||||
private void getData() {
|
private void getData() {
|
||||||
CityManager.clear();
|
CityManager.clear();
|
||||||
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
|
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
|
||||||
@ -557,7 +609,10 @@ public class MainController {
|
|||||||
|
|
||||||
this.graphSimulation = new GraphSimulation(map);
|
this.graphSimulation = new GraphSimulation(map);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Opens a file chooser dialog to allow the user to select a map file (in JSON format).
|
||||||
|
* Once the file is selected, it loads the data and updates the map display.
|
||||||
|
*/
|
||||||
@FXML
|
@FXML
|
||||||
void loadMapFromFile() {
|
void loadMapFromFile() {
|
||||||
FileChooser fileChooser = new FileChooser();
|
FileChooser fileChooser = new FileChooser();
|
||||||
|
@ -9,81 +9,34 @@ import java.time.Duration;
|
|||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates pathfinding in a transportation network, managing paths between cities
|
||||||
|
* and calculating top paths based on different cost metrics (e.g., time, price, hops).
|
||||||
|
*/
|
||||||
public class GraphSimulation {
|
public class GraphSimulation {
|
||||||
|
|
||||||
private City[][] matrix;
|
private City[][] matrix;
|
||||||
private List<PathResult> allPaths = new ArrayList<>();
|
private List<PathResult> allPaths = new ArrayList<>();
|
||||||
private int pathIdCounter = 1;
|
private int pathIdCounter = 1;
|
||||||
private static int nextid = 0;
|
private static int nextid = 0;
|
||||||
private static Set<String> visitedRoutes = new HashSet<>();
|
private static Set<String> visitedRoutes = new HashSet<>();
|
||||||
public static PriorityQueue<PathResult> topPaths =
|
public static PriorityQueue<PathResult> topPaths =
|
||||||
new PriorityQueue<>(5, Comparator.comparingDouble(PathResult::getCost).reversed());
|
new PriorityQueue<>(5, Comparator.comparingDouble(PathResult::getCost).reversed());
|
||||||
/*
|
|
||||||
public static void main(String[] args) {
|
|
||||||
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
|
|
||||||
List<Departure> departures = JsonParser.getDeparturesList("transport_data.json", "departures");
|
|
||||||
for (Departure dep : departures) {
|
|
||||||
for (City city : cities) {
|
|
||||||
if (dep.getTo().equals(city.getName())) {
|
|
||||||
dep.setToCity(city);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cities = JsonParser.loadDepartures(cities, departures);
|
|
||||||
City[][] map = JsonParser.loadMap("transport_data.json", "countryMap", cities);
|
|
||||||
|
|
||||||
GraphSimulation graphSimulation = new GraphSimulation(map);
|
/**
|
||||||
cities = JsonParser.loadDepartures(cities, departures);
|
* Gets the list of top 5 paths sorted by cost in ascending order.
|
||||||
for (City city : cities) {
|
*
|
||||||
CityManager.addCity(city);
|
* @return a list of the top 5 path results sorted by cost.
|
||||||
}
|
*/
|
||||||
|
|
||||||
System.out.println(cities.getFirst().getName() + " do " + cities.getLast().getName());
|
|
||||||
Map<Location, Double> result =
|
|
||||||
graphSimulation.calculateShortestPath(cities.getFirst(), cities.getLast(), "time");
|
|
||||||
System.out.println(
|
|
||||||
cities.get(1).getName() + " = " + result.get(cities.getLast().getLocation()));
|
|
||||||
|
|
||||||
/*
|
|
||||||
graph.calculateTopPaths(cities.getFirst(), cities.getLast());
|
|
||||||
|
|
||||||
List<PathResult> sorted = new ArrayList<>(graph.topPaths);
|
|
||||||
sorted.sort(Comparator.comparingDouble(PathResult::getCost));
|
|
||||||
for (PathResult res : sorted) {
|
|
||||||
System.out.println("Path ID: " + res.getId());
|
|
||||||
System.out.print("Cities: ");
|
|
||||||
for (City city : res.getPath()) {
|
|
||||||
System.out.print(city.getName() + " → ");
|
|
||||||
}
|
|
||||||
System.out.println("End");
|
|
||||||
|
|
||||||
System.out.println("Departures:");
|
|
||||||
|
|
||||||
|
|
||||||
System.out.println("Total Cost: " + res.getCost() + " min");
|
|
||||||
System.out.println("Arrival Time: " + res.getArrivalTime());
|
|
||||||
System.out.println("--------------------------------------------------");
|
|
||||||
}
|
|
||||||
|
|
||||||
*\/
|
|
||||||
|
|
||||||
List<City> path = new ArrayList<>();
|
|
||||||
List<Integer> departuress = new ArrayList<>();
|
|
||||||
LocalTime currentTime = LocalTime.of(1, 0);
|
|
||||||
double totalCost = 0.0;
|
|
||||||
|
|
||||||
calculateTopPaths(
|
|
||||||
cities.getFirst(), cities.getLast(), path, totalCost, currentTime, departuress, "time");
|
|
||||||
System.out.println(topPaths.size());
|
|
||||||
// Output the top 5 paths
|
|
||||||
printTopPaths();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public List<PathResult> getSortedPaths() {
|
public List<PathResult> getSortedPaths() {
|
||||||
List<PathResult> pathList = new ArrayList<>(topPaths);
|
List<PathResult> pathList = new ArrayList<>(topPaths);
|
||||||
pathList.sort(Comparator.comparingDouble(PathResult::getCost));
|
pathList.sort(Comparator.comparingDouble(PathResult::getCost));
|
||||||
return pathList;
|
return pathList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the simulation, clearing all paths, visited routes, and top paths.
|
||||||
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
topPaths.clear();
|
topPaths.clear();
|
||||||
pathIdCounter = 1;
|
pathIdCounter = 1;
|
||||||
@ -92,6 +45,12 @@ public class GraphSimulation {
|
|||||||
visitedRoutes.clear();
|
visitedRoutes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new path result to the top paths if it has a lower cost than the current top paths.
|
||||||
|
* Ensures that no duplicate routes are added.
|
||||||
|
*
|
||||||
|
* @param newPath the new path result to be added.
|
||||||
|
*/
|
||||||
public static void addToTopPaths(PathResult newPath) {
|
public static void addToTopPaths(PathResult newPath) {
|
||||||
String routeHash = generateRouteHash(newPath.getDeparturesUsed());
|
String routeHash = generateRouteHash(newPath.getDeparturesUsed());
|
||||||
|
|
||||||
@ -112,6 +71,12 @@ public class GraphSimulation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a unique hash for a route based on the departure IDs used in the path.
|
||||||
|
*
|
||||||
|
* @param departures the list of departure IDs used in the path.
|
||||||
|
* @return a string hash representing the route.
|
||||||
|
*/
|
||||||
private static String generateRouteHash(List<Integer> departures) {
|
private static String generateRouteHash(List<Integer> departures) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (Integer depId : departures) {
|
for (Integer depId : departures) {
|
||||||
@ -120,24 +85,35 @@ public class GraphSimulation {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively calculates the top paths from a starting city to an ending city, considering
|
||||||
|
* the type of cost metric (e.g., time, price, or hops).
|
||||||
|
*
|
||||||
|
* @param currentCity the city where the journey is currently at.
|
||||||
|
* @param endCity the destination city of the journey.
|
||||||
|
* @param path the list of cities visited so far.
|
||||||
|
* @param totalCost the total cost accumulated up to the current city.
|
||||||
|
* @param currentTime the current time at the city.
|
||||||
|
* @param departures the list of departure IDs taken so far.
|
||||||
|
* @param type the type of cost metric to use ("time", "price", or "hops").
|
||||||
|
*/
|
||||||
public static void calculateTopPaths(
|
public static void calculateTopPaths(
|
||||||
City currentCity,
|
City currentCity,
|
||||||
City endCity,
|
City endCity,
|
||||||
List<City> path,
|
List<City> path,
|
||||||
double totalCost,
|
double totalCost,
|
||||||
LocalTime currentTime,
|
LocalTime currentTime,
|
||||||
List<Integer> departures,
|
List<Integer> departures,
|
||||||
String type) {
|
String type) {
|
||||||
|
|
||||||
if (currentCity.getLocation().equals(endCity.getLocation())) {
|
if (currentCity.getLocation().equals(endCity.getLocation())) {
|
||||||
|
|
||||||
addToTopPaths(
|
addToTopPaths(
|
||||||
new PathResult(
|
new PathResult(
|
||||||
nextid++,
|
nextid++,
|
||||||
new ArrayList<>(path),
|
new ArrayList<>(path),
|
||||||
new ArrayList<>(departures),
|
new ArrayList<>(departures),
|
||||||
totalCost,
|
totalCost,
|
||||||
currentTime));
|
currentTime));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +131,6 @@ public class GraphSimulation {
|
|||||||
duration = duration.abs();
|
duration = duration.abs();
|
||||||
|
|
||||||
if (type.equals("time")) {
|
if (type.equals("time")) {
|
||||||
// cost += dep.getDuration();
|
|
||||||
cost += duration.toMinutes();
|
cost += duration.toMinutes();
|
||||||
cost += dep.getMinTransferTime();
|
cost += dep.getMinTransferTime();
|
||||||
} else if (type.equals("price")) {
|
} else if (type.equals("price")) {
|
||||||
@ -177,12 +152,14 @@ public class GraphSimulation {
|
|||||||
departures.remove(departures.size() - 1);
|
departures.remove(departures.size() - 1);
|
||||||
path.remove(path.size() - 1);
|
path.remove(path.size() - 1);
|
||||||
if (type.equals("hops")) {
|
if (type.equals("hops")) {
|
||||||
|
|
||||||
cost--;
|
cost--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the top 5 paths to the console.
|
||||||
|
*/
|
||||||
public static void printTopPaths() {
|
public static void printTopPaths() {
|
||||||
if (topPaths.isEmpty()) {
|
if (topPaths.isEmpty()) {
|
||||||
System.out.println("No Paths");
|
System.out.println("No Paths");
|
||||||
@ -201,137 +178,14 @@ public class GraphSimulation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
private PriorityQueue<PathResult> topPaths =
|
* Calculates the shortest path between two cities using a specified cost metric (e.g., price, time, hops).
|
||||||
new PriorityQueue<>(Comparator.comparingDouble(PathResult::getCost).reversed());
|
*
|
||||||
private final AtomicInteger pathIdGenerator = new AtomicInteger(1); // Start from 1
|
* @param startCity the starting city of the path.
|
||||||
private final Set<String> uniquePathKeys = new HashSet<>();
|
* @param endCity the destination city of the path.
|
||||||
|
* @param type the type of cost metric to use ("price", "time", or "hops").
|
||||||
private int makeDeparturePathHash(Set<Departure> departures) {
|
* @return a map where the keys are city locations and the values are the shortest cost to that location.
|
||||||
return departures.stream()
|
*/
|
||||||
.mapToInt(
|
|
||||||
dep ->
|
|
||||||
Objects.hash(
|
|
||||||
dep.getDepartureTime()
|
|
||||||
.toSecondOfDay(),
|
|
||||||
dep.getDestinationCity()
|
|
||||||
.getLocation(),
|
|
||||||
Double.valueOf(dep.getDuration()).hashCode()))
|
|
||||||
.sorted()
|
|
||||||
.reduce(1, (a, b) -> 31 * a + b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private HashSet<Integer> uniquePathHashes = new HashSet<Integer>();
|
|
||||||
public void calculateTopPaths(City start, City end) {
|
|
||||||
topPaths.clear();
|
|
||||||
uniquePathKeys.clear();
|
|
||||||
pathIdGenerator.set(1);
|
|
||||||
|
|
||||||
for (Departure dep : start.getDestinations()) {
|
|
||||||
City next = dep.getDestinationCity();
|
|
||||||
double duration = dep.getDuration();
|
|
||||||
LocalTime depTime = dep.getDepartureTime();
|
|
||||||
LocalTime arrivalTime = depTime.plusMinutes((long) duration);
|
|
||||||
|
|
||||||
List<City> initialPath = new ArrayList<>();
|
|
||||||
Set<Departure> usedDepartures = new HashSet<>();
|
|
||||||
usedDepartures.add(dep);
|
|
||||||
|
|
||||||
initialPath.add(start);
|
|
||||||
initialPath.add(next);
|
|
||||||
List<Integer> initialDepartures = new ArrayList<>();
|
|
||||||
initialDepartures.add(dep.getIdCounter());
|
|
||||||
Set<Location> visited = new HashSet<>();
|
|
||||||
visited.add(start.getLocation());
|
|
||||||
|
|
||||||
findPaths(
|
|
||||||
next,
|
|
||||||
end,
|
|
||||||
initialPath,
|
|
||||||
usedDepartures,
|
|
||||||
initialDepartures,
|
|
||||||
duration,
|
|
||||||
arrivalTime,
|
|
||||||
visited);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void findPaths(
|
|
||||||
City current,
|
|
||||||
City end,
|
|
||||||
List<City> pathSoFar,
|
|
||||||
Set<Departure> usedDepartures,
|
|
||||||
List<Integer> departuresSoFar,
|
|
||||||
double totalCost,
|
|
||||||
LocalTime currentTime,
|
|
||||||
Set<Location> visitedCities
|
|
||||||
) {
|
|
||||||
if (visitedCities.contains(current.getLocation())) return;
|
|
||||||
|
|
||||||
visitedCities.add(current.getLocation());
|
|
||||||
|
|
||||||
if (current.getLocation().equals(end.getLocation())) {
|
|
||||||
int pathHash = makeDeparturePathHash(usedDepartures);
|
|
||||||
if (uniquePathHashes.contains(pathHash)) {
|
|
||||||
visitedCities.remove(current.getLocation());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uniquePathHashes.add(pathHash);
|
|
||||||
int pathId = pathIdGenerator.getAndIncrement();
|
|
||||||
topPaths.add(
|
|
||||||
new PathResult(
|
|
||||||
pathId,
|
|
||||||
new ArrayList<>(pathSoFar),
|
|
||||||
new ArrayList<>(departuresSoFar),
|
|
||||||
totalCost,
|
|
||||||
currentTime));
|
|
||||||
|
|
||||||
if (topPaths.size() > 5) topPaths.poll();
|
|
||||||
|
|
||||||
visitedCities.remove(current.getLocation()); // backtrack
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Departure dep : current.getDestinations()) {
|
|
||||||
if (usedDepartures.contains(dep)) continue;
|
|
||||||
if (dep.getDepartureTime().isBefore(currentTime)) continue;
|
|
||||||
|
|
||||||
City next = dep.getDestinationCity();
|
|
||||||
if (visitedCities.contains(next.getLocation())) continue; // skip if already visited
|
|
||||||
|
|
||||||
LocalTime arrivalTime = dep.getDepartureTime().plusMinutes((long) dep.getDuration());
|
|
||||||
|
|
||||||
usedDepartures.add(dep);
|
|
||||||
departuresSoFar.add(dep.getIdCounter());
|
|
||||||
pathSoFar.add(next);
|
|
||||||
if (!(topPaths.peek() == null)) {
|
|
||||||
if (totalCost + dep.getDuration() > topPaths.peek().getCost()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
findPaths(
|
|
||||||
next,
|
|
||||||
end,
|
|
||||||
pathSoFar,
|
|
||||||
usedDepartures,
|
|
||||||
departuresSoFar,
|
|
||||||
totalCost + dep.getDuration(),
|
|
||||||
arrivalTime,
|
|
||||||
visitedCities);
|
|
||||||
|
|
||||||
// backtrack
|
|
||||||
pathSoFar.remove(pathSoFar.size() - 1);
|
|
||||||
departuresSoFar.remove(departuresSoFar.size() - 1);
|
|
||||||
usedDepartures.remove(dep);
|
|
||||||
}
|
|
||||||
|
|
||||||
visitedCities.remove(current.getLocation()); // backtrack
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public Map<Location, Double> calculateShortestPath(City startCity, City endCity, String type) {
|
public Map<Location, Double> calculateShortestPath(City startCity, City endCity, String type) {
|
||||||
int n = matrix.length;
|
int n = matrix.length;
|
||||||
int m = matrix[0].length;
|
int m = matrix[0].length;
|
||||||
@ -346,7 +200,7 @@ public class GraphSimulation {
|
|||||||
distances.put(startCity.getLocation(), 0.0);
|
distances.put(startCity.getLocation(), 0.0);
|
||||||
|
|
||||||
PriorityQueue<City> pq =
|
PriorityQueue<City> pq =
|
||||||
new PriorityQueue<>(Comparator.comparingDouble(city -> distances.get(city.getLocation())));
|
new PriorityQueue<>(Comparator.comparingDouble(city -> distances.get(city.getLocation())));
|
||||||
pq.add(startCity);
|
pq.add(startCity);
|
||||||
|
|
||||||
while (!pq.isEmpty()) {
|
while (!pq.isEmpty()) {
|
||||||
@ -380,27 +234,58 @@ public class GraphSimulation {
|
|||||||
return distances;
|
return distances;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of all paths found during the simulation.
|
||||||
|
*
|
||||||
|
* @return a list of all PathResult objects representing the paths.
|
||||||
|
*/
|
||||||
public List<PathResult> getAllPaths() {
|
public List<PathResult> getAllPaths() {
|
||||||
return allPaths;
|
return allPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a GraphSimulation object with the given matrix of cities.
|
||||||
|
*
|
||||||
|
* @param matrix a 2D array representing the map of cities.
|
||||||
|
*/
|
||||||
public GraphSimulation(City[][] matrix) {
|
public GraphSimulation(City[][] matrix) {
|
||||||
this.matrix = matrix;
|
this.matrix = matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the city matrix used in the simulation.
|
||||||
|
*
|
||||||
|
* @param matrix the new 2D array of cities.
|
||||||
|
*/
|
||||||
public void updateMatrix(City[][] matrix) {
|
public void updateMatrix(City[][] matrix) {
|
||||||
this.matrix = matrix;
|
this.matrix = matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current matrix of cities used in the simulation.
|
||||||
|
*
|
||||||
|
* @return the current 2D array of cities.
|
||||||
|
*/
|
||||||
public City[][] getMatrix() {
|
public City[][] getMatrix() {
|
||||||
return matrix;
|
return matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the city at a specific location in the matrix.
|
||||||
|
*
|
||||||
|
* @param loc the location of the city.
|
||||||
|
* @return the city at the specified location.
|
||||||
|
*/
|
||||||
public City getCity(Location loc) {
|
public City getCity(Location loc) {
|
||||||
return matrix[loc.getX()][loc.getY()];
|
return matrix[loc.getX()][loc.getY()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the priority queue of top paths, sorted by cost in descending order.
|
||||||
|
*
|
||||||
|
* @return the priority queue of top paths.
|
||||||
|
*/
|
||||||
public static PriorityQueue<PathResult> getTopPaths() {
|
public static PriorityQueue<PathResult> getTopPaths() {
|
||||||
return topPaths;
|
return topPaths;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,13 +6,28 @@ import java.time.LocalTime;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the result of a path calculation, including the path (list of cities),
|
||||||
|
* departures used, total cost, and arrival time for the journey.
|
||||||
|
*/
|
||||||
public class PathResult {
|
public class PathResult {
|
||||||
private int id;
|
|
||||||
|
private int id;
|
||||||
private List<City> path = new ArrayList<>();
|
private List<City> path = new ArrayList<>();
|
||||||
private List<Integer> departuresUsed = new ArrayList<>();
|
private List<Integer> departuresUsed = new ArrayList<>();
|
||||||
private double cost;
|
private double cost;
|
||||||
private LocalTime arrivalTime;
|
private LocalTime arrivalTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a PathResult object with the specified id, path, departures, cost,
|
||||||
|
* and arrival time.
|
||||||
|
*
|
||||||
|
* @param id the unique identifier for the path result
|
||||||
|
* @param path the list of cities in the path
|
||||||
|
* @param departuresUsed the list of departures used in the path
|
||||||
|
* @param cost the total cost of the journey
|
||||||
|
* @param arrivalTime the time of arrival at the destination
|
||||||
|
*/
|
||||||
public PathResult(int id, List<City> path, List<Integer> departuresUsed, double cost, LocalTime arrivalTime) {
|
public PathResult(int id, List<City> path, List<Integer> departuresUsed, double cost, LocalTime arrivalTime) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
@ -21,25 +36,57 @@ public class PathResult {
|
|||||||
this.arrivalTime = arrivalTime;
|
this.arrivalTime = arrivalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the unique identifier for the path result.
|
||||||
|
*
|
||||||
|
* @return the unique identifier of the path result.
|
||||||
|
*/
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of cities in the path.
|
||||||
|
*
|
||||||
|
* @return a list of City objects representing the journey's path.
|
||||||
|
*/
|
||||||
public List<City> getPath() {
|
public List<City> getPath() {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of departures used during the journey.
|
||||||
|
*
|
||||||
|
* @return a list of integers representing the departure IDs used.
|
||||||
|
*/
|
||||||
public List<Integer> getDeparturesUsed() {
|
public List<Integer> getDeparturesUsed() {
|
||||||
return departuresUsed;
|
return departuresUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the total cost of the journey represented by this path result.
|
||||||
|
*
|
||||||
|
* @return the total cost of the journey.
|
||||||
|
*/
|
||||||
public double getCost() {
|
public double getCost() {
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the arrival time at the destination.
|
||||||
|
*
|
||||||
|
* @return a LocalTime object representing the arrival time.
|
||||||
|
*/
|
||||||
public LocalTime getArrivalTime() {
|
public LocalTime getArrivalTime() {
|
||||||
return arrivalTime;
|
return arrivalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the PathResult object, including the id,
|
||||||
|
* total cost, path, and arrival time.
|
||||||
|
*
|
||||||
|
* @return a string representation of the PathResult object.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PathResult{id=" + id + " cost = " + cost + ", path=" + path + ", arrivalTime=" + arrivalTime + '}';
|
return "PathResult{id=" + id + " cost = " + cost + ", path=" + path + ", arrivalTime=" + arrivalTime + '}';
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.graphSimulation;
|
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.model.City;
|
|
||||||
import dev.ksan.travelpathoptimizer.model.Departure;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class PathState {
|
|
||||||
private City city;
|
|
||||||
private List<City> path;
|
|
||||||
private List<Departure> departures;
|
|
||||||
double cost;
|
|
||||||
|
|
||||||
public PathState(City city, List<City> path, List<Departure> departures, double cost) {
|
|
||||||
this.city = city;
|
|
||||||
this.path = path;
|
|
||||||
this.departures = departures;
|
|
||||||
this.cost = cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPathSignature() {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (int i = 0; i < path.size(); i++) {
|
|
||||||
sb.append(path.get(i).getLocation().toString());
|
|
||||||
if (i < path.size() - 1) {
|
|
||||||
sb.append("->");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public City getCity() {
|
|
||||||
return city;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCity(City city) {
|
|
||||||
this.city = city;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<City> getPath() {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPath(List<City> path) {
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Departure> getDepartures() {
|
|
||||||
return departures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDepartures(List<Departure> departures) {
|
|
||||||
this.departures = departures;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getCost() {
|
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCost(double cost) {
|
|
||||||
this.cost = cost;
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,12 +3,27 @@ package dev.ksan.travelpathoptimizer.model;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a city with associated transportation stations (train and bus)
|
||||||
|
* and its location.
|
||||||
|
*/
|
||||||
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 Location location;
|
private Location location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a City object with a specified name, bus station, train station,
|
||||||
|
* and location.
|
||||||
|
*
|
||||||
|
* @param name the name of the city
|
||||||
|
* @param bus the name of the bus station
|
||||||
|
* @param train the name of the train station
|
||||||
|
* @param row the row coordinate for the city's location
|
||||||
|
* @param col the column coordinate for the city's location
|
||||||
|
*/
|
||||||
public City(String name, String bus, String train, int row, int col) {
|
public 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);
|
||||||
@ -16,6 +31,16 @@ public class City {
|
|||||||
this.location = new Location(row, col);
|
this.location = new Location(row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a City object with a specified name, pre-existing bus and train stations,
|
||||||
|
* and location.
|
||||||
|
*
|
||||||
|
* @param name the name of the city
|
||||||
|
* @param bus the bus station object
|
||||||
|
* @param train the train station object
|
||||||
|
* @param row the row coordinate for the city's location
|
||||||
|
* @param col the column coordinate for the city's location
|
||||||
|
*/
|
||||||
public City(String name, Station bus, Station train, int row, int col) {
|
public City(String name, Station bus, Station train, int row, int col) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.trainStation = train;
|
this.trainStation = train;
|
||||||
@ -23,6 +48,12 @@ public class City {
|
|||||||
this.location = new Location(row, col);
|
this.location = new Location(row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of all departures (destinations) from both the bus and train stations
|
||||||
|
* in this city.
|
||||||
|
*
|
||||||
|
* @return a list of Departure objects representing the destinations from this city.
|
||||||
|
*/
|
||||||
public List<Departure> getDestinations() {
|
public List<Departure> getDestinations() {
|
||||||
List<Departure> departures = new ArrayList<>();
|
List<Departure> departures = new ArrayList<>();
|
||||||
|
|
||||||
@ -36,34 +67,75 @@ public class City {
|
|||||||
return departures;
|
return departures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of the city.
|
||||||
|
*
|
||||||
|
* @return the name of the city.
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of the city.
|
||||||
|
*
|
||||||
|
* @param name the name to set for the city.
|
||||||
|
*/
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the train station of the city.
|
||||||
|
*
|
||||||
|
* @return the train station of the city.
|
||||||
|
*/
|
||||||
public Station getTrainStation() {
|
public Station getTrainStation() {
|
||||||
return trainStation;
|
return trainStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the train station for the city.
|
||||||
|
*
|
||||||
|
* @param trainStation the Station object to set as the city's train station.
|
||||||
|
*/
|
||||||
public void setTrainStation(Station trainStation) {
|
public void setTrainStation(Station trainStation) {
|
||||||
this.trainStation = trainStation;
|
this.trainStation = trainStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the bus station of the city.
|
||||||
|
*
|
||||||
|
* @return the bus station of the city.
|
||||||
|
*/
|
||||||
public Station getBusStation() {
|
public Station getBusStation() {
|
||||||
return busStation;
|
return busStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the bus station for the city.
|
||||||
|
*
|
||||||
|
* @param busStation the Station object to set as the city's bus station.
|
||||||
|
*/
|
||||||
public void setBusStation(Station busStation) {
|
public void setBusStation(Station busStation) {
|
||||||
this.busStation = busStation;
|
this.busStation = busStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the geographic location of the city.
|
||||||
|
*
|
||||||
|
* @return the Location object representing the city's location.
|
||||||
|
*/
|
||||||
public Location getLocation() {
|
public Location getLocation() {
|
||||||
return this.location;
|
return this.location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the City object, including the city's name,
|
||||||
|
* and details of the train and bus stations.
|
||||||
|
*
|
||||||
|
* @return a string representation of the city.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return name + "\n\tTrain Station: " + trainStation + "\n\tBus Station: " + busStation;
|
return name + "\n\tTrain Station: " + trainStation + "\n\tBus Station: " + busStation;
|
||||||
|
@ -18,13 +18,13 @@ public class Departure {
|
|||||||
private static int idCounter = 0;
|
private static int idCounter = 0;
|
||||||
private int id;
|
private int id;
|
||||||
public Departure(
|
public Departure(
|
||||||
TransportType type,
|
TransportType type,
|
||||||
String from,
|
String from,
|
||||||
String to,
|
String to,
|
||||||
String departureTime,
|
String departureTime,
|
||||||
int duration,
|
int duration,
|
||||||
double price,
|
double price,
|
||||||
int minTransferTime) {
|
int minTransferTime) {
|
||||||
this.id = idCounter++;
|
this.id = idCounter++;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.from = from;
|
this.from = from;
|
||||||
@ -80,22 +80,22 @@ public class Departure {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Departure{"
|
return "Departure{"
|
||||||
+ "type="
|
+ "type="
|
||||||
+ type
|
+ type
|
||||||
+ ", from='"
|
+ ", from='"
|
||||||
+ from
|
+ from
|
||||||
+ '\''
|
+ '\''
|
||||||
+ ", to='"
|
+ ", to='"
|
||||||
+ to
|
+ to
|
||||||
+ '\''
|
+ '\''
|
||||||
+ ", departureTime="
|
+ ", departureTime="
|
||||||
+ departureTime.format(DateTimeFormatter.ofPattern("HH:mm"))
|
+ departureTime.format(DateTimeFormatter.ofPattern("HH:mm"))
|
||||||
+ ", duration="
|
+ ", duration="
|
||||||
+ duration
|
+ duration
|
||||||
+ ", price="
|
+ ", price="
|
||||||
+ price
|
+ price
|
||||||
+ ", minTransferTime="
|
+ ", minTransferTime="
|
||||||
+ minTransferTime
|
+ minTransferTime
|
||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,32 +2,71 @@ package dev.ksan.travelpathoptimizer.model;
|
|||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a 2D location, defined by its x and y coordinates.
|
||||||
|
* Used to specify positions on a grid or map.
|
||||||
|
*/
|
||||||
public class Location {
|
public class Location {
|
||||||
|
|
||||||
private int x;
|
private int x;
|
||||||
private int y;
|
private int y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Location object with the specified x and y coordinates.
|
||||||
|
*
|
||||||
|
* @param x the x-coordinate of the location
|
||||||
|
* @param y the y-coordinate of the location
|
||||||
|
*/
|
||||||
public Location(int x, int y) {
|
public Location(int x, int y) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the x-coordinate of this location.
|
||||||
|
*
|
||||||
|
* @return the x-coordinate
|
||||||
|
*/
|
||||||
public int getX() {
|
public int getX() {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the x-coordinate of this location.
|
||||||
|
*
|
||||||
|
* @param x the new x-coordinate
|
||||||
|
*/
|
||||||
public void setX(int x) {
|
public void setX(int x) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the y-coordinate of this location.
|
||||||
|
*
|
||||||
|
* @return the y-coordinate
|
||||||
|
*/
|
||||||
public int getY() {
|
public int getY() {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the y-coordinate of this location.
|
||||||
|
*
|
||||||
|
* @param y the new y-coordinate
|
||||||
|
*/
|
||||||
public void setY(int y) {
|
public void setY(int y) {
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares this location to another object for equality.
|
||||||
|
* Two locations are considered equal if their x and y coordinates are the same.
|
||||||
|
*
|
||||||
|
* @param o the object to compare this location to
|
||||||
|
* @return true if the object is a Location and has the same x and y coordinates, false otherwise
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
@ -36,11 +75,22 @@ public class Location {
|
|||||||
return x == location.x && y == location.y;
|
return x == location.x && y == location.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a hash code value for this location.
|
||||||
|
* The hash code is computed based on the x and y coordinates.
|
||||||
|
*
|
||||||
|
* @return a hash code value for this location
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(x, y);
|
return Objects.hash(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of the location in the format "x_y".
|
||||||
|
*
|
||||||
|
* @return a string representation of the location
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return x + "_" + y;
|
return x + "_" + y;
|
||||||
|
@ -3,36 +3,77 @@ package dev.ksan.travelpathoptimizer.model;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a station, which can be of a specific transport type (e.g., bus, train),
|
||||||
|
* and contains a list of departures for that station.
|
||||||
|
*/
|
||||||
public class Station {
|
public class Station {
|
||||||
|
|
||||||
private TransportType type = TransportType.NOT_ASSIGNED;
|
private TransportType type = TransportType.NOT_ASSIGNED;
|
||||||
private String name;
|
private String name;
|
||||||
private List<Departure> departures = new ArrayList<Departure>();
|
private List<Departure> departures = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor for a Station object. The transport type is set to NOT_ASSIGNED,
|
||||||
|
* and the departures list is initialized as empty.
|
||||||
|
*/
|
||||||
Station() {}
|
Station() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a Station object with the specified transport type and station name.
|
||||||
|
*
|
||||||
|
* @param type the type of transport (e.g., train, bus)
|
||||||
|
* @param name the name of the station
|
||||||
|
*/
|
||||||
Station(TransportType type, String name) {
|
Station(TransportType type, String name) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the transport type of this station (e.g., train, bus).
|
||||||
|
*
|
||||||
|
* @return the transport type of the station
|
||||||
|
*/
|
||||||
public TransportType getType() {
|
public TransportType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the name of this station.
|
||||||
|
*
|
||||||
|
* @return the name of the station
|
||||||
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of departures from this station.
|
||||||
|
*
|
||||||
|
* @return a list of Departure objects associated with this station
|
||||||
|
*/
|
||||||
public List<Departure> getDepartures() {
|
public List<Departure> getDepartures() {
|
||||||
return departures;
|
return departures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a departure to the list of departures for this station.
|
||||||
|
*
|
||||||
|
* @param departure the departure to add to the list
|
||||||
|
*/
|
||||||
public void addDeparture(Departure departure) {
|
public void addDeparture(Departure departure) {
|
||||||
departures.add(departure);
|
departures.add(departure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a string representation of this station, including its transport type, name, and departures.
|
||||||
|
*
|
||||||
|
* @return a string representation of the station
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Station{" + "type=" + type + ", name=" + name + ", departures=" + departures;
|
return "Station{" + "type=" + type + ", name=" + name + ", departures=" + departures + "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,43 @@
|
|||||||
package dev.ksan.travelpathoptimizer.model;
|
package dev.ksan.travelpathoptimizer.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum representing different types of transport, such as BUS, TRAIN, and a default NOT_ASSIGNED type.
|
||||||
|
* Each transport type is associated with a string representation.
|
||||||
|
*/
|
||||||
public enum TransportType {
|
public enum TransportType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an unassigned transport type. This is used as a placeholder.
|
||||||
|
*/
|
||||||
NOT_ASSIGNED("null"),
|
NOT_ASSIGNED("null"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a bus transport type.
|
||||||
|
*/
|
||||||
BUS("autobus"),
|
BUS("autobus"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a train transport type.
|
||||||
|
*/
|
||||||
TRAIN("voz");
|
TRAIN("voz");
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a TransportType with the specified string representation.
|
||||||
|
*
|
||||||
|
* @param type the string representation of the transport type
|
||||||
|
*/
|
||||||
TransportType(String type) {
|
TransportType(String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation of the transport type.
|
||||||
|
* This is the string value that corresponds to the transport type (e.g., "autobus", "voz").
|
||||||
|
*
|
||||||
|
* @return the string representation of the transport type
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.type;
|
return this.type;
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.model;
|
|
||||||
|
|
||||||
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 + "'}";
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,25 +5,53 @@ import dev.ksan.travelpathoptimizer.model.Location;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class CityManager {
|
|
||||||
private static Map<String, City> cities = new HashMap<>();
|
|
||||||
private static Map<Location, City> citiesByLocation = new HashMap<>();
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The CityManager class manages a collection of cities in a travel optimization system.
|
||||||
|
* It allows adding cities, retrieving cities by name or location, and clearing the city data.
|
||||||
|
*/
|
||||||
|
public class CityManager {
|
||||||
|
|
||||||
|
private static Map<String, City> cities = new HashMap<>(); // Map to store cities by name
|
||||||
|
private static Map<Location, City> citiesByLocation = new HashMap<>(); // Map to store cities by location
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all stored cities from the manager.
|
||||||
|
* This method will remove all cities from both the name-based and location-based maps.
|
||||||
|
*/
|
||||||
public static void clear() {
|
public static void clear() {
|
||||||
citiesByLocation.clear();
|
citiesByLocation.clear();
|
||||||
cities.clear();
|
cities.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a city to the city manager.
|
||||||
|
* The city will be stored in both the name-based and location-based maps.
|
||||||
|
*
|
||||||
|
* @param city the city to be added
|
||||||
|
*/
|
||||||
public static void addCity(City city) {
|
public static void addCity(City city) {
|
||||||
cities.put(city.getName(), city);
|
cities.put(city.getName(), city); // Add city by name
|
||||||
citiesByLocation.put(city.getLocation(), city);
|
citiesByLocation.put(city.getLocation(), city); // Add city by location
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a city by its location.
|
||||||
|
*
|
||||||
|
* @param loc the location of the city
|
||||||
|
* @return the city associated with the given location, or null if no city exists at that location
|
||||||
|
*/
|
||||||
public static City getCityByLocation(Location loc) {
|
public static City getCityByLocation(Location loc) {
|
||||||
return citiesByLocation.get(loc);
|
return citiesByLocation.get(loc); // Get city by location
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a city by its name.
|
||||||
|
*
|
||||||
|
* @param cityName the name of the city
|
||||||
|
* @return the city associated with the given name, or null if no city exists with that name
|
||||||
|
*/
|
||||||
public static City getCityByName(String cityName) {
|
public static City getCityByName(String cityName) {
|
||||||
return cities.get(cityName);
|
return cities.get(cityName); // Get city by name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,19 +12,20 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class for parsing JSON-like data from files and converting them into Java objects.
|
||||||
|
* This class is used to extract information from JSON files related to cities, departures, and transport maps.
|
||||||
|
*/
|
||||||
public class JsonParser {
|
public class JsonParser {
|
||||||
/*
|
|
||||||
public static void main(String[] args) {
|
|
||||||
String[][] map = JsonParser.parseCountryMap("transport_data.json", "countryMap");
|
|
||||||
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
|
|
||||||
List<Departure> departures = JsonParser.getDeparturesList("transport_data.json", "departures");
|
|
||||||
|
|
||||||
cities = JsonParser.loadDepartures(cities, departures);
|
/**
|
||||||
for (City city : cities) {
|
* Retrieves the value associated with a given key from a JSON-like file.
|
||||||
System.out.println(city);
|
* The value is expected to be an array, and the function extracts the array's content as a string.
|
||||||
}
|
*
|
||||||
}
|
* @param fileName the name of the file containing the JSON data
|
||||||
*/
|
* @param key the key to search for in the JSON data
|
||||||
|
* @return the string value associated with the key, or {@code null} if the key is not found
|
||||||
|
*/
|
||||||
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 (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
|
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
|
||||||
@ -51,6 +52,14 @@ public class JsonParser {
|
|||||||
return jsonString.substring(startIndex, endIndex);
|
return jsonString.substring(startIndex, endIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a map of cities from a JSON file, associating cities with their respective locations on the map.
|
||||||
|
*
|
||||||
|
* @param fileName the name of the file containing the city map data
|
||||||
|
* @param key the key used to identify the map data in the JSON file
|
||||||
|
* @param cities a list of cities to be mapped to their respective locations
|
||||||
|
* @return a 2D array representing the map of cities
|
||||||
|
*/
|
||||||
public static City[][] loadMap(String fileName, String key, List<City> cities) {
|
public static City[][] loadMap(String fileName, String key, List<City> cities) {
|
||||||
String[][] cityMap = parseCountryMap(fileName, key);
|
String[][] cityMap = parseCountryMap(fileName, key);
|
||||||
City[][] map = new City[cityMap.length][cityMap[0].length];
|
City[][] map = new City[cityMap.length][cityMap[0].length];
|
||||||
@ -62,6 +71,13 @@ public class JsonParser {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a country map from a JSON file and converts it into a 2D array of strings.
|
||||||
|
*
|
||||||
|
* @param fileName the name of the file containing the map data
|
||||||
|
* @param key the key used to identify the map data in the JSON file
|
||||||
|
* @return a 2D array representing the country 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);
|
||||||
@ -74,67 +90,75 @@ public class JsonParser {
|
|||||||
for (String row : rows) {
|
for (String row : rows) {
|
||||||
if (row.trim().isEmpty()) continue;
|
if (row.trim().isEmpty()) continue;
|
||||||
String[] cities =
|
String[] cities =
|
||||||
Arrays.stream(row.split(","))
|
Arrays.stream(row.split(","))
|
||||||
.map(s -> s.replaceAll("\"", "").trim())
|
.map(s -> s.replaceAll("\"", "").trim())
|
||||||
.filter(s -> !s.isEmpty())
|
.filter(s -> !s.isEmpty())
|
||||||
.toArray(String[]::new);
|
.toArray(String[]::new);
|
||||||
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()][];
|
||||||
for (int i = 0; i < matrixList.size(); i++) {
|
for (int i = 0; i < matrixList.size(); i++) {
|
||||||
|
|
||||||
result[i] = matrixList.get(i);
|
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a list of departures from a JSON file based on the given key.
|
||||||
|
* Each departure is converted into a {@link Departure} object.
|
||||||
|
*
|
||||||
|
* @param fileName the name of the file containing the departure data
|
||||||
|
* @param key the key used to identify the departure data in the JSON file
|
||||||
|
* @return a list of {@link Departure} objects
|
||||||
|
*/
|
||||||
public static List<Departure> getDeparturesList(String fileName, String key) {
|
public static List<Departure> getDeparturesList(String fileName, String key) {
|
||||||
List<Departure> departures = new ArrayList<>();
|
List<Departure> departures = new ArrayList<>();
|
||||||
|
|
||||||
String departuresJson = getValue(fileName, key);
|
String departuresJson = getValue(fileName, key);
|
||||||
|
|
||||||
String res =
|
String res =
|
||||||
departuresJson
|
departuresJson
|
||||||
.replaceAll("[\\{\\[\\]]", "")
|
.replaceAll("[\\{\\[\\]]", "")
|
||||||
.replaceAll("\\},", "\\|")
|
.replaceAll("\\},", "\\|")
|
||||||
.replaceAll("\\}", "")
|
.replaceAll("\\}", "")
|
||||||
.replaceAll("\\\"", "")
|
.replaceAll("\\\"", "")
|
||||||
.replaceAll(
|
.replaceAll(
|
||||||
"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",
|
||||||
"");
|
"");
|
||||||
|
|
||||||
String[] arr = res.split("\\|");
|
String[] arr = res.split("\\|");
|
||||||
for (String a : arr) {
|
for (String a : arr) {
|
||||||
String[] temp = a.split(",");
|
String[] temp = a.split(",");
|
||||||
departures.add(
|
departures.add(
|
||||||
new Departure(
|
new Departure(
|
||||||
parseTransportType(temp[0]),
|
parseTransportType(temp[0]),
|
||||||
temp[1],
|
temp[1],
|
||||||
temp[2],
|
temp[2],
|
||||||
temp[3],
|
temp[3],
|
||||||
Integer.parseInt(temp[4]),
|
Integer.parseInt(temp[4]),
|
||||||
Double.parseDouble(temp[5]),
|
Double.parseDouble(temp[5]),
|
||||||
Integer.parseInt(temp[6])));
|
Integer.parseInt(temp[6])));
|
||||||
}
|
}
|
||||||
|
|
||||||
return departures;
|
return departures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the list of cities from a JSON file and returns a list of {@link City} objects.
|
||||||
|
*
|
||||||
|
* @param fileName the name of the file containing the city data
|
||||||
|
* @param key the key used to identify the city data in the JSON file
|
||||||
|
* @return a list of {@link City} objects
|
||||||
|
*/
|
||||||
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);
|
||||||
String res =
|
String res =
|
||||||
cityData
|
cityData
|
||||||
.replaceAll("[\\[\\]]+", "")
|
.replaceAll("[\\[\\]]+", "")
|
||||||
.replaceAll("\\},\\{", "\n")
|
.replaceAll("\\},\\{", "\n")
|
||||||
.replaceAll("[\\{\\}]", "")
|
.replaceAll("[\\{\\}]", "")
|
||||||
.replaceAll("\\n", "|");
|
.replaceAll("\\n", "|");
|
||||||
|
|
||||||
String[] arr = res.split("\\|");
|
String[] arr = res.split("\\|");
|
||||||
|
|
||||||
@ -158,7 +182,7 @@ public class JsonParser {
|
|||||||
|
|
||||||
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("\\\"", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] parts = formatedList.get(0).split("_");
|
String[] parts = formatedList.get(0).split("_");
|
||||||
@ -172,28 +196,14 @@ public class JsonParser {
|
|||||||
return cities;
|
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) {
|
* Loads departure data into the corresponding cities' stations.
|
||||||
|
* This method maps departures to their respective bus or train stations in the city.
|
||||||
for (Departure dep : departures) {
|
*
|
||||||
|
* @param cities a list of {@link City} objects
|
||||||
for (City city : cities) {
|
* @param departures a list of {@link Departure} objects
|
||||||
|
* @return the list of cities with departures loaded into their respective stations
|
||||||
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) {
|
public static List<City> loadDepartures(List<City> cities, List<Departure> departures) {
|
||||||
|
|
||||||
Map<String, City> stationToCityMap = new HashMap();
|
Map<String, City> stationToCityMap = new HashMap();
|
||||||
@ -212,11 +222,11 @@ public class JsonParser {
|
|||||||
|
|
||||||
if (city != null) {
|
if (city != null) {
|
||||||
if (dep.getType() == TransportType.BUS
|
if (dep.getType() == TransportType.BUS
|
||||||
&& city.getBusStation().getName().equals(dep.getFrom())) {
|
&& city.getBusStation().getName().equals(dep.getFrom())) {
|
||||||
|
|
||||||
city.getBusStation().addDeparture(dep);
|
city.getBusStation().addDeparture(dep);
|
||||||
} else if (dep.getType() == TransportType.TRAIN
|
} else if (dep.getType() == TransportType.TRAIN
|
||||||
&& city.getTrainStation().getName().equals(dep.getFrom())) {
|
&& city.getTrainStation().getName().equals(dep.getFrom())) {
|
||||||
city.getTrainStation().addDeparture(dep);
|
city.getTrainStation().addDeparture(dep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,6 +234,13 @@ public class JsonParser {
|
|||||||
return cities;
|
return cities;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the closing pair for an open bracket or brace in a JSON-like string.
|
||||||
|
*
|
||||||
|
* @param str the string to search
|
||||||
|
* @param startIndex the index where the search starts
|
||||||
|
* @return the index of the closing pair, or -1 if no pair is found
|
||||||
|
*/
|
||||||
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);
|
||||||
@ -244,6 +261,12 @@ public class JsonParser {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a transport type from a string value.
|
||||||
|
*
|
||||||
|
* @param str the string representing the transport type
|
||||||
|
* @return the corresponding {@link TransportType}, or {@link TransportType#NOT_ASSIGNED} if the type is unknown
|
||||||
|
*/
|
||||||
public static TransportType parseTransportType(String str) {
|
public static TransportType parseTransportType(String str) {
|
||||||
for (TransportType t : TransportType.values()) {
|
for (TransportType t : TransportType.values()) {
|
||||||
if (t.toString().equalsIgnoreCase(str)) {
|
if (t.toString().equalsIgnoreCase(str)) {
|
||||||
@ -252,4 +275,4 @@ public class JsonParser {
|
|||||||
}
|
}
|
||||||
return TransportType.NOT_ASSIGNED;
|
return TransportType.NOT_ASSIGNED;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,12 +7,28 @@ import java.nio.file.Paths;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TicketPrinter {
|
import java.io.*;
|
||||||
private static final String COUNTER_FILE = "ticket_counter.txt";
|
import java.nio.file.*;
|
||||||
private static final String RECEIPTS_DIRECTORY = "receipts";
|
import java.time.LocalDate;
|
||||||
private static double totalProfit = 0.0;
|
import java.util.List;
|
||||||
private static int ticketIdCounter = 0;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility class for generating and managing ticket receipts. This class handles the creation of ticket receipts,
|
||||||
|
* saving them to a file, and keeping track of ticket sales and profits. The receipts are saved in a specified
|
||||||
|
* directory, and a counter is used to generate unique ticket IDs.
|
||||||
|
*/
|
||||||
|
public class TicketPrinter {
|
||||||
|
private static final String COUNTER_FILE = "ticket_counter.txt"; // File to save the ticket ID counter and total profit
|
||||||
|
private static final String RECEIPTS_DIRECTORY = "receipts"; // Directory where receipts will be saved
|
||||||
|
private static double totalProfit = 0.0; // Total profit from ticket sales
|
||||||
|
private static int ticketIdCounter = 0; // Counter for ticket IDs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a receipt for the given departures and total price, and saves it to a file.
|
||||||
|
*
|
||||||
|
* @param departures the list of departures for the ticket
|
||||||
|
* @param totalPrice the total price of the ticket
|
||||||
|
*/
|
||||||
public static void generateTicketReceipt(List<Departure> departures, double totalPrice) {
|
public static void generateTicketReceipt(List<Departure> departures, double totalPrice) {
|
||||||
LocalDate currentDate = LocalDate.now();
|
LocalDate currentDate = LocalDate.now();
|
||||||
|
|
||||||
@ -24,22 +40,21 @@ public class TicketPrinter {
|
|||||||
receipt.append("=====================================================\n");
|
receipt.append("=====================================================\n");
|
||||||
|
|
||||||
receipt.append("Ticket ID: ").append(getNextId()).append("\n");
|
receipt.append("Ticket ID: ").append(getNextId()).append("\n");
|
||||||
|
|
||||||
receipt.append("Date: ").append(currentDate).append("\n");
|
receipt.append("Date: ").append(currentDate).append("\n");
|
||||||
receipt.append("From: ").append(departures.getFirst().getFrom()).append("\n");
|
receipt.append("From: ").append(departures.get(0).getFrom()).append("\n");
|
||||||
receipt.append("To: ").append(departures.getLast().getTo()).append("\n");
|
receipt.append("To: ").append(departures.get(departures.size() - 1).getTo()).append("\n");
|
||||||
receipt.append("-----------------------------------------------------\n");
|
receipt.append("-----------------------------------------------------\n");
|
||||||
|
|
||||||
receipt.append("Departure Prices:\n");
|
receipt.append("Departure Prices:\n");
|
||||||
for (Departure dep : departures) {
|
for (Departure dep : departures) {
|
||||||
receipt
|
receipt
|
||||||
.append(" - ")
|
.append(" - ")
|
||||||
.append(dep.getFrom())
|
.append(dep.getFrom())
|
||||||
.append(" -> ")
|
.append(" -> ")
|
||||||
.append(dep.getTo())
|
.append(dep.getTo())
|
||||||
.append(" | Price: $")
|
.append(" | Price: $")
|
||||||
.append(String.format("%.2f", dep.getPrice()))
|
.append(String.format("%.2f", dep.getPrice()))
|
||||||
.append("\n");
|
.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
receipt.append("-----------------------------------------------------\n");
|
receipt.append("-----------------------------------------------------\n");
|
||||||
@ -52,6 +67,12 @@ public class TicketPrinter {
|
|||||||
writeReceipt(receipt.toString());
|
writeReceipt(receipt.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the generated receipt to a file.
|
||||||
|
* The file is saved in the `receipts` directory with a unique ticket ID.
|
||||||
|
*
|
||||||
|
* @param receipt the receipt content to be written to the file
|
||||||
|
*/
|
||||||
private static void writeReceipt(String receipt) {
|
private static void writeReceipt(String receipt) {
|
||||||
Path receiptFile = Paths.get(RECEIPTS_DIRECTORY, "receipt_" + ticketIdCounter + ".txt");
|
Path receiptFile = Paths.get(RECEIPTS_DIRECTORY, "receipt_" + ticketIdCounter + ".txt");
|
||||||
try {
|
try {
|
||||||
@ -62,6 +83,9 @@ public class TicketPrinter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the receipts directory exists. If not, it creates the directory.
|
||||||
|
*/
|
||||||
private static void folderExists() {
|
private static void folderExists() {
|
||||||
Path path = Paths.get(RECEIPTS_DIRECTORY);
|
Path path = Paths.get(RECEIPTS_DIRECTORY);
|
||||||
|
|
||||||
@ -74,6 +98,10 @@ public class TicketPrinter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the ticket ID counter and total profit from a file. If the file doesn't exist or there is an error,
|
||||||
|
* it resets the values to 0.
|
||||||
|
*/
|
||||||
public static void loadCounter() {
|
public static void loadCounter() {
|
||||||
try {
|
try {
|
||||||
Path path = Paths.get(COUNTER_FILE);
|
Path path = Paths.get(COUNTER_FILE);
|
||||||
@ -99,24 +127,41 @@ public class TicketPrinter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total profit accumulated from ticket sales.
|
||||||
|
*
|
||||||
|
* @return the total profit
|
||||||
|
*/
|
||||||
public static double getTotalProfit() {
|
public static double getTotalProfit() {
|
||||||
return totalProfit;
|
return totalProfit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total number of tickets sold (based on the ticket ID counter).
|
||||||
|
*
|
||||||
|
* @return the number of tickets sold
|
||||||
|
*/
|
||||||
public static int getTicketsSoldNum() {
|
public static int getTicketsSoldNum() {
|
||||||
return ticketIdCounter;
|
return ticketIdCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the current ticket ID counter and total profit to a file, so they can be persisted for future use.
|
||||||
|
*/
|
||||||
private static void saveCounter() {
|
private static void saveCounter() {
|
||||||
try {
|
try {
|
||||||
String str = "ticketIdCounter=" + ticketIdCounter + "\n" + "totalProfit=" + totalProfit;
|
String str = "ticketIdCounter=" + ticketIdCounter + "\n" + "totalProfit=" + totalProfit;
|
||||||
Files.write(Paths.get(COUNTER_FILE), str.getBytes());
|
Files.write(Paths.get(COUNTER_FILE), str.getBytes());
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the next available ticket ID by incrementing the current ticket ID counter.
|
||||||
|
*
|
||||||
|
* @return the next ticket ID
|
||||||
|
*/
|
||||||
private static int getNextId() {
|
private static int getNextId() {
|
||||||
return ++ticketIdCounter;
|
return ++ticketIdCounter;
|
||||||
}
|
}
|
||||||
|
@ -12,36 +12,69 @@ import org.graphstream.ui.fx_viewer.FxDefaultView;
|
|||||||
import org.graphstream.ui.fx_viewer.FxViewer;
|
import org.graphstream.ui.fx_viewer.FxViewer;
|
||||||
import org.graphstream.ui.view.Viewer;
|
import org.graphstream.ui.view.Viewer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GraphVisualizer class is responsible for visualizing a graph structure in a JavaFX HBox container.
|
||||||
|
* It allows the graph to be displayed with a custom stylesheet and also provides functionality
|
||||||
|
* to highlight a specific path of departures.
|
||||||
|
*/
|
||||||
public class GraphVisualizer {
|
public class GraphVisualizer {
|
||||||
|
|
||||||
|
// The file path to the CSS file that styles the graph visualization
|
||||||
static File cssFile = new File("src/main/resources/dev/ksan/travelpathoptimizer/app/graph.css");
|
static File cssFile = new File("src/main/resources/dev/ksan/travelpathoptimizer/app/graph.css");
|
||||||
|
|
||||||
|
// The graph to be visualized
|
||||||
private Graph graph;
|
private Graph graph;
|
||||||
|
|
||||||
|
// The HBox container in which the graph view will be displayed
|
||||||
private HBox container;
|
private HBox container;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a GraphVisualizer with the specified graph and container.
|
||||||
|
*
|
||||||
|
* @param graph the graph to be visualized
|
||||||
|
* @param container the HBox container in which to display the graph
|
||||||
|
*/
|
||||||
public GraphVisualizer(Graph graph, HBox container) {
|
public GraphVisualizer(Graph graph, HBox container) {
|
||||||
this.graph = graph;
|
this.graph = graph;
|
||||||
this.container = container;
|
this.container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the graph in the provided container.
|
||||||
|
* Applies a custom stylesheet and labels each node with its ID.
|
||||||
|
* Initializes a viewer to render the graph using JavaFX.
|
||||||
|
*/
|
||||||
public void showGraph() {
|
public void showGraph() {
|
||||||
|
// Set the stylesheet for the graph visualization
|
||||||
graph.setAttribute("ui.stylesheet", "url('" + cssFile + "')");
|
graph.setAttribute("ui.stylesheet", "url('" + cssFile + "')");
|
||||||
|
|
||||||
|
// Label each node with its ID
|
||||||
for (Node node : graph) {
|
for (Node node : graph) {
|
||||||
node.setAttribute("ui.label", node.getId());
|
node.setAttribute("ui.label", node.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a viewer and enable auto-layout for the graph
|
||||||
Viewer viewer = new FxViewer(graph, FxViewer.ThreadingModel.GRAPH_IN_GUI_THREAD);
|
Viewer viewer = new FxViewer(graph, FxViewer.ThreadingModel.GRAPH_IN_GUI_THREAD);
|
||||||
viewer.enableAutoLayout();
|
viewer.enableAutoLayout();
|
||||||
|
|
||||||
|
// Add a default view to the viewer and add it to the container
|
||||||
FxDefaultView view = (FxDefaultView) viewer.addDefaultView(false);
|
FxDefaultView view = (FxDefaultView) viewer.addDefaultView(false);
|
||||||
|
|
||||||
container.getChildren().clear();
|
container.getChildren().clear();
|
||||||
|
|
||||||
container.getChildren().add(view);
|
container.getChildren().add(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlights a specific path of departures in the graph.
|
||||||
|
* It highlights the nodes and edges corresponding to the specified departures.
|
||||||
|
*
|
||||||
|
* @param departures the list of departures representing the path to be highlighted
|
||||||
|
*/
|
||||||
public synchronized void highlightPath(List<Departure> departures) {
|
public synchronized void highlightPath(List<Departure> departures) {
|
||||||
List<String> nodes = new ArrayList();
|
// Lists to hold nodes and edges to be highlighted
|
||||||
|
List<String> nodes = new ArrayList<>();
|
||||||
List<String> edges = new ArrayList<>();
|
List<String> edges = new ArrayList<>();
|
||||||
|
|
||||||
|
// Remove any existing highlight from all nodes and edges
|
||||||
for (Node node : graph) {
|
for (Node node : graph) {
|
||||||
node.removeAttribute("ui.class");
|
node.removeAttribute("ui.class");
|
||||||
}
|
}
|
||||||
@ -49,26 +82,31 @@ public class GraphVisualizer {
|
|||||||
Edge edge = graph.getEdge(i);
|
Edge edge = graph.getEdge(i);
|
||||||
edge.removeAttribute("ui.class");
|
edge.removeAttribute("ui.class");
|
||||||
}
|
}
|
||||||
for (Departure dep : departures) {
|
|
||||||
|
|
||||||
|
// Collect nodes and edges to highlight based on the departures list
|
||||||
|
for (Departure dep : departures) {
|
||||||
String from = dep.getFrom();
|
String from = dep.getFrom();
|
||||||
from = from.replaceAll("[A-Z]", "G");
|
from = from.replaceAll("[A-Z]", "G"); // Adjust formatting
|
||||||
if (!nodes.contains(from)) nodes.add(from);
|
if (!nodes.contains(from)) nodes.add(from);
|
||||||
|
|
||||||
if (!nodes.contains(dep.getTo())) nodes.add(dep.getTo());
|
if (!nodes.contains(dep.getTo())) nodes.add(dep.getTo());
|
||||||
edges.add(from + "-" + dep.getTo() + "-" + dep.getIdCounter());
|
edges.add(from + "-" + dep.getTo() + "-" + dep.getIdCounter());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String s : nodes) {
|
// Print nodes for debugging
|
||||||
System.out.println(s);
|
for (String nodeId : nodes) {
|
||||||
|
System.out.println(nodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply the highlight to nodes
|
||||||
for (String nodeId : nodes) {
|
for (String nodeId : nodes) {
|
||||||
Node node = graph.getNode(nodeId);
|
Node node = graph.getNode(nodeId);
|
||||||
if (node != null) {
|
if (node != null) {
|
||||||
node.setAttribute("ui.class", "highlighted");
|
node.setAttribute("ui.class", "highlighted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply the highlight to edges
|
||||||
for (int i = 0; i < edges.size(); i++) {
|
for (int i = 0; i < edges.size(); i++) {
|
||||||
String from = nodes.get(i);
|
String from = nodes.get(i);
|
||||||
String to = nodes.get(i + 1);
|
String to = nodes.get(i + 1);
|
||||||
@ -83,4 +121,4 @@ public class GraphVisualizer {
|
|||||||
}
|
}
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user