Compare commits
No commits in common. "main" and "78879104017b49f491f7edfff48e98ec416b7c6d" have entirely different histories.
main
...
7887910401
27
.gitignore
vendored
27
.gitignore
vendored
@ -1,21 +1,10 @@
|
|||||||
transport_data.json
|
|
||||||
ticket_counter.txt
|
|
||||||
docs/
|
|
||||||
todo
|
|
||||||
receipts/
|
|
||||||
target/
|
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
|
||||||
!**/src/main/**/target/
|
|
||||||
!**/src/test/**/target/
|
|
||||||
|
|
||||||
|
*.class
|
||||||
### IntelliJ IDEA ###
|
### IntelliJ IDEA ###
|
||||||
.idea/modules.xml
|
transport_data.json
|
||||||
.idea/jarRepositories.xml
|
out/
|
||||||
.idea/compiler.xml
|
!**/src/main/**/out/
|
||||||
.idea/libraries/
|
!**/src/test/**/out/
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
### Eclipse ###
|
### Eclipse ###
|
||||||
.apt_generated
|
.apt_generated
|
||||||
@ -25,6 +14,9 @@ target/
|
|||||||
.settings
|
.settings
|
||||||
.springBeans
|
.springBeans
|
||||||
.sts4-cache
|
.sts4-cache
|
||||||
|
bin/
|
||||||
|
!**/src/main/**/bin/
|
||||||
|
!**/src/test/**/bin/
|
||||||
|
|
||||||
### NetBeans ###
|
### NetBeans ###
|
||||||
/nbproject/private/
|
/nbproject/private/
|
||||||
@ -32,9 +24,6 @@ target/
|
|||||||
/dist/
|
/dist/
|
||||||
/nbdist/
|
/nbdist/
|
||||||
/.nb-gradle/
|
/.nb-gradle/
|
||||||
build/
|
|
||||||
!**/src/main/**/build/
|
|
||||||
!**/src/test/**/build/
|
|
||||||
|
|
||||||
### VS Code ###
|
### VS Code ###
|
||||||
.vscode/
|
.vscode/
|
||||||
|
7
.idea/encodings.xml
generated
7
.idea/encodings.xml
generated
@ -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>
|
|
11
.idea/misc.xml
generated
11
.idea/misc.xml
generated
@ -1,16 +1,5 @@
|
|||||||
<?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="JavadocGenerationManager">
|
|
||||||
<option name="OUTPUT_DIRECTORY" value="$PROJECT_DIR$/docs" />
|
|
||||||
</component>
|
|
||||||
<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">
|
<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" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal 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>
|
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
BIN
.mvn/wrapper/maven-wrapper.jar
vendored
Binary file not shown.
2
.mvn/wrapper/maven-wrapper.properties
vendored
2
.mvn/wrapper/maven-wrapper.properties
vendored
@ -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
11
PJ2.iml
Normal 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
316
mvnw
vendored
@ -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
188
mvnw.cmd
vendored
@ -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%
|
|
98
pom.xml
98
pom.xml
@ -1,98 +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>22.0.2</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.openjfx</groupId>
|
|
||||||
<artifactId>javafx-swing</artifactId>
|
|
||||||
<version>24</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.graphstream</groupId>
|
|
||||||
<artifactId>gs-core</artifactId>
|
|
||||||
<version>2.0</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.graphstream</groupId>
|
|
||||||
<artifactId>gs-ui-javafx</artifactId>
|
|
||||||
<version>2.0</version>
|
|
||||||
</dependency>
|
|
||||||
<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>
|
|
69
src/City.java
Normal file
69
src/City.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class City {
|
||||||
|
private String name;
|
||||||
|
private Station trainStation;
|
||||||
|
private Station busStation;
|
||||||
|
private Location location;
|
||||||
|
|
||||||
|
City(String name, String bus, String train, int row, int col) {
|
||||||
|
this.name = name;
|
||||||
|
this.trainStation = new Station(TransportType.TRAIN, train);
|
||||||
|
this.busStation = new Station(TransportType.BUS, bus);
|
||||||
|
this.location = new Location(row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
City(String name, Station bus, Station train, int row, int col) {
|
||||||
|
this.name = name;
|
||||||
|
this.trainStation = train;
|
||||||
|
this.busStation = bus;
|
||||||
|
this.location = new Location(row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Departure> getDestinations() {
|
||||||
|
List<Departure> departures = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Departure dep : busStation.getDepartures()) {
|
||||||
|
departures.add(dep);
|
||||||
|
}
|
||||||
|
for (Departure dep : trainStation.getDepartures()) {
|
||||||
|
departures.add(dep);
|
||||||
|
}
|
||||||
|
|
||||||
|
return departures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Station getTrainStation() {
|
||||||
|
return trainStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTrainStation(Station trainStation) {
|
||||||
|
this.trainStation = trainStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Station getBusStation() {
|
||||||
|
return busStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBusStation(Station busStation) {
|
||||||
|
this.busStation = busStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getLocation() {
|
||||||
|
return this.location;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return name + "\n\tTrain Station: " + trainStation + "\n\tBus Station: " + busStation;
|
||||||
|
}
|
||||||
|
}
|
14
src/CityManager.java
Normal file
14
src/CityManager.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
80
src/Departure.java
Normal file
80
src/Departure.java
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import java.time.LocalTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
public class Departure {
|
||||||
|
private TransportType type;
|
||||||
|
private String from;
|
||||||
|
private String to;
|
||||||
|
private int duration;
|
||||||
|
private LocalTime departureTime;
|
||||||
|
private double price;
|
||||||
|
private int minTransferTime;
|
||||||
|
|
||||||
|
public Departure(
|
||||||
|
TransportType type,
|
||||||
|
String from,
|
||||||
|
String to,
|
||||||
|
String departureTime,
|
||||||
|
int duration,
|
||||||
|
double price,
|
||||||
|
int minTransferTime) {
|
||||||
|
this.type = type;
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.departureTime = LocalTime.parse(departureTime, DateTimeFormatter.ofPattern("HH:mm"));
|
||||||
|
this.duration = duration;
|
||||||
|
this.price = price;
|
||||||
|
this.minTransferTime = minTransferTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public City getDestinationCity() {
|
||||||
|
|
||||||
|
return CityManager.getCityByName(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTo() {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getPrice() {
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinTransferTime() {
|
||||||
|
return minTransferTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Departure{"
|
||||||
|
+ "type="
|
||||||
|
+ type
|
||||||
|
+ ", from='"
|
||||||
|
+ from
|
||||||
|
+ '\''
|
||||||
|
+ ", to='"
|
||||||
|
+ to
|
||||||
|
+ '\''
|
||||||
|
+ ", departureTime="
|
||||||
|
+ departureTime.format(DateTimeFormatter.ofPattern("HH:mm"))
|
||||||
|
+ ", duration="
|
||||||
|
+ duration
|
||||||
|
+ ", price="
|
||||||
|
+ price
|
||||||
|
+ ", minTransferTime="
|
||||||
|
+ minTransferTime
|
||||||
|
+ "}";
|
||||||
|
}
|
||||||
|
}
|
92
src/Graph.java
Normal file
92
src/Graph.java
Normal 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()];
|
||||||
|
}
|
||||||
|
}
|
@ -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.BufferedReader;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -12,20 +6,19 @@ 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);
|
||||||
* Retrieves the value associated with a given key from a JSON-like file.
|
for (City city : cities) {
|
||||||
* The value is expected to be an array, and the function extracts the array's content as a string.
|
System.out.println(city);
|
||||||
*
|
}
|
||||||
* @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))) {
|
||||||
@ -52,14 +45,6 @@ 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];
|
||||||
@ -71,13 +56,6 @@ 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);
|
||||||
@ -90,75 +68,67 @@ 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("\\|");
|
||||||
|
|
||||||
@ -182,7 +152,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("_");
|
||||||
@ -196,14 +166,28 @@ public class JsonParser {
|
|||||||
return cities;
|
return cities;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Way to slow for big sets of data because it has O(n*m)
|
||||||
* Loads departure data into the corresponding cities' stations.
|
public static List<City> loadDeparturesOld(List<City> cities, List<Departure> departures) {
|
||||||
* 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
|
|
||||||
* @param departures a list of {@link Departure} objects
|
for (City city : cities) {
|
||||||
* @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();
|
||||||
@ -222,11 +206,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,13 +218,6 @@ 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);
|
||||||
@ -261,12 +238,6 @@ 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)) {
|
||||||
@ -275,4 +246,4 @@ public class JsonParser {
|
|||||||
}
|
}
|
||||||
return TransportType.NOT_ASSIGNED;
|
return TransportType.NOT_ASSIGNED;
|
||||||
}
|
}
|
||||||
}
|
}
|
41
src/Location.java
Normal file
41
src/Location.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Location {
|
||||||
|
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
|
||||||
|
public Location(int x, int y) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(int x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY(int y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Location location = (Location) o;
|
||||||
|
return x == location.x && y == location.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(x, y);
|
||||||
|
}
|
||||||
|
}
|
6
src/Main.java
Normal file
6
src/Main.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
System.out.println("Hello World!");
|
||||||
|
}
|
||||||
|
}
|
36
src/Station.java
Normal file
36
src/Station.java
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Station {
|
||||||
|
|
||||||
|
private TransportType type = TransportType.NOT_ASSIGNED;
|
||||||
|
private String name;
|
||||||
|
private List<Departure> departures = new ArrayList<Departure>();
|
||||||
|
|
||||||
|
Station() {}
|
||||||
|
|
||||||
|
Station(TransportType type, String name) {
|
||||||
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Departure> getDepartures() {
|
||||||
|
return departures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDeparture(Departure departure) {
|
||||||
|
departures.add(departure);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Station{" + "type=" + type + ", name=" + name + ", departures=" + departures;
|
||||||
|
}
|
||||||
|
}
|
222
src/TransportDataGenerator.java
Normal file
222
src/TransportDataGenerator.java
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class TransportDataGenerator {
|
||||||
|
private static final int SIZE = 10;
|
||||||
|
private int n;
|
||||||
|
private int m;
|
||||||
|
|
||||||
|
private static final int DEPARTURES_PER_STATION = 1;
|
||||||
|
private static final Random random = new Random();
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
TransportDataGenerator generator = new TransportDataGenerator(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransportDataGenerator(int n) {
|
||||||
|
this.n = n;
|
||||||
|
this.m = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransportDataGenerator(int n, int m) {
|
||||||
|
this.n = n;
|
||||||
|
this.m = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
// struktura podataka koja sadrzi sve trazene ulazne podatke
|
||||||
|
public static class TransportData {
|
||||||
|
public String[][] countryMap;
|
||||||
|
public List<Station> stations;
|
||||||
|
public List<Departure> departures;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Station {
|
||||||
|
public String city;
|
||||||
|
public String busStation;
|
||||||
|
public String trainStation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Departure {
|
||||||
|
public String type; // "autobus" ili "voz"
|
||||||
|
public String from;
|
||||||
|
public String to;
|
||||||
|
public String departureTime;
|
||||||
|
public int duration; // u minutama
|
||||||
|
public int price;
|
||||||
|
public int minTransferTime; // vrijeme potrebno za transfer (u minutama)
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportData generateData() {
|
||||||
|
TransportData data = new TransportData();
|
||||||
|
data.countryMap = generateCountryMap();
|
||||||
|
data.stations = generateStations();
|
||||||
|
data.departures = generateDepartures(data.stations);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generisanje gradova (G_X_Y)
|
||||||
|
private String[][] generateCountryMap() {
|
||||||
|
String[][] countryMap = new String[n][m];
|
||||||
|
for (int x = 0; x < n; x++) {
|
||||||
|
for (int y = 0; y < m; y++) {
|
||||||
|
countryMap[x][y] = "G_" + x + "_" + y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return countryMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generisanje autobuskih i zeljeznickih stanica
|
||||||
|
private List<Station> generateStations() {
|
||||||
|
List<Station> stations = new ArrayList<>();
|
||||||
|
for (int x = 0; x < n; x++) {
|
||||||
|
for (int y = 0; y < m; y++) {
|
||||||
|
Station station = new Station();
|
||||||
|
station.city = "G_" + x + "_" + y;
|
||||||
|
station.busStation = "A_" + x + "_" + y;
|
||||||
|
station.trainStation = "Z_" + x + "_" + y;
|
||||||
|
stations.add(station);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stations;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generisanje vremena polazaka
|
||||||
|
private List<Departure> generateDepartures(List<Station> stations) {
|
||||||
|
List<Departure> departures = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Station station : stations) {
|
||||||
|
int x = Integer.parseInt(station.city.split("_")[1]);
|
||||||
|
int y = Integer.parseInt(station.city.split("_")[2]);
|
||||||
|
|
||||||
|
// generisanje polazaka autobusa
|
||||||
|
for (int i = 0; i < DEPARTURES_PER_STATION; i++) {
|
||||||
|
departures.add(generateDeparture("autobus", station.busStation, x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// generisanje polazaka vozova
|
||||||
|
for (int i = 0; i < DEPARTURES_PER_STATION; i++) {
|
||||||
|
departures.add(generateDeparture("voz", station.trainStation, x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return departures;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Departure generateDeparture(String type, String from, int x, int y) {
|
||||||
|
Departure departure = new Departure();
|
||||||
|
departure.type = type;
|
||||||
|
departure.from = from;
|
||||||
|
|
||||||
|
// generisanje susjeda
|
||||||
|
List<String> neighbors = getNeighbors(x, y);
|
||||||
|
departure.to = neighbors.isEmpty() ? from : neighbors.get(random.nextInt(neighbors.size()));
|
||||||
|
|
||||||
|
// generisanje vremena
|
||||||
|
int hour = random.nextInt(24);
|
||||||
|
int minute = random.nextInt(4) * 15; // 0, 15, 30, 45
|
||||||
|
departure.departureTime = String.format("%02d:%02d", hour, minute);
|
||||||
|
|
||||||
|
// geneirsanje cijene
|
||||||
|
departure.duration = 30 + random.nextInt(151);
|
||||||
|
departure.price = 100 + random.nextInt(901);
|
||||||
|
|
||||||
|
// generisanje vremena transfera
|
||||||
|
departure.minTransferTime = 5 + random.nextInt(26);
|
||||||
|
|
||||||
|
return departure;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pronalazak susjednih gradova
|
||||||
|
private List<String> getNeighbors(int x, int y) {
|
||||||
|
List<String> neighbors = new ArrayList<>();
|
||||||
|
int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
|
||||||
|
|
||||||
|
for (int[] dir : directions) {
|
||||||
|
int nx = x + dir[0];
|
||||||
|
int ny = y + dir[1];
|
||||||
|
if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
|
||||||
|
neighbors.add("G_" + nx + "_" + ny);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cuvanje podataka u JSON mapu
|
||||||
|
private void saveToJson(TransportData data, String filename) {
|
||||||
|
try (FileWriter file = new FileWriter(filename)) {
|
||||||
|
StringBuilder json = new StringBuilder();
|
||||||
|
json.append("{\n");
|
||||||
|
|
||||||
|
// mapa drzave
|
||||||
|
json.append(" \"countryMap\": [\n");
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
json.append(" [");
|
||||||
|
for (int j = 0; j < m; j++) {
|
||||||
|
json.append("\"").append(data.countryMap[i][j]).append("\"");
|
||||||
|
if (j < m - 1)
|
||||||
|
json.append(", ");
|
||||||
|
}
|
||||||
|
json.append("]");
|
||||||
|
if (i < n - 1)
|
||||||
|
json.append(",");
|
||||||
|
json.append("\n");
|
||||||
|
}
|
||||||
|
json.append(" ],\n");
|
||||||
|
|
||||||
|
// stanice
|
||||||
|
json.append(" \"stations\": [\n");
|
||||||
|
for (int i = 0; i < data.stations.size(); i++) {
|
||||||
|
Station s = data.stations.get(i);
|
||||||
|
json.append(" {\"city\": \"")
|
||||||
|
.append(s.city)
|
||||||
|
.append("\", \"busStation\": \"")
|
||||||
|
.append(s.busStation)
|
||||||
|
.append("\", \"trainStation\": \"")
|
||||||
|
.append(s.trainStation)
|
||||||
|
.append("\"}");
|
||||||
|
if (i < data.stations.size() - 1)
|
||||||
|
json.append(",");
|
||||||
|
json.append("\n");
|
||||||
|
}
|
||||||
|
json.append(" ],\n");
|
||||||
|
|
||||||
|
// vremena polazaka
|
||||||
|
json.append(" \"departures\": [\n");
|
||||||
|
for (int i = 0; i < data.departures.size(); i++) {
|
||||||
|
Departure d = data.departures.get(i);
|
||||||
|
json.append(" {\"type\": \"")
|
||||||
|
.append(d.type)
|
||||||
|
.append("\", \"from\": \"")
|
||||||
|
.append(d.from)
|
||||||
|
.append("\", \"to\": \"")
|
||||||
|
.append(d.to)
|
||||||
|
.append("\", \"departureTime\": \"")
|
||||||
|
.append(d.departureTime)
|
||||||
|
.append("\", \"duration\": ")
|
||||||
|
.append(d.duration)
|
||||||
|
.append(", \"price\": ")
|
||||||
|
.append(d.price)
|
||||||
|
.append(", \"minTransferTime\": ")
|
||||||
|
.append(d.minTransferTime)
|
||||||
|
.append("}");
|
||||||
|
if (i < data.departures.size() - 1)
|
||||||
|
json.append(",");
|
||||||
|
json.append("\n");
|
||||||
|
}
|
||||||
|
json.append(" ]\n");
|
||||||
|
|
||||||
|
json.append("}");
|
||||||
|
file.write(json.toString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/TransportType.java
Normal file
16
src/TransportType.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
public enum TransportType {
|
||||||
|
NOT_ASSIGNED("null"),
|
||||||
|
BUS("autobus"),
|
||||||
|
TRAIN("voz");
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
TransportType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
}
|
48
src/User.java
Normal file
48
src/User.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
public class User {
|
||||||
|
private String name;
|
||||||
|
private int id;
|
||||||
|
private Location location;
|
||||||
|
private Location destination;
|
||||||
|
|
||||||
|
private static int idCounter = 1;
|
||||||
|
// :TODO:
|
||||||
|
private static final String ID_FILE = "id_counter.txt";
|
||||||
|
|
||||||
|
public User(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.id = idCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocation(Location location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Location getDestination() {
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestination(Location destination) {
|
||||||
|
this.destination = destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "User{id=" + id + ", name='" + name + "'}";
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer;
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
}
|
|
@ -1,333 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.app;
|
|
||||||
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
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 {
|
|
||||||
|
|
||||||
// Default grid size
|
|
||||||
private static final int SIZE = 10;
|
|
||||||
|
|
||||||
// Number of rows and columns in the generated map
|
|
||||||
private int n;
|
|
||||||
private int m;
|
|
||||||
|
|
||||||
// Default number of departures per station
|
|
||||||
private static final int DEPARTURES_DEFAULT = 3;
|
|
||||||
private static int DEPARTURES_PER_STATION = DEPARTURES_DEFAULT;
|
|
||||||
|
|
||||||
// Random number generator for data generation
|
|
||||||
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) {
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
TransportDataGenerator generator = new TransportDataGenerator(n, m);
|
|
||||||
DEPARTURES_PER_STATION = departures;
|
|
||||||
TransportData data = generator.generateData();
|
|
||||||
generator.saveToJson(data, "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() {
|
|
||||||
this.n = 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) {
|
|
||||||
this.n = 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) {
|
|
||||||
this.n = n;
|
|
||||||
this.m = m;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 String[][] countryMap;
|
|
||||||
public List<Station> stations;
|
|
||||||
public List<Departure> departures;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a station, which includes the city and the corresponding bus and train stations.
|
|
||||||
*/
|
|
||||||
public static class Station {
|
|
||||||
public String city;
|
|
||||||
public String busStation;
|
|
||||||
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 String type; // "autobus" or "voz"
|
|
||||||
public String from;
|
|
||||||
public String to;
|
|
||||||
public String departureTime;
|
|
||||||
public int duration; // in minutes
|
|
||||||
public int price;
|
|
||||||
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() {
|
|
||||||
TransportData data = new TransportData();
|
|
||||||
data.countryMap = generateCountryMap();
|
|
||||||
data.stations = generateStations();
|
|
||||||
data.departures = generateDepartures(data.stations);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() {
|
|
||||||
String[][] countryMap = new String[n][m];
|
|
||||||
for (int x = 0; x < n; x++) {
|
|
||||||
for (int y = 0; y < m; y++) {
|
|
||||||
countryMap[x][y] = "G_" + x + "_" + y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return countryMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the list of stations (bus and train) for each city in the grid.
|
|
||||||
*
|
|
||||||
* @return the list of generated stations
|
|
||||||
*/
|
|
||||||
private List<Station> generateStations() {
|
|
||||||
List<Station> stations = new ArrayList<>();
|
|
||||||
for (int x = 0; x < n; x++) {
|
|
||||||
for (int y = 0; y < m; y++) {
|
|
||||||
Station station = new Station();
|
|
||||||
station.city = "G_" + x + "_" + y;
|
|
||||||
station.busStation = "A_" + x + "_" + y;
|
|
||||||
station.trainStation = "Z_" + x + "_" + y;
|
|
||||||
stations.add(station);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
List<Departure> departures = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Station station : stations) {
|
|
||||||
int x = Integer.parseInt(station.city.split("_")[1]);
|
|
||||||
int y = Integer.parseInt(station.city.split("_")[2]);
|
|
||||||
|
|
||||||
// Generate bus departures
|
|
||||||
for (int i = 0; i < DEPARTURES_PER_STATION; i++) {
|
|
||||||
departures.add(generateDeparture("autobus", station.busStation, x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate train departures
|
|
||||||
for (int i = 0; i < DEPARTURES_PER_STATION; i++) {
|
|
||||||
departures.add(generateDeparture("voz", station.trainStation, x, y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
Departure departure = new Departure();
|
|
||||||
departure.type = type;
|
|
||||||
departure.from = from;
|
|
||||||
|
|
||||||
// Generate neighboring cities
|
|
||||||
List<String> neighbors = getNeighbors(x, y);
|
|
||||||
departure.to = neighbors.isEmpty() ? from : neighbors.get(random.nextInt(neighbors.size()));
|
|
||||||
|
|
||||||
// Generate departure time
|
|
||||||
int hour = random.nextInt(24);
|
|
||||||
int minute = random.nextInt(4) * 15; // 0, 15, 30, 45
|
|
||||||
departure.departureTime = String.format("%02d:%02d", hour, minute);
|
|
||||||
|
|
||||||
// Generate duration (in minutes)
|
|
||||||
departure.duration = 30 + random.nextInt(151);
|
|
||||||
|
|
||||||
// Generate price (in currency units)
|
|
||||||
departure.price = 100 + random.nextInt(901);
|
|
||||||
|
|
||||||
// Generate minimum transfer time (in minutes)
|
|
||||||
departure.minTransferTime = 5 + random.nextInt(26);
|
|
||||||
|
|
||||||
return departure;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
List<String> neighbors = new ArrayList<>();
|
|
||||||
int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
|
|
||||||
|
|
||||||
for (int[] dir : directions) {
|
|
||||||
int nx = x + dir[0];
|
|
||||||
int ny = y + dir[1];
|
|
||||||
if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
|
|
||||||
neighbors.add("G_" + nx + "_" + ny);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return neighbors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
try (FileWriter file = new FileWriter(filename)) {
|
|
||||||
StringBuilder json = new StringBuilder();
|
|
||||||
json.append("{\n");
|
|
||||||
|
|
||||||
// Add country map
|
|
||||||
json.append(" \"countryMap\": [\n");
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
json.append(" [");
|
|
||||||
for (int j = 0; j < m; j++) {
|
|
||||||
json.append("\"").append(data.countryMap[i][j]).append("\"");
|
|
||||||
if (j < m - 1)
|
|
||||||
json.append(", ");
|
|
||||||
}
|
|
||||||
json.append("]");
|
|
||||||
if (i < n - 1)
|
|
||||||
json.append(",");
|
|
||||||
json.append("\n");
|
|
||||||
}
|
|
||||||
json.append(" ],\n");
|
|
||||||
|
|
||||||
// Add stations
|
|
||||||
json.append(" \"stations\": [\n");
|
|
||||||
for (int i = 0; i < data.stations.size(); i++) {
|
|
||||||
Station s = data.stations.get(i);
|
|
||||||
json.append(" {\"city\": \"")
|
|
||||||
.append(s.city)
|
|
||||||
.append("\", \"busStation\": \"")
|
|
||||||
.append(s.busStation)
|
|
||||||
.append("\", \"trainStation\": \"")
|
|
||||||
.append(s.trainStation)
|
|
||||||
.append("\"}");
|
|
||||||
if (i < data.stations.size() - 1)
|
|
||||||
json.append(",");
|
|
||||||
json.append("\n");
|
|
||||||
}
|
|
||||||
json.append(" ],\n");
|
|
||||||
|
|
||||||
// Add departures
|
|
||||||
json.append(" \"departures\": [\n");
|
|
||||||
for (int i = 0; i < data.departures.size(); i++) {
|
|
||||||
Departure d = data.departures.get(i);
|
|
||||||
json.append(" {\"type\": \"")
|
|
||||||
.append(d.type)
|
|
||||||
.append("\", \"from\": \"")
|
|
||||||
.append(d.from)
|
|
||||||
.append("\", \"to\": \"")
|
|
||||||
.append(d.to)
|
|
||||||
.append("\", \"departureTime\": \"")
|
|
||||||
.append(d.departureTime)
|
|
||||||
.append("\", \"duration\": ")
|
|
||||||
.append(d.duration)
|
|
||||||
.append(", \"price\": ")
|
|
||||||
.append(d.price)
|
|
||||||
.append(", \"minTransferTime\": ")
|
|
||||||
.append(d.minTransferTime)
|
|
||||||
.append("}");
|
|
||||||
if (i < data.departures.size() - 1)
|
|
||||||
json.append(",");
|
|
||||||
json.append("\n");
|
|
||||||
}
|
|
||||||
json.append(" ]\n");
|
|
||||||
|
|
||||||
json.append("}");
|
|
||||||
file.write(json.toString());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
public void start(Stage stage) throws IOException {
|
|
||||||
// Load and initialize the ticket counter (profit and tickets sold)
|
|
||||||
TicketPrinter.loadCounter();
|
|
||||||
System.out.println(TicketPrinter.getTotalProfit() + " " + TicketPrinter.getTicketsSoldNum());
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
// Create the main scene with the loaded FXML layout
|
|
||||||
Scene scene = new Scene(fxmlLoader.load());
|
|
||||||
|
|
||||||
// Set the application's window icon
|
|
||||||
Image image = new Image(getClass().getResourceAsStream("/images/img1.jpg"));
|
|
||||||
scene.getStylesheets().add(css); // Add the CSS stylesheet to the scene
|
|
||||||
stage.getIcons().add(image); // Set the application icon
|
|
||||||
|
|
||||||
// Set the window title
|
|
||||||
stage.setTitle("Hello!");
|
|
||||||
|
|
||||||
// Set the scene for the stage (window) and show the stage
|
|
||||||
stage.setScene(scene);
|
|
||||||
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) {
|
|
||||||
launch();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,639 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.controller;
|
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.app.TransportDataGenerator;
|
|
||||||
import dev.ksan.travelpathoptimizer.graphSimulation.GraphSimulation;
|
|
||||||
import dev.ksan.travelpathoptimizer.graphSimulation.PathResult;
|
|
||||||
import dev.ksan.travelpathoptimizer.model.City;
|
|
||||||
import dev.ksan.travelpathoptimizer.model.Departure;
|
|
||||||
import dev.ksan.travelpathoptimizer.model.Location;
|
|
||||||
import dev.ksan.travelpathoptimizer.model.TransportType;
|
|
||||||
import dev.ksan.travelpathoptimizer.service.CityManager;
|
|
||||||
import dev.ksan.travelpathoptimizer.util.JsonParser;
|
|
||||||
import dev.ksan.travelpathoptimizer.util.TicketPrinter;
|
|
||||||
import dev.ksan.travelpathoptimizer.visualize.GraphVisualizer;
|
|
||||||
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;
|
|
||||||
import org.graphstream.graph.Graph;
|
|
||||||
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 {
|
|
||||||
|
|
||||||
// UI Elements (FXML)
|
|
||||||
@FXML private HBox graphPane;
|
|
||||||
@FXML private GridPane map;
|
|
||||||
@FXML private Label welcomeText;
|
|
||||||
@FXML private Text selectedFileText;
|
|
||||||
@FXML private Button mapSelectButton;
|
|
||||||
@FXML private TextField startCityText;
|
|
||||||
@FXML private TextField endCityText;
|
|
||||||
@FXML private Button startCityButton;
|
|
||||||
@FXML private Button endCityButton;
|
|
||||||
@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;
|
|
||||||
@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;
|
|
||||||
|
|
||||||
// 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 GraphVisualizer visualizer;
|
|
||||||
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
|
|
||||||
void showGraph() {
|
|
||||||
graph.clear();
|
|
||||||
|
|
||||||
if (map.isVisible()) {
|
|
||||||
map.setVisible(false);
|
|
||||||
map.setManaged(false);
|
|
||||||
graphPane.setVisible(true);
|
|
||||||
graphPane.setManaged(true);
|
|
||||||
} else {
|
|
||||||
graphPane.setManaged(false);
|
|
||||||
graphPane.setVisible(false);
|
|
||||||
|
|
||||||
map.setManaged(true);
|
|
||||||
map.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (City[] row : cities) {
|
|
||||||
for (City city : row) {
|
|
||||||
if (city != null) {
|
|
||||||
graph.addNode(city.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (City[] row : cities) {
|
|
||||||
for (City city : row) {
|
|
||||||
if (city != null) {
|
|
||||||
for (Departure dep : city.getDestinations()) {
|
|
||||||
City destinationCity = dep.getDestinationCity();
|
|
||||||
if (destinationCity != null) {
|
|
||||||
if (!city.getName().equals(destinationCity.getName())) {
|
|
||||||
String edgeId =
|
|
||||||
city.getName() + "-" + destinationCity.getName() + "-" + dep.getIdCounter();
|
|
||||||
|
|
||||||
if (graph.getEdge(edgeId) != null) {
|
|
||||||
System.out.println("Edge already exists: " + edgeId);
|
|
||||||
System.out.println("skip");
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
graph.addEdge(edgeId, city.getName(), destinationCity.getName(), true);
|
|
||||||
System.out.println(
|
|
||||||
"Added directed edge: "
|
|
||||||
+ edgeId
|
|
||||||
+ " from "
|
|
||||||
+ city.getName()
|
|
||||||
+ " to "
|
|
||||||
+ destinationCity.getName());
|
|
||||||
} catch (org.graphstream.graph.EdgeRejectedException e) {
|
|
||||||
System.out.println(
|
|
||||||
"Edge rejected: "
|
|
||||||
+ edgeId
|
|
||||||
+ " from "
|
|
||||||
+ city.getName()
|
|
||||||
+ " to "
|
|
||||||
+ destinationCity.getName());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
visualizer.showGraph();
|
|
||||||
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
|
|
||||||
private void buyTicket() {
|
|
||||||
|
|
||||||
TicketPrinter printer = new TicketPrinter();
|
|
||||||
printer.generateTicketReceipt(
|
|
||||||
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
|
|
||||||
private void findTopPaths() {
|
|
||||||
graphSimulation.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 {
|
|
||||||
graphSimulation.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());
|
|
||||||
graphSimulation.calculateTopPaths(
|
|
||||||
startCity,
|
|
||||||
endCity,
|
|
||||||
path,
|
|
||||||
totalCost,
|
|
||||||
currentTime,
|
|
||||||
departures,
|
|
||||||
categoryBox.getValue().toString(), TransportType.NOT_ASSIGNED);
|
|
||||||
|
|
||||||
System.out.println(graphSimulation.getTopPaths().size());
|
|
||||||
System.out.println(startCity.getName() + endCity.getName());
|
|
||||||
if (graphSimulation.getTopPaths().isEmpty()) return null;
|
|
||||||
Platform.runLater(
|
|
||||||
() -> {
|
|
||||||
for (PathResult pathResult : graphSimulation.getSortedPaths()) {
|
|
||||||
pathChoiceBox.getItems().add("Route: " + String.valueOf(pathResult.getId()));
|
|
||||||
}
|
|
||||||
pathChoiceBox.setValue(
|
|
||||||
"Route: "
|
|
||||||
+ String.valueOf(graphSimulation.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();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 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() {
|
|
||||||
|
|
||||||
ObservableList<Departure> departureList = FXCollections.observableArrayList();
|
|
||||||
while (pathChoiceBox == null) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(10);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (graphSimulation.getTopPaths().size() > 0) {
|
|
||||||
Optional<List<Integer>> departuresOpt =
|
|
||||||
graphSimulation.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);
|
|
||||||
tempDepartureList.clear();
|
|
||||||
tempDepartureList = 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!");
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Toggles the visibility of the "Route View" section, which shows the available paths and their details.
|
|
||||||
*/
|
|
||||||
@FXML
|
|
||||||
private void showRouteView() {
|
|
||||||
boolean visible = routeView.isVisible();
|
|
||||||
routeView.setVisible(!visible);
|
|
||||||
routeView.setManaged(!visible);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Toggles the visibility of the random sidebar, tbh forgot this part.
|
|
||||||
*/
|
|
||||||
@FXML
|
|
||||||
void showRandomSideBar() {
|
|
||||||
boolean visible = randomSideBar.isVisible();
|
|
||||||
randomSideBar.setVisible(!visible);
|
|
||||||
randomSideBar.setManaged(!visible);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Toggles the visibility of the map sidebar, which contains options for selecting a map or file.
|
|
||||||
*/
|
|
||||||
@FXML
|
|
||||||
void showMapSideBar() {
|
|
||||||
boolean visible = mapSideBar.isVisible();
|
|
||||||
mapSideBar.setVisible(!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() {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
private void selectStart() {
|
|
||||||
this.selectingEnd = false;
|
|
||||||
this.selectingStart = true;
|
|
||||||
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
|
|
||||||
private void selectEnd() {
|
|
||||||
this.selectingStart = false;
|
|
||||||
this.selectingEnd = true;
|
|
||||||
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
|
|
||||||
public void initialize() {
|
|
||||||
visualizer = new GraphVisualizer(graph, graphPane);
|
|
||||||
pathChoiceBox.setOnAction(
|
|
||||||
event -> {
|
|
||||||
updateUiGetList();
|
|
||||||
|
|
||||||
Platform.runLater(
|
|
||||||
() -> {
|
|
||||||
visualizer.highlightPath(tempDepartureList);
|
|
||||||
});
|
|
||||||
// visualizer.highlightPath(tempDepartureList);
|
|
||||||
});
|
|
||||||
|
|
||||||
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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
double totalCost = 0.0;
|
|
||||||
for (Departure dep : depList) {
|
|
||||||
totalCost += dep.getPrice();
|
|
||||||
}
|
|
||||||
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
|
|
||||||
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()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 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() {
|
|
||||||
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.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
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,306 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.graphSimulation;
|
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.model.City;
|
|
||||||
import dev.ksan.travelpathoptimizer.model.Departure;
|
|
||||||
import dev.ksan.travelpathoptimizer.model.Location;
|
|
||||||
import dev.ksan.travelpathoptimizer.model.TransportType;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.LocalTime;
|
|
||||||
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 {
|
|
||||||
|
|
||||||
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());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the list of top 5 paths sorted by cost in ascending order.
|
|
||||||
*
|
|
||||||
* @return a list of the top 5 path results sorted by cost.
|
|
||||||
*/
|
|
||||||
public List<PathResult> getSortedPaths() {
|
|
||||||
List<PathResult> pathList = new ArrayList<>(topPaths);
|
|
||||||
pathList.sort(Comparator.comparingDouble(PathResult::getCost));
|
|
||||||
return pathList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Resets the simulation, clearing all paths, visited routes, and top paths. */
|
|
||||||
public void reset() {
|
|
||||||
topPaths.clear();
|
|
||||||
pathIdCounter = 1;
|
|
||||||
nextid = 0;
|
|
||||||
allPaths.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) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (Integer depId : departures) {
|
|
||||||
sb.append(depId).append("-");
|
|
||||||
}
|
|
||||||
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(
|
|
||||||
City currentCity,
|
|
||||||
City endCity,
|
|
||||||
List<City> path,
|
|
||||||
double totalCost,
|
|
||||||
LocalTime currentTime,
|
|
||||||
List<Integer> departures,
|
|
||||||
String type,
|
|
||||||
TransportType lastType) {
|
|
||||||
|
|
||||||
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 += duration.toMinutes();
|
|
||||||
|
|
||||||
if (lastType == TransportType.NOT_ASSIGNED) {
|
|
||||||
|
|
||||||
cost += dep.getMinTransferTime();
|
|
||||||
} else if (lastType != dep.getType()) {
|
|
||||||
|
|
||||||
cost += dep.getMinTransferTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
// cost += dep.getMinTransferTime();
|
|
||||||
} else if (type.equals("price")) {
|
|
||||||
cost += dep.getPrice();
|
|
||||||
} else if (type.equals("hops")) {
|
|
||||||
cost++;
|
|
||||||
/*if(!(lastType == dep.getType())){
|
|
||||||
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, dep.getType());
|
|
||||||
|
|
||||||
departures.remove(departures.size() - 1);
|
|
||||||
path.remove(path.size() - 1);
|
|
||||||
if (type.equals("hops")) {
|
|
||||||
cost--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Prints the top 5 paths to the console. */
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the shortest path between two cities using a specified cost metric (e.g., price,
|
|
||||||
* time, hops).
|
|
||||||
*
|
|
||||||
* @param startCity the starting city of the path.
|
|
||||||
* @param endCity the destination city of the path.
|
|
||||||
* @param type the type of cost metric to use ("price", "time", or "hops").
|
|
||||||
* @return a map where the keys are city locations and the values are the shortest cost to that
|
|
||||||
* location.
|
|
||||||
*/
|
|
||||||
// old function used just for testing (missing come features and not used in the final product)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the list of all paths found during the simulation.
|
|
||||||
*
|
|
||||||
* @return a list of all PathResult objects representing the paths.
|
|
||||||
*/
|
|
||||||
public List<PathResult> getAllPaths() {
|
|
||||||
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) {
|
|
||||||
this.matrix = matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the city matrix used in the simulation.
|
|
||||||
*
|
|
||||||
* @param matrix the new 2D array of cities.
|
|
||||||
*/
|
|
||||||
public void updateMatrix(City[][] matrix) {
|
|
||||||
this.matrix = matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current matrix of cities used in the simulation.
|
|
||||||
*
|
|
||||||
* @return the current 2D array of cities.
|
|
||||||
*/
|
|
||||||
public City[][] getMatrix() {
|
|
||||||
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) {
|
|
||||||
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() {
|
|
||||||
return topPaths;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.graphSimulation;
|
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.model.City;
|
|
||||||
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
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 {
|
|
||||||
|
|
||||||
private int id;
|
|
||||||
private List<City> path = new ArrayList<>();
|
|
||||||
private List<Integer> departuresUsed = new ArrayList<>();
|
|
||||||
private double cost;
|
|
||||||
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) {
|
|
||||||
this.id = id;
|
|
||||||
this.path = path;
|
|
||||||
this.departuresUsed = departuresUsed;
|
|
||||||
this.cost = cost;
|
|
||||||
this.arrivalTime = arrivalTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the unique identifier for the path result.
|
|
||||||
*
|
|
||||||
* @return the unique identifier of the path result.
|
|
||||||
*/
|
|
||||||
public int getId() {
|
|
||||||
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() {
|
|
||||||
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() {
|
|
||||||
return departuresUsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the total cost of the journey represented by this path result.
|
|
||||||
*
|
|
||||||
* @return the total cost of the journey.
|
|
||||||
*/
|
|
||||||
public double getCost() {
|
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the arrival time at the destination.
|
|
||||||
*
|
|
||||||
* @return a LocalTime object representing the arrival time.
|
|
||||||
*/
|
|
||||||
public LocalTime getArrivalTime() {
|
|
||||||
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
|
|
||||||
public String toString() {
|
|
||||||
return "PathResult{id=" + id + " cost = " + cost + ", path=" + path + ", arrivalTime=" + arrivalTime + '}';
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.model;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a city with associated transportation stations (train and bus)
|
|
||||||
* and its location.
|
|
||||||
*/
|
|
||||||
public class City {
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
private Station trainStation;
|
|
||||||
private Station busStation;
|
|
||||||
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) {
|
|
||||||
this.name = name;
|
|
||||||
this.trainStation = new Station(TransportType.TRAIN, train);
|
|
||||||
this.busStation = new Station(TransportType.BUS, bus);
|
|
||||||
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) {
|
|
||||||
this.name = name;
|
|
||||||
this.trainStation = train;
|
|
||||||
this.busStation = bus;
|
|
||||||
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() {
|
|
||||||
List<Departure> departures = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Departure dep : busStation.getDepartures()) {
|
|
||||||
departures.add(dep);
|
|
||||||
}
|
|
||||||
for (Departure dep : trainStation.getDepartures()) {
|
|
||||||
departures.add(dep);
|
|
||||||
}
|
|
||||||
|
|
||||||
return departures;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the name of the city.
|
|
||||||
*
|
|
||||||
* @return the name of the city.
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the name of the city.
|
|
||||||
*
|
|
||||||
* @param name the name to set for the city.
|
|
||||||
*/
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the train station of the city.
|
|
||||||
*
|
|
||||||
* @return the train station of the city.
|
|
||||||
*/
|
|
||||||
public Station getTrainStation() {
|
|
||||||
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) {
|
|
||||||
this.trainStation = trainStation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the bus station of the city.
|
|
||||||
*
|
|
||||||
* @return the bus station of the city.
|
|
||||||
*/
|
|
||||||
public Station getBusStation() {
|
|
||||||
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) {
|
|
||||||
this.busStation = busStation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the geographic location of the city.
|
|
||||||
*
|
|
||||||
* @return the Location object representing the city's location.
|
|
||||||
*/
|
|
||||||
public Location getLocation() {
|
|
||||||
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
|
|
||||||
public String toString() {
|
|
||||||
return name + "\n\tTrain Station: " + trainStation + "\n\tBus Station: " + busStation;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.model;
|
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.service.CityManager;
|
|
||||||
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
public class Departure {
|
|
||||||
private TransportType type;
|
|
||||||
private String from;
|
|
||||||
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,
|
|
||||||
String to,
|
|
||||||
String departureTime,
|
|
||||||
int duration,
|
|
||||||
double price,
|
|
||||||
int minTransferTime) {
|
|
||||||
this.id = idCounter++;
|
|
||||||
this.type = type;
|
|
||||||
this.from = from;
|
|
||||||
this.to = to;
|
|
||||||
this.departureTime = LocalTime.parse(departureTime, DateTimeFormatter.ofPattern("HH:mm"));
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocalTime getDepartureTime() {
|
|
||||||
return departureTime;
|
|
||||||
}
|
|
||||||
public LocalTime getArrivalTime() {
|
|
||||||
return arrivalTime;
|
|
||||||
}
|
|
||||||
public TransportType getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFrom() {
|
|
||||||
return from;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTo() {
|
|
||||||
return to;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDuration() {
|
|
||||||
return duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getPrice() {
|
|
||||||
return price;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMinTransferTime() {
|
|
||||||
return minTransferTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Departure{"
|
|
||||||
+ "type="
|
|
||||||
+ type
|
|
||||||
+ ", from='"
|
|
||||||
+ from
|
|
||||||
+ '\''
|
|
||||||
+ ", to='"
|
|
||||||
+ to
|
|
||||||
+ '\''
|
|
||||||
+ ", departureTime="
|
|
||||||
+ departureTime.format(DateTimeFormatter.ofPattern("HH:mm"))
|
|
||||||
+ ", duration="
|
|
||||||
+ duration
|
|
||||||
+ ", price="
|
|
||||||
+ price
|
|
||||||
+ ", minTransferTime="
|
|
||||||
+ minTransferTime
|
|
||||||
+ "}";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.model;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
|
|
||||||
private int x;
|
|
||||||
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) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the x-coordinate of this location.
|
|
||||||
*
|
|
||||||
* @return the x-coordinate
|
|
||||||
*/
|
|
||||||
public int getX() {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the x-coordinate of this location.
|
|
||||||
*
|
|
||||||
* @param x the new x-coordinate
|
|
||||||
*/
|
|
||||||
public void setX(int x) {
|
|
||||||
this.x = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the y-coordinate of this location.
|
|
||||||
*
|
|
||||||
* @return the y-coordinate
|
|
||||||
*/
|
|
||||||
public int getY() {
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the y-coordinate of this location.
|
|
||||||
*
|
|
||||||
* @param y the new y-coordinate
|
|
||||||
*/
|
|
||||||
public void setY(int 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
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
Location location = (Location) o;
|
|
||||||
return x == location.x && y == location.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
public int hashCode() {
|
|
||||||
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
|
|
||||||
public String toString() {
|
|
||||||
return x + "_" + y;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.model;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
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 {
|
|
||||||
|
|
||||||
private TransportType type = TransportType.NOT_ASSIGNED;
|
|
||||||
private String name;
|
|
||||||
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() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
this.type = type;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the transport type of this station (e.g., train, bus).
|
|
||||||
*
|
|
||||||
* @return the transport type of the station
|
|
||||||
*/
|
|
||||||
public TransportType getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the name of this station.
|
|
||||||
*
|
|
||||||
* @return the name of the station
|
|
||||||
*/
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the list of departures from this station.
|
|
||||||
*
|
|
||||||
* @return a list of Departure objects associated with this station
|
|
||||||
*/
|
|
||||||
public List<Departure> getDepartures() {
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
public String toString() {
|
|
||||||
return "Station{" + "type=" + type + ", name=" + name + ", departures=" + departures + "}";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
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 {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents an unassigned transport type. This is used as a placeholder.
|
|
||||||
*/
|
|
||||||
NOT_ASSIGNED("null"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a bus transport type.
|
|
||||||
*/
|
|
||||||
BUS("autobus"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a train transport type.
|
|
||||||
*/
|
|
||||||
TRAIN("voz");
|
|
||||||
|
|
||||||
private final String type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a TransportType with the specified string representation.
|
|
||||||
*
|
|
||||||
* @param type the string representation of the transport type
|
|
||||||
*/
|
|
||||||
TransportType(String 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
|
|
||||||
public String toString() {
|
|
||||||
return this.type;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() {
|
|
||||||
citiesByLocation.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) {
|
|
||||||
cities.put(city.getName(), city); // Add city by name
|
|
||||||
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) {
|
|
||||||
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) {
|
|
||||||
return cities.get(cityName); // Get city by name
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,168 +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;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.file.*;
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
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");
|
|
||||||
receipt.append("Date: ").append(currentDate).append("\n");
|
|
||||||
receipt.append("From: ").append(departures.get(0).getFrom()).append("\n");
|
|
||||||
receipt.append("To: ").append(departures.get(departures.size() - 1).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();
|
|
||||||
saveCounter();
|
|
||||||
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) {
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensures the receipts directory exists. If not, it creates the directory.
|
|
||||||
*/
|
|
||||||
private static void folderExists() {
|
|
||||||
Path path = Paths.get(RECEIPTS_DIRECTORY);
|
|
||||||
|
|
||||||
if (!Files.exists(path)) {
|
|
||||||
try {
|
|
||||||
Files.createDirectory(path);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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() {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the total profit accumulated from ticket sales.
|
|
||||||
*
|
|
||||||
* @return the total profit
|
|
||||||
*/
|
|
||||||
public static double getTotalProfit() {
|
|
||||||
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() {
|
|
||||||
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() {
|
|
||||||
try {
|
|
||||||
String str = "ticketIdCounter=" + ticketIdCounter + "\n" + "totalProfit=" + totalProfit;
|
|
||||||
Files.write(Paths.get(COUNTER_FILE), str.getBytes());
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next available ticket ID by incrementing the current ticket ID counter.
|
|
||||||
*
|
|
||||||
* @return the next ticket ID
|
|
||||||
*/
|
|
||||||
private static int getNextId() {
|
|
||||||
return ++ticketIdCounter;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,124 +0,0 @@
|
|||||||
package dev.ksan.travelpathoptimizer.visualize;
|
|
||||||
|
|
||||||
import dev.ksan.travelpathoptimizer.model.Departure;
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import javafx.scene.layout.HBox;
|
|
||||||
import org.graphstream.graph.Edge;
|
|
||||||
import org.graphstream.graph.Graph;
|
|
||||||
import org.graphstream.graph.Node;
|
|
||||||
import org.graphstream.ui.fx_viewer.FxDefaultView;
|
|
||||||
import org.graphstream.ui.fx_viewer.FxViewer;
|
|
||||||
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 {
|
|
||||||
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
// The graph to be visualized
|
|
||||||
private Graph graph;
|
|
||||||
|
|
||||||
// The HBox container in which the graph view will be displayed
|
|
||||||
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) {
|
|
||||||
this.graph = graph;
|
|
||||||
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() {
|
|
||||||
// Set the stylesheet for the graph visualization
|
|
||||||
graph.setAttribute("ui.stylesheet", "url('" + cssFile + "')");
|
|
||||||
|
|
||||||
// Label each node with its ID
|
|
||||||
for (Node node : graph) {
|
|
||||||
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.enableAutoLayout();
|
|
||||||
|
|
||||||
// Add a default view to the viewer and add it to the container
|
|
||||||
FxDefaultView view = (FxDefaultView) viewer.addDefaultView(false);
|
|
||||||
container.getChildren().clear();
|
|
||||||
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) {
|
|
||||||
// Lists to hold nodes and edges to be highlighted
|
|
||||||
List<String> nodes = new ArrayList<>();
|
|
||||||
List<String> edges = new ArrayList<>();
|
|
||||||
|
|
||||||
// Remove any existing highlight from all nodes and edges
|
|
||||||
for (Node node : graph) {
|
|
||||||
node.removeAttribute("ui.class");
|
|
||||||
}
|
|
||||||
for (int i = 0; i < graph.getEdgeCount(); i++) {
|
|
||||||
Edge edge = graph.getEdge(i);
|
|
||||||
edge.removeAttribute("ui.class");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect nodes and edges to highlight based on the departures list
|
|
||||||
for (Departure dep : departures) {
|
|
||||||
String from = dep.getFrom();
|
|
||||||
from = from.replaceAll("[A-Z]", "G"); // Adjust formatting
|
|
||||||
if (!nodes.contains(from)) nodes.add(from);
|
|
||||||
|
|
||||||
if (!nodes.contains(dep.getTo())) nodes.add(dep.getTo());
|
|
||||||
edges.add(from + "-" + dep.getTo() + "-" + dep.getIdCounter());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print nodes for debugging
|
|
||||||
for (String nodeId : nodes) {
|
|
||||||
System.out.println(nodeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the highlight to nodes
|
|
||||||
for (String nodeId : nodes) {
|
|
||||||
Node node = graph.getNode(nodeId);
|
|
||||||
if (node != null) {
|
|
||||||
node.setAttribute("ui.class", "highlighted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the highlight to edges
|
|
||||||
for (int i = 0; i < edges.size(); i++) {
|
|
||||||
String from = nodes.get(i);
|
|
||||||
String to = nodes.get(i + 1);
|
|
||||||
|
|
||||||
Edge edge = graph.getEdge(edges.get(i));
|
|
||||||
|
|
||||||
if (edge != null) {
|
|
||||||
edge.setAttribute("ui.class", "highlighted");
|
|
||||||
} else {
|
|
||||||
System.out.println("Edge not found between " + from + " and " + to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
module dev.ksan.travelpathoptimizer {
|
|
||||||
requires javafx.controls;
|
|
||||||
requires javafx.fxml;
|
|
||||||
requires java.desktop;
|
|
||||||
requires javafx.graphics;
|
|
||||||
requires javafx.base;
|
|
||||||
requires gs.core;
|
|
||||||
requires gs.ui.javafx;
|
|
||||||
|
|
||||||
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.graphSimulation;
|
|
||||||
|
|
||||||
opens dev.ksan.travelpathoptimizer.graphSimulation to
|
|
||||||
javafx.fxml;
|
|
||||||
|
|
||||||
exports dev.ksan.travelpathoptimizer.visualize to javafx.graphics;
|
|
||||||
}
|
|
@ -1,46 +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;
|
|
||||||
}
|
|
||||||
|
|
||||||
graphPane{
|
|
||||||
-fx-background-color: red;
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
|||||||
node {
|
|
||||||
size: 12px;
|
|
||||||
shape: box;
|
|
||||||
text-alignment: under;
|
|
||||||
fill-color: #4a148c;
|
|
||||||
text-color: #980b0b;
|
|
||||||
text-background-mode: rounded-box;
|
|
||||||
text-background-color: #333;
|
|
||||||
text-padding: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
edge {
|
|
||||||
size: 2px;
|
|
||||||
fill-color: #979797;
|
|
||||||
arrow-shape: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
edge.highlighted {
|
|
||||||
fill-color: green;
|
|
||||||
size: 3px;
|
|
||||||
}
|
|
||||||
node.highlighted {
|
|
||||||
fill-color: green;
|
|
||||||
}
|
|
@ -1,237 +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="Useless Button" />
|
|
||||||
<Label style="-fx-font-size: 20px; -fx-text-fill: gray;" text="|" />
|
|
||||||
<Button fx:id="headerButton3" onAction="#showGraph" text="Show Graph" />
|
|
||||||
</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>
|
|
||||||
<HBox fx:id="graphPane" managed="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" visible="false" />
|
|
||||||
<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>
|
|
@ -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 |
Loading…
x
Reference in New Issue
Block a user