Compare commits

...

No commits in common. "main" and "78879104017b49f491f7edfff48e98ec416b7c6d" have entirely different histories.

34 changed files with 149 additions and 2209 deletions

26
.gitignore vendored
View File

@ -1,20 +1,10 @@
transport_data.json
ticket_counter.txt
todo
receipts/
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
*.class
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
transport_data.json
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
@ -24,6 +14,9 @@ target/
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
@ -31,9 +24,6 @@ target/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

7
.idea/encodings.xml generated
View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

8
.idea/misc.xml generated
View File

@ -1,13 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/PJ2.iml" filepath="$PROJECT_DIR$/PJ2.iml" />
</modules>
</component>
</project>

Binary file not shown.

View File

@ -1,2 +0,0 @@
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar

11
PJ2.iml Normal file
View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

316
mvnw vendored
View File

@ -1,316 +0,0 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`\\unset -f command; \\command -v java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"

188
mvnw.cmd vendored
View File

@ -1,188 +0,0 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%

77
pom.xml
View File

@ -1,77 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.ksan</groupId>
<artifactId>TravelPathOptimizer</artifactId>
<version>1.0-SNAPSHOT</version>
<name>TravelPathOptimizer</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<junit.version>5.10.2</junit.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>17.0.6</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>17.0.6</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<source>23</source>
<target>23</target>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<executions>
<execution>
<!-- Default configuration for running with: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>dev.ksan.travelpathoptimizer/dev.ksan.travelpathoptimizer.app.TravelPathOptimizerApplication
</mainClass>
<launcher>app</launcher>
<jlinkZipName>app</jlinkZipName>
<jlinkImageName>app</jlinkImageName>
<noManPages>true</noManPages>
<stripDebug>true</stripDebug>
<noHeaderFiles>true</noHeaderFiles>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,5 +1,3 @@
package dev.ksan.travelpathoptimizer.model;
import java.util.ArrayList;
import java.util.List;
@ -9,14 +7,14 @@ public class City {
private Station busStation;
private Location location;
public City(String name, String bus, String train, int row, int col) {
City(String name, String bus, String train, int row, int col) {
this.name = name;
this.trainStation = new Station(TransportType.TRAIN, train);
this.busStation = new Station(TransportType.BUS, bus);
this.location = new Location(row, col);
}
public City(String name, Station bus, Station train, int row, int col) {
City(String name, Station bus, Station train, int row, int col) {
this.name = name;
this.trainStation = train;
this.busStation = bus;

14
src/CityManager.java Normal file
View File

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

View File

@ -1,7 +1,3 @@
package dev.ksan.travelpathoptimizer.model;
import dev.ksan.travelpathoptimizer.service.CityManager;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
@ -11,12 +7,9 @@ public class Departure {
private String to;
private int duration;
private LocalTime departureTime;
private LocalTime arrivalTime;
private double price;
private int minTransferTime;
private City toCity;
private static int idCounter = 0;
private int id;
public Departure(
TransportType type,
String from,
@ -25,7 +18,6 @@ public class Departure {
int duration,
double price,
int minTransferTime) {
this.id = idCounter++;
this.type = type;
this.from = from;
this.to = to;
@ -33,26 +25,13 @@ public class Departure {
this.duration = duration;
this.price = price;
this.minTransferTime = minTransferTime;
this.arrivalTime = this.departureTime.plusMinutes(duration);
}
public int getIdCounter() {
return id;
}
public void setToCity(City toCity) {
this.toCity = toCity;
}
public City getDestinationCity() {
return toCity;
// return CityManager.getCityByName(to);
return CityManager.getCityByName(to);
}
public LocalTime getDepartureTime() {
return departureTime;
}
public LocalTime getArrivalTime() {
return arrivalTime;
}
public TransportType getType() {
return type;
}

92
src/Graph.java Normal file
View File

@ -0,0 +1,92 @@
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
public class Graph {
private City[][] matrix;
public static void main(String[] args) {
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
List<Departure> departures = JsonParser.getDeparturesList("transport_data.json", "departures");
cities = JsonParser.loadDepartures(cities, departures);
City[][] map = JsonParser.loadMap("transport_data.json", "countryMap", cities);
Graph graph = new Graph(map);
cities = JsonParser.loadDepartures(cities, departures);
System.out.println(cities.getFirst().getName() + " do " + cities.getLast().getName());
for (City city : cities) {
CityManager.addCity(city);
}
Map<Location, Double> result =
graph.calculateShortestPath(cities.getFirst(), cities.get(3), "hops");
System.out.println(
cities.getLast().getName() + " = " + result.get(cities.get(3).getLocation()));
}
public Map<Location, Double> calculateShortestPath(City startCity, City endCity, String type) {
int n = matrix.length;
int m = matrix[0].length;
Map<Location, Double> distances = new HashMap<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
distances.put(new Location(i, j), Double.MAX_VALUE);
}
}
distances.put(startCity.getLocation(), 0.0);
PriorityQueue<City> pq =
new PriorityQueue<>(Comparator.comparingDouble(city -> distances.get(city.getLocation())));
pq.add(startCity);
while (!pq.isEmpty()) {
City current = pq.poll();
// If we reached the end city, we can stop early
if (current == endCity) {
break;
}
for (Departure dep : current.getDestinations()) {
City neighborCity = dep.getDestinationCity();
Location neighborLocation = neighborCity.getLocation();
double newCost = 0.0;
double currentCost = distances.get(current.getLocation());
if (type.equals("price")) {
newCost = distances.get(current.getLocation()) + dep.getPrice();
} else if (type.equals("time")) {
newCost = distances.get(current.getLocation()) + dep.getDuration();
} else if (type.equals("hops")) {
newCost = currentCost + 1;
}
if (newCost < distances.get(neighborLocation)) {
distances.put(neighborLocation, newCost);
pq.add(neighborCity);
}
}
}
return distances;
}
public Graph(City[][] matrix) {
this.matrix = matrix;
}
public void updateMatrix(City[][] matrix) {
this.matrix = matrix;
}
public City[][] getMatrix() {
return matrix;
}
public City getCity(Location loc) {
return matrix[loc.getX()][loc.getY()];
}
}

View File

@ -1,9 +1,3 @@
package dev.ksan.travelpathoptimizer.util;
import dev.ksan.travelpathoptimizer.model.City;
import dev.ksan.travelpathoptimizer.model.Departure;
import dev.ksan.travelpathoptimizer.model.TransportType;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;

View File

@ -1,5 +1,3 @@
package dev.ksan.travelpathoptimizer.model;
import java.util.Objects;
public class Location {
@ -40,9 +38,4 @@ public class Location {
public int hashCode() {
return Objects.hash(x, y);
}
@Override
public String toString() {
return x + "_" + y;
}
}

6
src/Main.java Normal file
View File

@ -0,0 +1,6 @@
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}

View File

@ -1,5 +1,3 @@
package dev.ksan.travelpathoptimizer.model;
import java.util.ArrayList;
import java.util.List;

View File

@ -1,5 +1,3 @@
package dev.ksan.travelpathoptimizer.app;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
@ -8,26 +6,17 @@ public class TransportDataGenerator {
private static final int SIZE = 10;
private int n;
private int m;
private static final int DEPARTURES_DEFAULT = 3;
private static int DEPARTURES_PER_STATION = DEPARTURES_DEFAULT;
private static final int DEPARTURES_PER_STATION = 1;
private static final Random random = new Random();
public static void generateNewMap(int n, int m) {
DEPARTURES_PER_STATION= DEPARTURES_DEFAULT;
TransportDataGenerator generator = new TransportDataGenerator(n, m);
TransportData data = generator.generateData();
generator.saveToJson(data, "transport_data.json");
System.out.println("Podaci su generisani i sacuvani kao transport_data.json");
}
public static void generateNewMap(int n, int m, int departures) {
TransportDataGenerator generator = new TransportDataGenerator(n, m);
DEPARTURES_PER_STATION = departures;
public static void main(String[] args) {
TransportDataGenerator generator = new TransportDataGenerator(2, 2);
TransportData data = generator.generateData();
generator.saveToJson(data, "transport_data.json");
System.out.println("Podaci su generisani i sacuvani kao transport_data.json");
}
TransportDataGenerator() {
this.n = SIZE;
this.m = SIZE;

View File

@ -1,5 +1,3 @@
package dev.ksan.travelpathoptimizer.model;
public enum TransportType {
NOT_ASSIGNED("null"),
BUS("autobus"),

View File

@ -1,5 +1,3 @@
package dev.ksan.travelpathoptimizer.model;
public class User {
private String name;
private int id;

View File

@ -1,4 +0,0 @@
package dev.ksan.travelpathoptimizer;
public class Main {
}

View File

@ -1,33 +0,0 @@
package dev.ksan.travelpathoptimizer.app;
import dev.ksan.travelpathoptimizer.util.TicketPrinter;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
public class TravelPathOptimizerApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
TicketPrinter.loadCounter();
System.out.println(TicketPrinter.getTotalProfit() + " " + TicketPrinter.getTicketsSoldNum());
FXMLLoader fxmlLoader =
new FXMLLoader(TravelPathOptimizerApplication.class.getResource("main.fxml"));
String css = this.getClass().getResource("application.css").toExternalForm();
Scene scene = new Scene(fxmlLoader.load());
Image image = new Image(getClass().getResourceAsStream("/images/img1.jpg"));
scene.getStylesheets().add(css);
stage.getIcons().add(image);
stage.setTitle("Hello!");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}

View File

@ -1,495 +0,0 @@
package dev.ksan.travelpathoptimizer.controller;
import dev.ksan.travelpathoptimizer.app.TransportDataGenerator;
import dev.ksan.travelpathoptimizer.graph.Graph;
import dev.ksan.travelpathoptimizer.graph.PathResult;
import dev.ksan.travelpathoptimizer.model.City;
import dev.ksan.travelpathoptimizer.model.Departure;
import dev.ksan.travelpathoptimizer.model.Location;
import dev.ksan.travelpathoptimizer.service.CityManager;
import dev.ksan.travelpathoptimizer.util.JsonParser;
import dev.ksan.travelpathoptimizer.util.TicketPrinter;
import java.io.File;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
public class MainController {
@FXML private GridPane map;
@FXML private Label welcomeText;
@FXML private Text selectedFileText;
@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 endCityText;
@FXML private Button startCityButton;
@FXML private Button endCityButton;
private HashMap<Integer, Departure> departuresMap = new HashMap<>();
private Graph graph;
private City[][] cities;
private File selectedFile;
@FXML private Button openFileButton;
@FXML private TextField nTextField;
@FXML private TextField mTextField;
@FXML private TextField departureTextField;
@FXML private VBox randomSideBar;
@FXML private VBox mapSideBar;
@FXML private ChoiceBox categoryBox;
@FXML private Button startButton;
// routeView
@FXML private HBox routeView;
@FXML private Text totalTicketPriceText;
@FXML private Button buyButton;
@FXML private TableView<Departure> resultTable;
@FXML private TableColumn<Departure, String> tabDepartureCol;
@FXML private TableColumn<Departure, String> tabArrivalCol;
@FXML private TableColumn<Departure, String> tabTypeCol;
@FXML private TableColumn<Departure, Double> tabCostCol;
@FXML private ChoiceBox<String> pathChoiceBox;
@FXML
private void buyTicket() {
TicketPrinter printer = new TicketPrinter();
printer.generateTicketReceipt(
updateUiGetList(), Double.parseDouble(totalTicketPriceText.getText()));
}
@FXML
private void findTopPaths() {
graph.reset();
updateUiGetList();
pathChoiceBox.getItems().clear();
startButton.setDisable(true);
startCityText.setDisable(true);
startCityButton.setDisable(true);
endCityButton.setDisable(true);
endCityText.setDisable(true);
Task<Void> task =
new Task<Void>() {
@Override
protected Void call() throws Exception {
graph.reset();
if (startCity != null && endCity != null) {
List<City> path = new ArrayList<>();
List<Integer> departures = new ArrayList<>();
LocalTime currentTime = LocalTime.of(1, 0);
double totalCost = 0.0;
System.out.println(categoryBox.getValue().toString());
graph.calculateTopPaths(
startCity,
endCity,
path,
totalCost,
currentTime,
departures,
categoryBox.getValue().toString());
System.out.println(graph.getTopPaths().size());
System.out.println(startCity.getName() + endCity.getName());
if (graph.getTopPaths().isEmpty()) return null;
Platform.runLater(
() -> {
for (PathResult pathResult : graph.getSortedPaths()) {
pathChoiceBox.getItems().add("Route: " + String.valueOf(pathResult.getId()));
}
pathChoiceBox.setValue(
"Route: " + String.valueOf(graph.getSortedPaths().getFirst().getId()));
updateUiGetList();
});
}
return null;
}
@Override
protected void succeeded() {
super.succeeded();
startButton.setDisable(false);
startCityText.setDisable(false);
startCityButton.setDisable(false);
endCityButton.setDisable(false);
endCityText.setDisable(false);
if (!routeView.isVisible()) showRouteView();
}
@Override
protected void failed() {
super.failed();
startButton.setDisable(false);
startCityText.setDisable(false);
startCityButton.setDisable(false);
endCityButton.setDisable(false);
endCityText.setDisable(false);
}
};
new Thread(task).start();
}
private synchronized ObservableList<Departure> updateUiGetList() {
ObservableList<Departure> departureList = FXCollections.observableArrayList();
while (pathChoiceBox == null) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (graph.getTopPaths().size() > 0) {
Optional<List<Integer>> departuresOpt =
graph.getSortedPaths().stream()
.filter(
item ->
item.getId()
== Integer.parseInt(pathChoiceBox.getValue().replaceAll("[^0-9]", "")))
.map(PathResult::getDeparturesUsed)
.findFirst();
if (departuresOpt.isPresent()) {
for (Integer dep : departuresOpt.get()) {
departureList.add(departuresMap.get(dep));
}
} else {
System.out.println("No matching PathResult found.");
}
}
System.out.println(departureList.size());
resultTable.setItems(departureList);
resultTable.refresh();
double totalTicketPrice = calculateTotalCost(departureList);
Platform.runLater(
() -> {
totalTicketPriceText.setText(String.format("%.2f", totalTicketPrice));
});
return departureList;
}
@FXML
protected void onHelloButtonClick() {
welcomeText.setText("Welcome to JavaFX Application!");
}
@FXML
private void showRouteView() {
boolean visible = routeView.isVisible();
routeView.setVisible(!visible);
routeView.setManaged(!visible);
}
@FXML
void showRandomSideBar() {
boolean visible = randomSideBar.isVisible();
randomSideBar.setVisible(!visible);
randomSideBar.setManaged(!visible);
}
@FXML
void showMapSideBar() {
boolean visible = mapSideBar.isVisible();
mapSideBar.setVisible(!visible);
mapSideBar.setManaged(!visible);
}
private void updateMap() {
map.getChildren().clear();
map.getRowConstraints().clear();
map.getColumnConstraints().clear();
int rows = cities.length;
int cols = cities[0].length;
// Make each row/column take equal space and grow
for (int i = 0; i < rows; i++) {
RowConstraints rc = new RowConstraints();
rc.setPercentHeight(100.0 / rows);
rc.setVgrow(Priority.ALWAYS);
map.getRowConstraints().add(rc);
}
for (int j = 0; j < cols; j++) {
ColumnConstraints cc = new ColumnConstraints();
cc.setPercentWidth(100.0 / cols);
cc.setHgrow(Priority.ALWAYS);
map.getColumnConstraints().add(cc);
}
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
final int currentRow = row;
final int currentCol = col;
StackPane cell = new StackPane();
cell.setPrefSize(60, 60);
cell.setStyle("-fx-border-color: black; -fx-background-color: white;");
City city = cities[currentRow][currentCol];
Label label = new Label(city.getName());
label.setStyle("-fx-font-size: 10px;");
label.setWrapText(true);
final StackPane thisCell = cell;
thisCell.getChildren().add(label);
cell.setOnMouseClicked(
e -> {
if (selectingStart) {
startCity = cities[currentRow][currentCol];
startCityText.setText(startCity.getName());
selectingStart = false;
updateMap();
} else if (selectingEnd) {
endCity = cities[currentRow][currentCol];
endCityText.setText(endCity.getName());
selectingEnd = false;
updateMap();
}
});
thisCell.setStyle("-fx-border-color: black; -fx-background-color: white;");
Location loc = cities[currentRow][currentCol].getLocation();
if (startCity != null) {
Location startLoc = startCity.getLocation();
if (loc.getX() == startLoc.getX() && loc.getY() == startLoc.getY()) {
thisCell.setStyle(
"-fx-border-color: green; -fx-border-width: 3; -fx-background-color: white;");
}
}
if (endCity != null) {
Location endLoc = endCity.getLocation();
if (loc.getX() == endLoc.getX() && loc.getY() == endLoc.getY()) {
thisCell.setStyle(
"-fx-border-color: red; -fx-border-width: 3; -fx-background-color: white;");
}
}
map.add(cell, col, row);
}
}
}
@FXML
private void selectStart() {
this.selectingEnd = false;
this.selectingStart = true;
updateMap();
}
@FXML
private void selectEnd() {
this.selectingStart = false;
this.selectingEnd = true;
updateMap();
}
@FXML
public void initialize() {
pathChoiceBox.setOnAction(
event -> {
updateUiGetList();
});
categoryBox.getItems().addAll("time", "price", "hops");
categoryBox.setValue("time");
tabDepartureCol.setCellFactory(
column ->
new TableCell<Departure, String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty || getTableRow() == null || getTableRow().getItem() == null) {
setText(null);
} else {
Departure dep = getTableRow().getItem();
String departureInfo =
dep.getFrom() + " (" + dep.getDepartureTime().toString() + ")";
setText(departureInfo);
}
}
});
tabArrivalCol.setCellFactory(
column ->
new TableCell<Departure, String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty || getTableRow() == null || getTableRow().getItem() == null) {
setText(null);
} else {
Departure dep = getTableRow().getItem();
String departureInfo = dep.getTo() + " (" + dep.getArrivalTime().toString() + ")";
setText(departureInfo);
}
}
});
tabTypeCol.setCellFactory(
column ->
new TableCell<Departure, String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty || getTableRow() == null || getTableRow().getItem() == null) {
setText(null);
} else {
Departure dep = getTableRow().getItem();
setText(dep.getType().toString());
}
}
});
tabCostCol.setCellValueFactory(new PropertyValueFactory<>("price"));
endCityText
.textProperty()
.addListener(
(obs, oldText, newText) -> {
if (newText.isBlank()) {
endCity = null;
endCityText.setStyle("-fx-text-fill: black;");
} else {
City match = CityManager.getCityByName(newText.trim());
if (match != null) {
System.out.println("Selected end: " + match.getName());
endCity = match;
endCityText.setStyle("-fx-text-fill: green;");
} else {
endCity = null;
endCityText.setStyle("-fx-text-fill: red;");
}
}
updateMap(); // Re-draw with highlight if matched
});
startCityText
.textProperty()
.addListener(
(obs, oldText, newText) -> {
if (newText.isBlank()) {
startCity = null;
startCityText.setStyle("-fx-text-fill: black;");
} else {
City match = CityManager.getCityByName(newText.trim());
if (match != null) {
System.out.println("Selected start: " + match.getName());
startCity = match;
startCityText.setStyle("-fx-text-fill: green;");
} else {
startCity = null;
startCityText.setStyle("-fx-text-fill: red;");
}
}
updateMap(); // Re-draw with highlight if matched
});
}
private double calculateTotalCost(ObservableList<Departure> depList) {
double totalCost = 0.0;
for (Departure dep : depList) {
totalCost += dep.getPrice();
}
return totalCost;
}
@FXML
void generateNewMap() {
if (!nTextField.getText().isEmpty() && !mTextField.getText().isEmpty()) {
System.out.println(nTextField.getText());
System.out.println(mTextField.getText());
System.out.println(departureTextField.getText());
if (!departureTextField.getText().isEmpty()) {
TransportDataGenerator.generateNewMap(
Integer.parseInt(nTextField.getText()),
Integer.parseInt(mTextField.getText()),
Integer.parseInt(departureTextField.getText()));
} else {
TransportDataGenerator.generateNewMap(
Integer.parseInt(nTextField.getText()), Integer.parseInt(mTextField.getText()));
}
}
}
private void getData() {
CityManager.clear();
List<City> cities = JsonParser.parseCities("transport_data.json", "stations");
List<Departure> departures = JsonParser.getDeparturesList("transport_data.json", "departures");
for (Departure dep : departures) {
this.departuresMap.put(dep.getIdCounter(), dep);
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);
cities = JsonParser.loadDepartures(cities, departures);
for (City city : cities) {
CityManager.addCity(city);
}
this.cities = map;
this.graph = new Graph(map);
}
@FXML
void loadMapFromFile() {
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Open File");
fileChooser
.getExtensionFilters()
.addAll(
new FileChooser.ExtensionFilter("Json Files", "*.json"),
new FileChooser.ExtensionFilter("All Files", "*.*"));
Stage stage = (Stage) openFileButton.getScene().getWindow();
selectedFile = fileChooser.showOpenDialog(stage);
if (selectedFile != null) {
selectedFileText.setText(selectedFile.getAbsoluteFile().getName().toString());
}
getData();
updateMap();
this.mapSelectButton.setText(selectedFile.getName().toString());
}
}

View File

@ -1,404 +0,0 @@
package dev.ksan.travelpathoptimizer.graph;
import dev.ksan.travelpathoptimizer.model.City;
import dev.ksan.travelpathoptimizer.model.Departure;
import dev.ksan.travelpathoptimizer.model.Location;
import dev.ksan.travelpathoptimizer.service.CityManager;
import dev.ksan.travelpathoptimizer.util.JsonParser;
import java.time.Duration;
import java.time.LocalTime;
import java.util.*;
public class Graph {
private City[][] matrix;
private List<PathResult> allPaths = new ArrayList<>();
private int pathIdCounter = 1;
private static int nextid = 0;
private static Set<String> visitedRoutes = new HashSet<>();
public static PriorityQueue<PathResult> topPaths =
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);
Graph graph = new Graph(map);
cities = JsonParser.loadDepartures(cities, departures);
for (City city : cities) {
CityManager.addCity(city);
}
System.out.println(cities.getFirst().getName() + " do " + cities.getLast().getName());
Map<Location, Double> result =
graph.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(){
List<PathResult> pathList = new ArrayList<>(topPaths);
pathList.sort(Comparator.comparingDouble(PathResult::getCost));
return pathList;
}
public void reset() {
topPaths.clear();
pathIdCounter = 1;
nextid = 0;
allPaths.clear();
visitedRoutes.clear();
}
public static void addToTopPaths(PathResult newPath) {
String routeHash = generateRouteHash(newPath.getDeparturesUsed());
if (visitedRoutes.contains(routeHash)) {
return;
}
visitedRoutes.add(routeHash);
if (topPaths.size() < 5) {
topPaths.offer(newPath);
} else {
if (newPath.getCost() < topPaths.peek().getCost()) {
System.out.println("Removing path with cost: " + topPaths.peek().getCost());
topPaths.poll();
topPaths.offer(newPath);
}
}
}
private static String generateRouteHash(List<Integer> departures) {
StringBuilder sb = new StringBuilder();
for (Integer depId : departures) {
sb.append(depId).append("-");
}
return sb.toString();
}
public static void calculateTopPaths(
City currentCity,
City endCity,
List<City> path,
double totalCost,
LocalTime currentTime,
List<Integer> departures,
String type) {
if (currentCity.getLocation().equals(endCity.getLocation())) {
addToTopPaths(
new PathResult(
nextid++,
new ArrayList<>(path),
new ArrayList<>(departures),
totalCost,
currentTime));
return;
}
for (Departure dep : currentCity.getDestinations()) {
double cost = 0.0;
if (dep.getDepartureTime().isBefore(currentTime)) continue;
City nextCity;
if (path.contains(dep.getDestinationCity())) {
continue;
} else {
nextCity = dep.getDestinationCity();
}
LocalTime arrivalTime = dep.getDepartureTime().plusMinutes(dep.getDuration());
Duration duration = Duration.between(currentTime, arrivalTime);
duration = duration.abs();
if (type.equals("time")) {
// cost += dep.getDuration();
cost += duration.toMinutes();
} else if (type.equals("price")) {
cost += dep.getPrice();
} else if (type.equals("hops")) {
cost++;
if(!topPaths.isEmpty() && totalCost + cost >= topPaths.peek().getCost()) continue;
} else {
return;
}
if (topPaths.size() >= 5 && totalCost + cost > topPaths.peek().getCost()) {
return;
}
path.add(nextCity);
departures.add(dep.getIdCounter());
calculateTopPaths(nextCity, endCity, path, totalCost + cost, arrivalTime, departures, type);
departures.remove(departures.size() - 1);
path.remove(path.size() - 1);
if (type.equals("hops")) {
cost--;
}
}
}
public static void printTopPaths() {
if (topPaths.isEmpty()) {
System.out.println("No Paths");
return;
}
System.out.println("Top 5 Paths:");
int rank = 5;
while (!topPaths.isEmpty()) {
PathResult pathResult = topPaths.poll();
System.out.println("Rank: " + rank--);
System.out.println("ID: " + pathResult.getId());
System.out.println("Cost: " + pathResult.getCost());
System.out.println("Path: " + pathResult.getPath().size());
System.out.println("Departures: " + pathResult.getDeparturesUsed());
System.out.println();
}
}
/*
private PriorityQueue<PathResult> topPaths =
new PriorityQueue<>(Comparator.comparingDouble(PathResult::getCost).reversed());
private final AtomicInteger pathIdGenerator = new AtomicInteger(1); // Start from 1
private final Set<String> uniquePathKeys = new HashSet<>();
private int makeDeparturePathHash(Set<Departure> departures) {
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) {
int n = matrix.length;
int m = matrix[0].length;
Map<Location, Double> distances = new HashMap<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
distances.put(new Location(i, j), Double.MAX_VALUE);
}
}
distances.put(startCity.getLocation(), 0.0);
PriorityQueue<City> pq =
new PriorityQueue<>(Comparator.comparingDouble(city -> distances.get(city.getLocation())));
pq.add(startCity);
while (!pq.isEmpty()) {
City current = pq.poll();
if (current == endCity) {
break;
}
for (Departure dep : current.getDestinations()) {
City neighborCity = dep.getDestinationCity();
Location neighborLocation = neighborCity.getLocation();
double newCost = 0.0;
double currentCost = distances.get(current.getLocation());
if (type.equals("price")) {
newCost = distances.get(current.getLocation()) + dep.getPrice();
} else if (type.equals("time")) {
newCost = distances.get(current.getLocation()) + dep.getDuration();
} else if (type.equals("hops")) {
newCost = currentCost + 1;
}
if (newCost < distances.get(neighborLocation)) {
distances.put(neighborLocation, newCost);
pq.add(neighborCity);
}
}
}
return distances;
}
public List<PathResult> getAllPaths() {
return allPaths;
}
public Graph(City[][] matrix) {
this.matrix = matrix;
}
public void updateMatrix(City[][] matrix) {
this.matrix = matrix;
}
public City[][] getMatrix() {
return matrix;
}
public City getCity(Location loc) {
return matrix[loc.getX()][loc.getY()];
}
public static PriorityQueue<PathResult> getTopPaths() {
return topPaths;
}
}

View File

@ -1,48 +0,0 @@
package dev.ksan.travelpathoptimizer.graph;
import dev.ksan.travelpathoptimizer.model.City;
import dev.ksan.travelpathoptimizer.model.Departure;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
public class PathResult {
private int id;
private List<City> path = new ArrayList<>();
private List<Integer> departuresUsed = new ArrayList<>();
private double cost;
private LocalTime arrivalTime;
public PathResult(int id, List<City> path, List<Integer> departuresUsed, double cost, LocalTime arrivalTime) {
this.id = id;
this.path = path;
this.departuresUsed = departuresUsed;
this.cost = cost;
this.arrivalTime = arrivalTime;
}
public int getId() {
return id;
}
public List<City> getPath() {
return path;
}
public List<Integer> getDeparturesUsed() {
return departuresUsed;
}
public double getCost() {
return cost;
}
public LocalTime getArrivalTime() {
return arrivalTime;
}
@Override
public String toString() {
return "PathResult{id=" + id + " cost = " + cost + ", path=" + path + ", arrivalTime=" + arrivalTime + '}';
}
}

View File

@ -1,63 +0,0 @@
package dev.ksan.travelpathoptimizer.graph;
import dev.ksan.travelpathoptimizer.model.City;
import dev.ksan.travelpathoptimizer.model.Departure;
import java.util.List;
import java.util.stream.Collectors;
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;
}
}

View File

@ -1,29 +0,0 @@
package dev.ksan.travelpathoptimizer.service;
import dev.ksan.travelpathoptimizer.model.City;
import dev.ksan.travelpathoptimizer.model.Location;
import java.util.HashMap;
import java.util.Map;
public class CityManager {
private static Map<String, City> cities = new HashMap<>();
private static Map<Location, City> citiesByLocation = new HashMap<>();
public static void clear() {
citiesByLocation.clear();
cities.clear();
}
public static void addCity(City city) {
cities.put(city.getName(), city);
citiesByLocation.put(city.getLocation(), city);
}
public static City getCityByLocation(Location loc) {
return citiesByLocation.get(loc);
}
public static City getCityByName(String cityName) {
return cities.get(cityName);
}
}

View File

@ -1,123 +0,0 @@
package dev.ksan.travelpathoptimizer.util;
import dev.ksan.travelpathoptimizer.model.Departure;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.List;
public class TicketPrinter {
private static final String COUNTER_FILE = "ticket_counter.txt";
private static final String RECEIPTS_DIRECTORY = "receipts";
private static double totalProfit = 0.0;
private static int ticketIdCounter = 0;
public static void generateTicketReceipt(List<Departure> departures, double totalPrice) {
LocalDate currentDate = LocalDate.now();
StringBuilder receipt = new StringBuilder();
receipt.append("=====================================================\n");
receipt.append(" TICKET RECEIPT\n");
receipt.append(" Ksan Travel Optimizer\n");
receipt.append("=====================================================\n");
receipt.append("Ticket ID: ").append(getNextId()).append("\n");
saveCounter();
receipt.append("Date: ").append(currentDate).append("\n");
receipt.append("From: ").append(departures.getFirst().getFrom()).append("\n");
receipt.append("To: ").append(departures.getLast().getTo()).append("\n");
receipt.append("-----------------------------------------------------\n");
receipt.append("Departure Prices:\n");
for (Departure dep : departures) {
receipt
.append(" - ")
.append(dep.getFrom())
.append(" -> ")
.append(dep.getTo())
.append(" | Price: $")
.append(String.format("%.2f", dep.getPrice()))
.append("\n");
}
receipt.append("-----------------------------------------------------\n");
receipt.append("Total Price: $").append(String.format("%.2f", totalPrice)).append("\n");
totalProfit += totalPrice;
receipt.append("=====================================================\n");
receipt.append("Thank you for choosing our service!\n");
folderExists();
writeReceipt(receipt.toString());
}
private static void writeReceipt(String receipt) {
Path receiptFile = Paths.get(RECEIPTS_DIRECTORY, "receipt_" + ticketIdCounter + ".txt");
try {
Files.write(receiptFile, receipt.getBytes());
System.out.println("Receipt saved to: " + receiptFile.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
private static void folderExists() {
Path path = Paths.get(RECEIPTS_DIRECTORY);
if (!Files.exists(path)) {
try {
Files.createDirectory(path);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void loadCounter() {
try {
Path path = Paths.get(COUNTER_FILE);
if (Files.exists(path)) {
List<String> lines = Files.readAllLines(path);
for (String line : lines) {
String[] parts = line.split("=");
if ("ticketIdCounter".equals(parts[0].trim())) {
ticketIdCounter = Integer.parseInt(parts[1].trim());
} else if ("totalProfit".equals(parts[0].trim())) {
totalProfit = Double.parseDouble(parts[1].trim());
}
}
} else {
ticketIdCounter = 0;
totalProfit = 0.0;
}
} catch (Exception e) {
e.printStackTrace();
ticketIdCounter = 0;
totalProfit = 0.0;
}
}
public static double getTotalProfit() {
return totalProfit;
}
public static int getTicketsSoldNum() {
return ticketIdCounter;
}
private static void saveCounter() {
try {
String str = "ticketIdCounter=" + ticketIdCounter + "\n" + "totalProfit=" + totalProfit;
Files.write(Paths.get(COUNTER_FILE), str.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
private static int getNextId() {
return ++ticketIdCounter;
}
}

View File

@ -1,41 +0,0 @@
module dev.ksan.travelpathoptimizer {
requires javafx.controls;
requires javafx.fxml;
requires java.desktop;
requires javafx.graphics;
requires javafx.base;
opens dev.ksan.travelpathoptimizer to
javafx.fxml;
exports dev.ksan.travelpathoptimizer;
exports dev.ksan.travelpathoptimizer.app;
opens dev.ksan.travelpathoptimizer.app to
javafx.fxml;
exports dev.ksan.travelpathoptimizer.controller;
opens dev.ksan.travelpathoptimizer.controller to
javafx.fxml;
exports dev.ksan.travelpathoptimizer.model;
opens dev.ksan.travelpathoptimizer.model to
javafx.fxml;
exports dev.ksan.travelpathoptimizer.util;
opens dev.ksan.travelpathoptimizer.util to
javafx.fxml;
exports dev.ksan.travelpathoptimizer.service;
opens dev.ksan.travelpathoptimizer.service to
javafx.fxml;
exports dev.ksan.travelpathoptimizer.graph;
opens dev.ksan.travelpathoptimizer.graph to
javafx.fxml;
}

View File

@ -1,41 +0,0 @@
#sideMenu{
-fx-background-color: rgba(118, 140, 239, 0.53);
}
#header{
-fx-background-color: rgb(132, 64, 234);
-fx-border-color: black;
}
#randomSideBar{
-fx-background-color: red;
}
#headerBar{
-fx-alignment: center;
-fx-end-margin: 40;
}
#headerBar Button {
-fx-background-color: linear-gradient(to bottom, #6a1b9a, #8e24aa);
-fx-text-fill: white;
-fx-font-weight: bold;
-fx-font-size: 14px;
-fx-background-radius: 8px;
-fx-border-radius: 8px;
-fx-padding: 8 16;
-fx-cursor: hand;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.3), 4, 0, 0, 2);
}
#mapSideBar{
-fx-background-color: #ba9be3;
}
#headerBar Button:hover {
-fx-background-color: linear-gradient(to bottom, #8e24aa, #9c27b0);
}
#headerBar Button:pressed {
-fx-background-color: linear-gradient(to bottom, #4a148c, #6a1b9a);
-fx-effect: innershadow(gaussian, rgba(0,0,0,0.5), 3, 0, 0, 1);
}
#sectionText{
-fx-font-size: 18;
-fx-underline: true;
}

View File

@ -1,235 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ChoiceBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Text?>
<VBox fx:id="root" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="800.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/23.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dev.ksan.travelpathoptimizer.controller.MainController">
<children>
<HBox fx:id="header" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minWidth="-Infinity" prefHeight="12.0" prefWidth="1000.0">
<children>
<HBox maxHeight="1.7976931348623157E308" prefHeight="50.0" prefWidth="180.0" HBox.hgrow="SOMETIMES">
<children>
<ImageView fitHeight="50.0" fitWidth="129.0" pickOnBounds="true" preserveRatio="true" HBox.hgrow="ALWAYS">
<image>
<Image url="@../../../../images/img1.jpg" />
</image>
<HBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</HBox.margin>
</ImageView>
<Text boundsType="LOGICAL_VERTICAL_CENTER" strokeType="OUTSIDE" strokeWidth="0.0" text="Text" textAlignment="CENTER" textOrigin="CENTER" wrappingWidth="80.13000106811523" HBox.hgrow="ALWAYS">
<HBox.margin>
<Insets top="25.0" />
</HBox.margin>
</Text>
</children>
</HBox>
<HBox fx:id="headerBar" minWidth="400.0" prefHeight="121.0" prefWidth="805.0">
<children>
<Button fx:id="headerButton1" onAction="#showMapSideBar" text="Map Options" />
<Label style="-fx-font-size: 20px; -fx-text-fill: gray;" text="|" />
<Button fx:id="headerButton2" text="Button" />
<Label style="-fx-font-size: 20px; -fx-text-fill: gray;" text="|" />
<Button fx:id="headerButton3" text="Button" />
</children>
</HBox>
</children></HBox>
<HBox fx:id="menuContainer" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="578.0" prefWidth="1000.0" VBox.vgrow="ALWAYS">
<children>
<VBox fx:id="mapSideBar" managed="false" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="354.0" prefWidth="180.0" visible="false">
<children>
<Text fx:id="sectionText" strokeType="OUTSIDE" strokeWidth="0.0" text="Map Generator" textAlignment="CENTER" wrappingWidth="179.2100067138672" />
<Button mnemonicParsing="false" onAction="#generateNewMap" prefHeight="26.0" prefWidth="194.0" text="Generate Map">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</Button>
<HBox prefHeight="39.0" prefWidth="180.0">
<children>
<TextField fx:id="nTextField" alignment="CENTER" promptText="n">
<HBox.margin>
<Insets left="10.0" right="5.0" />
</HBox.margin>
</TextField>
<TextField fx:id="mTextField" alignment="CENTER" promptText="m">
<HBox.margin>
<Insets left="5.0" right="10.0" />
</HBox.margin>
</TextField>
</children>
</HBox>
<HBox prefHeight="39.0" prefWidth="180.0">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Departures:">
<HBox.margin>
<Insets left="10.0" top="3.0" />
</HBox.margin>
</Text>
<TextField fx:id="departureTextField" alignment="CENTER" promptText="3">
<HBox.margin>
<Insets left="15.0" right="10.0" />
</HBox.margin>
</TextField>
</children>
</HBox>
<VBox prefHeight="80.0" prefWidth="180.0">
<children>
<Button fx:id="openFileButton" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" mnemonicParsing="false" onAction="#loadMapFromFile" text="Load Map" VBox.vgrow="ALWAYS">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</VBox.margin>
</Button>
<Text fx:id="selectedFileText" strokeType="OUTSIDE" strokeWidth="0.0" text="no file" textAlignment="CENTER" textOrigin="CENTER" wrappingWidth="147.13000106811523" VBox.vgrow="ALWAYS">
<VBox.margin>
<Insets left="15.0" right="15.0" />
</VBox.margin>
</Text>
</children>
</VBox>
</children>
</VBox>
<VBox fx:id="calculatorSideBar" managed="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="354.0" prefWidth="180.0" visible="true">
<children>
<Text fx:id="sectionText1" strokeType="OUTSIDE" strokeWidth="0.0" text="Path Calculator" textAlignment="CENTER" wrappingWidth="179.2100067138672" />
<HBox prefHeight="32.0" prefWidth="180.0">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Map:" textAlignment="CENTER" wrappingWidth="37.562997817993164">
<HBox.margin>
<Insets left="10.0" right="10.0" top="5.0" />
</HBox.margin>
</Text>
<Button fx:id="mapSelectButton" mnemonicParsing="false" onAction="#showMapSideBar" prefHeight="26.0" prefWidth="111.0" text="select">
<HBox.margin>
<Insets left="10.0" right="10.0" top="3.0" />
</HBox.margin>
</Button>
</children>
</HBox>
<HBox prefHeight="39.0" prefWidth="180.0">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Start:">
<HBox.margin>
<Insets left="10.0" top="3.0" />
</HBox.margin>
</Text>
<TextField fx:id="startCityText" alignment="CENTER" promptText="G_0_0">
<HBox.margin>
<Insets left="15.0" right="10.0" />
</HBox.margin>
</TextField>
</children>
</HBox>
<Button fx:id="startCityButton" mnemonicParsing="false" onAction="#selectStart" prefHeight="26.0" prefWidth="194.0" text="Click Start City">
<VBox.margin>
<Insets bottom="10.0" left="10.0" right="10.0" top="-5.0" />
</VBox.margin>
</Button>
<HBox prefHeight="39.0" prefWidth="180.0">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="End:">
<HBox.margin>
<Insets left="10.0" right="6.0" top="3.0" />
</HBox.margin>
</Text>
<TextField fx:id="endCityText" alignment="CENTER" promptText="G_1_1">
<HBox.margin>
<Insets left="15.0" right="10.0" />
</HBox.margin>
</TextField>
</children>
</HBox>
<Button fx:id="endCityButton" mnemonicParsing="false" onAction="#selectEnd" prefHeight="26.0" prefWidth="194.0" text="Click End City">
<VBox.margin>
<Insets left="10.0" right="10.0" top="-5.0" />
</VBox.margin>
</Button>
<HBox prefHeight="52.0" prefWidth="180.0">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Category:">
<HBox.margin>
<Insets left="10.0" top="13.0" />
</HBox.margin>
</Text>
<ChoiceBox fx:id="categoryBox" prefWidth="150.0">
<HBox.margin>
<Insets left="10.0" right="10.0" top="10.0" />
</HBox.margin>
</ChoiceBox>
</children>
</HBox>
<Button fx:id="startButton" mnemonicParsing="false" onAction="#findTopPaths" prefHeight="26.0" prefWidth="185.0" text="Start">
<VBox.margin>
<Insets left="15.0" right="15.0" top="15.0" />
</VBox.margin>
</Button>
</children>
</VBox>
<GridPane fx:id="map" alignment="CENTER" gridLinesVisible="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" HBox.hgrow="ALWAYS">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</GridPane>
<VBox fx:id="randomSideBar" managed="false" maxHeight="1.7976931348623157E308" prefHeight="354.0" prefWidth="150.0" visible="false" />
</children>
<VBox.margin>
<Insets />
</VBox.margin>
</HBox>
<HBox fx:id="routeView" prefHeight="148.0" prefWidth="1000.0">
<children>
<VBox prefHeight="148.0" prefWidth="807.0">
<children>
<TableView fx:id="resultTable" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="200.0" prefWidth="200.0">
<columns>
<TableColumn fx:id="tabDepartureCol" prefWidth="300.0" text="Departure" />
<TableColumn fx:id="tabArrivalCol" prefWidth="300.0" text="Arrival" />
<TableColumn fx:id="tabTypeCol" prefWidth="100.0" text="Type" />
<TableColumn fx:id="tabCostCol" prefWidth="100.0" text="Cost" />
</columns>
</TableView>
</children></VBox>
<VBox maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefHeight="148.0" prefWidth="194.0">
<children>
<ChoiceBox fx:id="pathChoiceBox" prefHeight="26.0" prefWidth="182.0">
<VBox.margin>
<Insets left="15.0" right="15.0" top="2.0" />
</VBox.margin>
</ChoiceBox>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Total:" textAlignment="CENTER" wrappingWidth="196.91699981689453">
<VBox.margin>
<Insets top="15.0" />
</VBox.margin>
</Text>
<Text fx:id="totalTicketPriceText" strokeType="OUTSIDE" strokeWidth="0.0" text="0.0" textAlignment="CENTER" wrappingWidth="201.13000106811523" />
<Button fx:id="buyButton" mnemonicParsing="false" onAction="#buyTicket" prefHeight="45.0" prefWidth="142.0" text="Buy Ticket" textAlignment="CENTER">
<VBox.margin>
<Insets left="30.0" right="30.0" top="15.0" />
</VBox.margin>
</Button>
</children>
</VBox>
</children></HBox>
</children>
</VBox>

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="dev.ksan.travelpathoptimizer.app.Test"
prefHeight="400.0" prefWidth="600.0">
</AnchorPane>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB