Initial commit of Mesos Java project
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
target/
|
||||
.idea/
|
||||
*.iml
|
||||
logs/
|
||||
316
mvnw
vendored
Normal file
@@ -0,0 +1,316 @@
|
||||
#!/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
Normal file
@@ -0,0 +1,188 @@
|
||||
@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%
|
||||
112
pom.xml
Normal file
@@ -0,0 +1,112 @@
|
||||
<?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>org.example</groupId>
|
||||
<artifactId>Mesos2</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<name>MesosLL07</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<junit.version>5.12.1</junit.version>
|
||||
<javafx.version>21.0.6</javafx.version>
|
||||
<log4j.version>2.23.1</log4j.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.controlsfx</groupId>
|
||||
<artifactId>controlsfx</artifactId>
|
||||
<version>11.2.1</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>
|
||||
|
||||
|
||||
<!-- JavaFX -->
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-controls</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-swing</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<artifactId>javafx-fxml</artifactId>
|
||||
<version>${javafx.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Apache PDFBox per leggere il PDF -->
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
<version>2.0.29</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j.version}</version> <!-- Controlla se ci sono versioni più recenti, ma questa è ottima e sicura -->
|
||||
</dependency>
|
||||
|
||||
<!-- Log4j 2 Core -->
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<configuration>
|
||||
<source>25</source>
|
||||
<target>25</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>org.example.mesosll07/org.example.mesosll07.HelloApplication</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>
|
||||
22
src/main/java/Server/Automaton/ActionResult.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package Server.Automaton;
|
||||
|
||||
public class ActionResult {
|
||||
private final boolean success;
|
||||
private final String errorMessage; // null se success
|
||||
|
||||
private ActionResult(boolean success, String errorMessage) {
|
||||
this.success = success;
|
||||
this.errorMessage = errorMessage;
|
||||
}
|
||||
|
||||
public static ActionResult ok() {
|
||||
return new ActionResult(true, null);
|
||||
}
|
||||
|
||||
public static ActionResult failure(String message) {
|
||||
return new ActionResult(false, message);
|
||||
}
|
||||
|
||||
public boolean isSuccess() { return success; }
|
||||
public String getErrorMessage(){ return errorMessage; }
|
||||
}
|
||||
53
src/main/java/Server/Automaton/Automaton.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package Server.Automaton;
|
||||
|
||||
public class Automaton {
|
||||
|
||||
private GameState state = GameState.SETUP;
|
||||
|
||||
public GameState getState(){
|
||||
return state;
|
||||
}
|
||||
|
||||
private Boolean canEvolve(int val){
|
||||
int currOrd = state.ordinal();
|
||||
int setupOrd = GameState.SETUP.ordinal();
|
||||
|
||||
if (currOrd == setupOrd && val > 5) {
|
||||
System.out.println("Invalid number of player");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public Boolean evolve(int i) {
|
||||
if (!canEvolve(i))
|
||||
return false;
|
||||
|
||||
int currOrd = state.ordinal();
|
||||
int lastOrd = GameState.GAME_OVER.ordinal();
|
||||
|
||||
if (currOrd < lastOrd) {
|
||||
state = state.next(i);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public Boolean evolveTo(GameState toState, int i){
|
||||
if (!canEvolve(i))
|
||||
return false;
|
||||
|
||||
int toOrd = toState.ordinal();
|
||||
int currOrd = state.ordinal();
|
||||
|
||||
if (toOrd>currOrd) {
|
||||
state = toState;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
789
src/main/java/Server/Automaton/Game.java
Normal file
@@ -0,0 +1,789 @@
|
||||
package Server.Automaton;
|
||||
|
||||
import Server.*;
|
||||
import Server.Cards.*;
|
||||
import Server.Utils.LoadingCardsException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* Central game controller for MESOS.
|
||||
*
|
||||
* Owns the full game lifecycle:
|
||||
*
|
||||
* SETUP → newGame()
|
||||
* TOTEM_PLACEMENT → placeTotem() — one call per player, in TurnTile order
|
||||
* ACTION_RESOLUTION → resolveCardAction() — one call per pending action
|
||||
* EXTRA_DRAW → extraDrawAction() / skipExtraDraw() [only if a player owns the building]
|
||||
* EVENT_RESOLUTION → handled automatically at end of round
|
||||
* GAME_OVER → endGame()
|
||||
*
|
||||
* All public methods that advance state return a boolean:
|
||||
* true = action accepted, state may have changed
|
||||
* false = action rejected, state unchanged (caller should log / notify client)
|
||||
*
|
||||
* NOTE: GameState must have EXTRA_DRAW added to the enum for this class to compile:
|
||||
* UNKNOWN, SETUP, TOTEM_PLACEMENT, ACTION_RESOLUTION, EXTRA_DRAW, EVENT_RESOLUTION, GAME_OVER
|
||||
*
|
||||
* NOTE: Tribe.endPoints() already computes end-game building bonuses internally via
|
||||
* buildingAbilitiesEndPoints(). Do NOT also call BuildingManager.endgameForSix() etc.
|
||||
* in endGame() — that would count those bonuses twice.
|
||||
*/
|
||||
public class Game {
|
||||
private static final Logger logger = LogManager.getLogger(Game.class);
|
||||
// -------------------------------------------------------------------------
|
||||
// Constants
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private static final int TOTAL_ROUNDS = 10;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Core state
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private final List<Player> players;
|
||||
private GameBoard gameBoard;
|
||||
private int round;
|
||||
private GameState state;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Phase tracking
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** How many players have placed their totem this round. */
|
||||
private int totemPlacedCount;
|
||||
|
||||
/** Index of the offering tile (central row) currently being resolved (left to right). */
|
||||
private int currentOfferingTileIndex;
|
||||
|
||||
/** Actions the current player still has to resolve. */
|
||||
private List<Symbol> pendingActions;
|
||||
|
||||
/**
|
||||
* Queue of players who own the EXTRA_DRAW building and still need to
|
||||
* make their extra-draw decision this round. Ordered by turn order.
|
||||
*/
|
||||
//TODO to check it should be a single player
|
||||
private final List<Player> extraDrawQueue;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public Game(List<Player> players) {
|
||||
this.players = new ArrayList<>(players);
|
||||
this.round = 0;
|
||||
this.state = GameState.SETUP;
|
||||
this.pendingActions = new ArrayList<>();
|
||||
this.extraDrawQueue = new ArrayList<>();
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// SETUP
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Initialises a new game: loads the deck, builds the board, deals initial
|
||||
* food, and randomises the first turn order.
|
||||
*
|
||||
* Initial food (rulebook setup step 10):
|
||||
* Slot 1 -> 2 food, slots 2-3 -> 3 food, slots 4-5 -> 4 food.
|
||||
*/
|
||||
public void newGame(String cardsFilePath) {
|
||||
try {
|
||||
logger.info("STARTING NEW GAME : ", cardsFilePath);
|
||||
|
||||
CardDeck deck = new CardDeck();
|
||||
deck.setForNPlayer(cardsFilePath, players.size());
|
||||
|
||||
gameBoard = new GameBoard(Era.I, deck, players.size());
|
||||
gameBoard.initOfferingTiles(players.size());
|
||||
gameBoard.setupInitialRows(players.size());
|
||||
|
||||
gameBoard.getTurnTile().setInitialOrder(players);
|
||||
dealInitialFood();
|
||||
|
||||
round = 1;
|
||||
totemPlacedCount = 0;
|
||||
state = GameState.TOTEM_PLACEMENT;
|
||||
|
||||
logger.info("Game started! Round 1.");
|
||||
logTurnOrder();
|
||||
|
||||
} catch (LoadingCardsException e) {
|
||||
System.err.println("Fatal: could not load cards — " + e.getMessage());
|
||||
state = GameState.GAME_OVER;
|
||||
}
|
||||
}
|
||||
|
||||
private void dealInitialFood() {
|
||||
Player[] order = gameBoard.getTurnTile().getPositions();
|
||||
for (int i = 0; i < order.length; i++) {
|
||||
int food = (i == 0) ? 2 : (i <= 2) ? 3 : 4;
|
||||
order[i].addFood(food);
|
||||
logger.info(" " + order[i].getNickname() + " starts with " + food + " food.");
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// PHASE 1 — TOTEM PLACEMENT
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Places the player's totem on an offering tile.
|
||||
*
|
||||
* Players must place in the order defined by the TurnTile (top to bottom).
|
||||
* If the wrong player calls this, it is rejected.
|
||||
*
|
||||
* @param player the player attempting to place
|
||||
* @param tileIndex 0-based index into the offering tile list
|
||||
* @return true if placement was accepted
|
||||
*/
|
||||
public boolean placeTotem(Player player, int tileIndex) {
|
||||
if (state != GameState.TOTEM_PLACEMENT) {
|
||||
logger.info("Error: not the totem-placement phase.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enforce turn order
|
||||
Player expected = gameBoard.getTurnTile().getPositions()[totemPlacedCount];
|
||||
if (expected != player) {
|
||||
logger.info("Error: it is " + expected.getNickname()
|
||||
+ "'s turn to place, not " + player.getNickname() + ".");
|
||||
return false;
|
||||
}
|
||||
|
||||
List<OfferingTile> tiles = gameBoard.getOfferingTiles();
|
||||
if (tileIndex < 0 || tileIndex >= tiles.size()) {
|
||||
logger.info("Error: tile index " + tileIndex + " out of range.");
|
||||
return false;
|
||||
}
|
||||
|
||||
OfferingTile chosen = tiles.get(tileIndex);
|
||||
if (!gameBoard.placeTotem(player, chosen, gameBoard.getTurnTile())) {
|
||||
logger.info("Tile " + chosen.getLetter() + " is already occupied.");
|
||||
return false;
|
||||
}
|
||||
|
||||
totemPlacedCount++;
|
||||
logger.info("player {} TOTEM PLACED ON TILE {}", player.getNickname() , chosen.getLetter());
|
||||
|
||||
// + " (" + totemPlacedCount + "/" + players.size() + ").");
|
||||
|
||||
if (totemPlacedCount == players.size()) {
|
||||
logger.info("START ACTION RESOLUTION");
|
||||
startActionResolution();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// PHASE 2 — ACTION RESOLUTION
|
||||
// =========================================================================
|
||||
|
||||
private void startActionResolution() {
|
||||
state = GameState.ACTION_RESOLUTION;
|
||||
currentOfferingTileIndex = 0;
|
||||
logger.info("All totems placed — resolving actions left to right.");
|
||||
loadNextPlayerActions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans offering tiles left to right for the next occupied one, loads that
|
||||
* player's actions, and either resolves them automatically (food tile) or
|
||||
* waits for player input (card tiles).
|
||||
*
|
||||
* Calls onAllActionsResolved() when every tile has been processed.
|
||||
*/
|
||||
private void loadNextPlayerActions() {
|
||||
List<OfferingTile> tiles = gameBoard.getOfferingTiles();
|
||||
|
||||
while (currentOfferingTileIndex < tiles.size()) {
|
||||
OfferingTile tile = tiles.get(currentOfferingTileIndex);
|
||||
|
||||
if (tile.isEmpty()) {
|
||||
currentOfferingTileIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Player player = tile.getOccupant();
|
||||
pendingActions = new ArrayList<>(tile.getActions());
|
||||
logger.info(" PLAYER {} PENDING_ACTIONS {} ", player.getNickname() , pendingActions );
|
||||
// --- Food tile: resolve entirely without player input ---
|
||||
if (pendingActions.get(0) == Symbol.FOOD) {
|
||||
|
||||
int food = pendingActions.size();
|
||||
player.addFood(food);
|
||||
BuildingManager.bonusEndTurn(player, food); // BONUS_FOOD_ENDTURN building effect
|
||||
logger.info(player.getNickname() + " receives " + food
|
||||
+ " food from tile " + tile.getLetter() + ".");
|
||||
pendingActions.clear();
|
||||
finishPlayerTurn(player);
|
||||
currentOfferingTileIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// --- Card tile: strip impossible actions first ---
|
||||
filterImpossibleActions(player);
|
||||
|
||||
if (pendingActions.isEmpty()) {
|
||||
// All actions were impossible (both rows empty)
|
||||
finishPlayerTurn(player);
|
||||
currentOfferingTileIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Wait for the player to call resolveCardAction()
|
||||
logger.info("player {} pending ACTIONS {}" , player.getNickname() , pendingActions);
|
||||
// logger.info("It is " + player.getNickname() + "'s turn — actions: " + pendingActions);
|
||||
return;
|
||||
}
|
||||
|
||||
// Every tile has been processed
|
||||
onAllActionsResolved();
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips actions that cannot be executed because the required row is empty.
|
||||
* Pure filter — no side effects beyond mutating pendingActions.
|
||||
*/
|
||||
private void filterImpossibleActions(Player player) {
|
||||
|
||||
Card ctop = gameBoard.getTopRow().stream().filter(s -> s instanceof CharacterCard || s instanceof BuildingCard).findFirst().orElse(null);
|
||||
Card cdown = gameBoard.getBottomRow().stream().filter(s -> s instanceof CharacterCard || s instanceof BuildingCard).findFirst().orElse(null);
|
||||
|
||||
boolean topEmpty = ctop == null;
|
||||
boolean bottomEmpty = cdown == null;
|
||||
|
||||
if (topEmpty) {
|
||||
long removed = pendingActions.stream().filter(s -> s == Symbol.UP).count();
|
||||
pendingActions.removeIf(s -> s == Symbol.UP);
|
||||
if (removed > 0)
|
||||
logger.info("{} LOSES ACTION UP" ,player.getNickname(), removed);
|
||||
|
||||
}
|
||||
if (bottomEmpty) {
|
||||
long removed = pendingActions.stream().filter(s -> s == Symbol.DOWN).count();
|
||||
pendingActions.removeIf(s -> s == Symbol.DOWN);
|
||||
if (removed > 0)
|
||||
logger.info("{} LOSES ACTION DOWN" ,player.getNickname(), removed);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves one card-pick action for the current player.
|
||||
* Works for both CharacterCards and BuildingCards.
|
||||
*
|
||||
* For BuildingCards: builder discount is applied and the player must have
|
||||
* enough food. If not, the card is put back and the call is rejected — the
|
||||
* player must choose a different card.
|
||||
*
|
||||
* @param player the acting player (must match the current tile occupant)
|
||||
* @param fromTop true = pick from the top row; false = from the bottom row
|
||||
* @param cardId the ID of the card to take
|
||||
* @return true if the action was accepted and consumed
|
||||
*/
|
||||
public ActionResult resolveCardAction(Player player, boolean fromTop, int cardId) {
|
||||
if (state != GameState.ACTION_RESOLUTION) {
|
||||
logger.info("Error: not in ACTION_RESOLUTION phase.");
|
||||
return ActionResult.failure("Error: not in ACTION_RESOLUTION phase.");
|
||||
|
||||
}
|
||||
|
||||
OfferingTile currentTile = gameBoard.getOfferingTiles().get(currentOfferingTileIndex);
|
||||
if (currentTile.getOccupant() != player) {
|
||||
logger.info("Error: it is not " + player.getNickname() + "'s turn to act.");
|
||||
return ActionResult.failure("Error: it is not " + player.getNickname() + "'s turn to act.");
|
||||
}
|
||||
|
||||
Symbol required = fromTop ? Symbol.UP : Symbol.DOWN;
|
||||
if (!pendingActions.contains(required)) {
|
||||
logger.info("Error: no " + required + " action available for "
|
||||
+ player.getNickname() + ".");
|
||||
return ActionResult.failure("Error: no " + required + " action available for "
|
||||
+ player.getNickname() + ".");
|
||||
}
|
||||
|
||||
// Find the card in the correct row
|
||||
Card card = fromTop
|
||||
? gameBoard.takeFromTopRow(cardId)
|
||||
: gameBoard.takeFromBottomRow(cardId);
|
||||
|
||||
if (card == null) {
|
||||
logger.info("Error: card " + cardId + " not found in the "
|
||||
+ (fromTop ? "top" : "bottom") + " row.");
|
||||
return ActionResult.failure("Error: card " + cardId + " not found in the "
|
||||
+ (fromTop ? "top" : "bottom") + " row.");
|
||||
}
|
||||
|
||||
// Event cards can never be taken by players
|
||||
if (card instanceof EventCard) {
|
||||
putCardBack(card, fromTop);
|
||||
logger.info("Error: Event cards cannot be taken.");
|
||||
return ActionResult.failure("Error: Event cards cannot be taken.");
|
||||
}
|
||||
|
||||
// Resolve the card
|
||||
if (card instanceof BuildingCard) {
|
||||
ActionResult result =resolveBuildingCard(player, (BuildingCard) card);
|
||||
if (!result.isSuccess()) {
|
||||
putCardBack(card, fromTop);
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
resolveCharacterCard(player, (CharacterCard) card);
|
||||
}
|
||||
|
||||
// Consume the action
|
||||
pendingActions.remove(required);
|
||||
logger.info("player {} TOOK CARD {} --> PEDNING ACTIONS {}",player.getNickname(), cardId, pendingActions);
|
||||
|
||||
|
||||
// A row may have become empty after this draw — re-check impossible actions
|
||||
if (!pendingActions.isEmpty()) {
|
||||
filterImpossibleActions(player);
|
||||
}
|
||||
|
||||
// If no more actions remain, finish this player's turn
|
||||
if (pendingActions.isEmpty()) {
|
||||
finishPlayerTurn(player);
|
||||
currentOfferingTileIndex++;
|
||||
loadNextPlayerActions();
|
||||
}
|
||||
|
||||
return ActionResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles building card acquisition.
|
||||
* Applies builder discount, checks affordability, deducts food, and
|
||||
* registers the building with BuildingManager.
|
||||
*
|
||||
* @return true if the acquisition succeeded
|
||||
*/
|
||||
private ActionResult resolveBuildingCard(Player player, BuildingCard building) {
|
||||
int discount = player.getPlayerTribe().buildersDiscount();
|
||||
int actualCost = Math.max(0, building.getCost() - discount);
|
||||
|
||||
if (player.getFoodTokens() < actualCost) {
|
||||
logger.info(player.getNickname() + " cannot afford building "
|
||||
+ building.getCardId() + " (cost after discount: " + actualCost
|
||||
+ ", has: " + player.getFoodTokens() + " food).");
|
||||
return ActionResult.failure(player.getNickname() + " cannot afford building "
|
||||
+ building.getCardId() + " (cost after discount: " + actualCost
|
||||
+ ", has: " + player.getFoodTokens() + " food).");
|
||||
}
|
||||
|
||||
player.removeFood(actualCost);
|
||||
player.getPlayerTribe().addBuilding(building);
|
||||
gameBoard.getBuildingManager().addActiveBuilding(building, player);
|
||||
|
||||
logger.info(player.getNickname() + " bought building "
|
||||
+ building.getCardId() + " for " + actualCost + " food.");
|
||||
return ActionResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles character card acquisition and triggers all immediate effects:
|
||||
*
|
||||
* Hunter with leg icon (iconValue > 0):
|
||||
* Take 1 food per Hunter currently in tribe (including this one).
|
||||
*
|
||||
* FOOD_FOR_SIX building:
|
||||
* Take 6 food if this draw completes a full set of all 6 character types.
|
||||
*
|
||||
* FOOD_PER_INVENTORS building:
|
||||
* Take 3 food if this Inventor forms a matching pair.
|
||||
*
|
||||
* The card is added to the tribe BEFORE effects fire so all counts include it.
|
||||
*/
|
||||
private void resolveCharacterCard(Player player, CharacterCard character) {
|
||||
player.getPlayerTribe().addCharacter(character);
|
||||
|
||||
// Hunter with leg icon: immediate food reward
|
||||
if (character.getCharacterType() == CharacterType.HUNTER
|
||||
&& character.getIconValue() > 0) {
|
||||
int food = player.getPlayerTribe().huntersNumber() * character.getIconValue();
|
||||
player.addFood(food);
|
||||
logger.info(player.getNickname() + "'s hunter (leg icon) grants +"
|
||||
+ food + " food.");
|
||||
}
|
||||
|
||||
// Building-triggered effects on character draw
|
||||
gameBoard.getBuildingManager().foodForSix(player, character);
|
||||
if (character.getCharacterType() == CharacterType.INVENTOR) {
|
||||
gameBoard.getBuildingManager().foodPerInventors(player, character);
|
||||
}
|
||||
|
||||
logger.info(player.getNickname() + " drew "
|
||||
+ character.getCharacterType() + " (id " + character.getCardId() + ").");
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the current player as done with their tile actions.
|
||||
* Calls TurnTile.returnTotem(), which places them in the next available
|
||||
* slot and immediately applies the position food reward or penalty.
|
||||
*/
|
||||
private void finishPlayerTurn(Player player) {
|
||||
int slot = gameBoard.getTurnTile().returnTotem(player);
|
||||
OfferingTile off = gameBoard.getOfferingTile(player);
|
||||
logger.info("player {} leaving offering {} " ,player.getNickname(), off);
|
||||
if(off!=null) off.setOccupant(null);
|
||||
logger.info("player {} left offering {} slot {} " ,player.getNickname(), off, slot);
|
||||
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// PHASE 2b — EXTRA DRAW (EXTRA_DRAW building effect)
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Called when every offering tile has been resolved.
|
||||
* Checks if any player owns the EXTRA_DRAW building and, if so, enters
|
||||
* the EXTRA_DRAW phase. Otherwise proceeds directly to end of round.
|
||||
*
|
||||
* Rulebook appendix: "After resolving all actions (once all totems are back
|
||||
* on the TurnTile) and before the end-of-round phase, you may take 1
|
||||
* Character or Building card (paying its cost) from the top row."
|
||||
*/
|
||||
private void onAllActionsResolved() {
|
||||
logger.info("All actions resolved.");
|
||||
|
||||
extraDrawQueue.clear();
|
||||
// Iterate in turn order so extra draws happen in a consistent sequence
|
||||
for (Player p : gameBoard.getTurnTile().getPositions()) {
|
||||
if (p != null && gameBoard.getBuildingManager().extraDraw(p)) {
|
||||
extraDrawQueue.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (!extraDrawQueue.isEmpty()) {
|
||||
state = GameState.EXTRA_DRAW;
|
||||
System.out.println("Extra draw phase: "
|
||||
+ extraDrawQueue.get(0).getNickname() + " may draw first.");
|
||||
} else {
|
||||
endRound();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The player uses their EXTRA_DRAW building to take one card from the top row.
|
||||
* Building cards may also be taken, paying the cost after builder discounts.
|
||||
*
|
||||
* @param player the player taking the extra draw
|
||||
* @param cardId the ID of the card they want from the top row
|
||||
* @return true if the action was accepted
|
||||
*/
|
||||
public ActionResult extraDrawAction(Player player, int cardId) {
|
||||
if (state != GameState.EXTRA_DRAW) {
|
||||
System.out.println("Error: not in EXTRA_DRAW phase.");
|
||||
return ActionResult.failure("Error: not in EXTRA_DRAW phase.");
|
||||
}
|
||||
if (extraDrawQueue.isEmpty() || extraDrawQueue.get(0) != player) {
|
||||
System.out.println("Error: it is not " + player.getNickname()
|
||||
+ "'s extra draw turn.");
|
||||
return ActionResult.failure("Error: it is not " + player.getNickname()
|
||||
+ "'s extra draw turn.");
|
||||
}
|
||||
|
||||
Card card = gameBoard.takeFromTopRow(cardId);
|
||||
if (card == null) {
|
||||
System.out.println("Error: card " + cardId + " not found in top row.");
|
||||
return ActionResult.failure("Error: card " + cardId + " not found in top row.");
|
||||
}
|
||||
if (card instanceof EventCard) {
|
||||
gameBoard.getTopRow().add(card);
|
||||
System.out.println("Error: cannot take Event cards.");
|
||||
return ActionResult.failure("Error: cannot take Event cards.");
|
||||
}
|
||||
|
||||
if (card instanceof BuildingCard) {
|
||||
ActionResult result = resolveBuildingCard(player, (BuildingCard) card);
|
||||
if (!result.isSuccess()) {
|
||||
gameBoard.getTopRow().add(card);
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
resolveCharacterCard(player, (CharacterCard) card);
|
||||
}
|
||||
|
||||
advanceExtraDrawQueue();
|
||||
return ActionResult.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* The player declines to use their EXTRA_DRAW building this round.
|
||||
*
|
||||
* @return true if accepted
|
||||
*/
|
||||
public boolean skipExtraDraw(Player player) {
|
||||
if (state != GameState.EXTRA_DRAW) return false;
|
||||
if (extraDrawQueue.isEmpty() || extraDrawQueue.get(0) != player) return false;
|
||||
|
||||
System.out.println(player.getNickname() + " skips extra draw.");
|
||||
advanceExtraDrawQueue();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void advanceExtraDrawQueue() {
|
||||
extraDrawQueue.remove(0);
|
||||
if (extraDrawQueue.isEmpty()) {
|
||||
endRound();
|
||||
} else {
|
||||
System.out.println("Next extra draw: " + extraDrawQueue.get(0).getNickname());
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// END OF ROUND
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Runs all end-of-round steps in rulebook order:
|
||||
*
|
||||
* Step 1 — Resolve Event cards.
|
||||
* Normal rounds: only bottom row events.
|
||||
* Round 10: events from BOTH rows; then GAME_OVER.
|
||||
* Step 2 — Advance rows: discard bottom non-buildings, shift top
|
||||
* non-buildings down, draw (numPlayers + 4) new cards.
|
||||
* Step 3 — If a new Era card was revealed in step 2, trigger
|
||||
* the Era transition (building row swap).
|
||||
* Step 4 — Start the next round.
|
||||
*/
|
||||
private void endRound() {
|
||||
state = GameState.EVENT_RESOLUTION;
|
||||
//notify( GameState.EVENT_RESOLUTION);
|
||||
|
||||
logger.info("--- End of round " + round + " ---");
|
||||
|
||||
boolean isFinalRound = (round == TOTAL_ROUNDS);
|
||||
|
||||
// Step 1: resolve events
|
||||
resolveVisibleEvents(isFinalRound);
|
||||
|
||||
if (isFinalRound) {
|
||||
state = GameState.GAME_OVER;
|
||||
notify( GameState.GAME_OVER, endGame());
|
||||
logger.info("Round 10 complete — game over!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: advance rows; returns true if a new Era card was revealed
|
||||
boolean eraChangeTriggered = gameBoard.advanceRows(players.size());
|
||||
|
||||
// Step 3: handle Era transition if needed
|
||||
if (eraChangeTriggered) {
|
||||
gameBoard.triggerEraChange(players.size());
|
||||
}
|
||||
|
||||
// Step 4: start next round
|
||||
startNewRound();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves all visible Event cards in the correct order.
|
||||
*
|
||||
* Rules:
|
||||
* - Multiple events of different types: any order, Sustainment always last.
|
||||
* - Two events of the same type in the same round: resolve in Era order.
|
||||
* - Round 10: events from both rows must be resolved.
|
||||
*
|
||||
* @param bothRows true means events from both rows are included (round 10)
|
||||
*/
|
||||
private void resolveVisibleEvents(boolean bothRows) {
|
||||
List<EventCard> events = bothRows
|
||||
? gameBoard.getAllVisibleEvents() // already sorted by Era ordinal
|
||||
: gameBoard.getVisibleEvents(); // already sorted by Era ordinal
|
||||
|
||||
if (events.isEmpty()) {
|
||||
logger.info("No events to resolve this round.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sustainment must always be resolved last
|
||||
List<EventCard> others = new ArrayList<>();
|
||||
List<EventCard> sustainments = new ArrayList<>();
|
||||
for (EventCard e : events) {
|
||||
if (e.getEvent() == Event.SUSTAINMENT) sustainments.add(e);
|
||||
else others.add(e);
|
||||
}
|
||||
|
||||
for (EventCard e : others) resolveOneEvent(e);
|
||||
for (EventCard e : sustainments) resolveOneEvent(e);
|
||||
}
|
||||
|
||||
private void resolveOneEvent(EventCard event) {
|
||||
notify( GameState.EVENT_RESOLUTION, event.toString());
|
||||
logger.info("EVENT Resolving: " + event.getEvent() + " (Era " + event.getEra() + ")");
|
||||
EventsSolver.solveEvents(Collections.singletonList(event), players);
|
||||
}
|
||||
|
||||
private void startNewRound() {
|
||||
|
||||
round++;
|
||||
|
||||
notify( GameState.NEXT_ROUND, "Round="+ round);
|
||||
logger.info("startNewRound: {}", round );
|
||||
totemPlacedCount = 0;
|
||||
currentOfferingTileIndex = 0;
|
||||
pendingActions.clear();
|
||||
|
||||
gameBoard.clearOfferingTiles();
|
||||
gameBoard.getTurnTile().resetTrack();
|
||||
|
||||
// notify( GameState.TOTEM_PLACEMENT);
|
||||
state = GameState.TOTEM_PLACEMENT;
|
||||
logger.info("=== NEW Round " + round + " ===");
|
||||
logTurnOrder();
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// END GAME
|
||||
// =========================================================================
|
||||
|
||||
/**
|
||||
* Computes the final leaderboard and returns it as a formatted string.
|
||||
*
|
||||
* Final score = prestige points accumulated during play
|
||||
* + Tribe.endPoints() which covers: builder PP, inventor PP,
|
||||
* artist PP, building base PP, and building end-game abilities.
|
||||
*
|
||||
* IMPORTANT: do NOT call BuildingManager.endgameForSix() /
|
||||
* endgameBonusCharacter() / endgameBonusPoints() here.
|
||||
* Tribe.endPoints() already computes those bonuses. Calling both would
|
||||
* count them twice.
|
||||
*
|
||||
* Tie-breaking rule: most food wins. Further ties share the victory.
|
||||
*/
|
||||
public String endGame() {
|
||||
state = GameState.GAME_OVER;
|
||||
|
||||
List<Player> ranked = new ArrayList<>(players);
|
||||
ranked.sort((a, b) -> {
|
||||
int diff = totalScore(b) - totalScore(a);
|
||||
if (diff != 0) return diff;
|
||||
return b.getFoodTokens() - a.getFoodTokens();
|
||||
});
|
||||
|
||||
StringBuilder sb = new StringBuilder("=== FINAL LEADERBOARD ===\n");
|
||||
for (int i = 0; i < ranked.size(); i++) {
|
||||
Player p = ranked.get(i);
|
||||
sb.append(i + 1).append(". ")
|
||||
.append(p.getNickname())
|
||||
.append(" — ").append(totalScore(p)).append(" PP")
|
||||
.append(" (food: ").append(p.getFoodTokens()).append(")\n");
|
||||
}
|
||||
|
||||
Player winner = ranked.get(0);
|
||||
sb.append("\nWINNER: ")
|
||||
.append(winner.getNickname().toUpperCase())
|
||||
.append(" with ").append(totalScore(winner)).append(" PP!");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** Prestige points accumulated during play + final scoring from the Tribe engine. */
|
||||
private int totalScore(Player p) {
|
||||
return p.getPrestigePoints() + p.getPlayerTribe().endPoints();
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// HELPERS
|
||||
// =========================================================================
|
||||
|
||||
private void putCardBack(Card card, boolean wasTopRow) {
|
||||
if (wasTopRow) gameBoard.getTopRow().add(card);
|
||||
else gameBoard.getBottomRow().add(card);
|
||||
}
|
||||
|
||||
private void logTurnOrder() {
|
||||
Player[] order = gameBoard.getTurnTile().getPositions();
|
||||
StringBuilder sb = new StringBuilder("Turn order: ");
|
||||
for (int i = 0; i < order.length; i++) {
|
||||
if (order[i] != null)
|
||||
sb.append(i + 1).append(". ").append(order[i].getNickname()).append(" ");
|
||||
}
|
||||
logger.info("logTurnOrder: " + sb);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// GETTERS
|
||||
// =========================================================================
|
||||
|
||||
public List<Player> getPlayers() { return Collections.unmodifiableList(players); }
|
||||
public GameBoard getGameBoard() { return gameBoard; }
|
||||
public int getRound() { return round; }
|
||||
public GameState getState() { return state; }
|
||||
public void setState(GameState s) { this.state = s; }
|
||||
public List<Symbol> getPendingActions() { return Collections.unmodifiableList(pendingActions); }
|
||||
|
||||
/**
|
||||
* Returns the player currently expected to act:
|
||||
* TOTEM_PLACEMENT — the next player who should place their totem
|
||||
* ACTION_RESOLUTION — the player currently resolving tile actions
|
||||
* EXTRA_DRAW — the next player to make their extra-draw decision
|
||||
*/
|
||||
public Player getCurrentPlayer() {
|
||||
switch (state) {
|
||||
case TOTEM_PLACEMENT:
|
||||
if (totemPlacedCount < players.size())
|
||||
return gameBoard.getTurnTile().getPositions()[totemPlacedCount];
|
||||
return null;
|
||||
case ACTION_RESOLUTION:
|
||||
List<OfferingTile> tiles = gameBoard.getOfferingTiles();
|
||||
if (currentOfferingTileIndex < tiles.size())
|
||||
return tiles.get(currentOfferingTileIndex).getOccupant();
|
||||
return null;
|
||||
case EXTRA_DRAW:
|
||||
return extraDrawQueue.isEmpty() ? null : extraDrawQueue.get(0);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Game{" +
|
||||
" state=" + state +
|
||||
",\n round=" + round +
|
||||
",\n totemPlacedCount=" + totemPlacedCount +
|
||||
",\n currentOfferingTileIndex=" + currentOfferingTileIndex +
|
||||
",\n pendingActions=" + pendingActions +
|
||||
",\n extraDrawQueue=" + extraDrawQueue +
|
||||
" \n GameBoard=" + gameBoard +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
public record GameEventNotification(GameState event, String message) {}
|
||||
|
||||
public interface GameEventListener {
|
||||
void onEvent(GameEventNotification notification);
|
||||
}
|
||||
|
||||
// Campo privato
|
||||
private GameEventListener eventListener;
|
||||
|
||||
// Setter per il controller FX
|
||||
public void setEventListener(GameEventListener listener) {
|
||||
this.eventListener = listener;
|
||||
}
|
||||
|
||||
// Metodi privati di notifica
|
||||
private void notify(GameState event, String message) {
|
||||
if (eventListener != null)
|
||||
eventListener.onEvent(new GameEventNotification(event, message));
|
||||
}
|
||||
|
||||
private void notify(GameState event) {
|
||||
notify(event, null);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
68
src/main/java/Server/Automaton/GameState.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package Server.Automaton;
|
||||
|
||||
public enum GameState implements Comparable<GameState> {
|
||||
UNKNOWN,
|
||||
SETUP,
|
||||
NEXT_ROUND,
|
||||
TOTEM_PLACEMENT,
|
||||
ACTION_RESOLUTION,
|
||||
END_ACTION,
|
||||
EXTRA_DRAW,
|
||||
EVENT_RESOLUTION,
|
||||
GAME_OVER;
|
||||
|
||||
GameState next(int turn){
|
||||
switch (this) {
|
||||
case SETUP:
|
||||
return SETUP;
|
||||
case NEXT_ROUND:
|
||||
return NEXT_ROUND;
|
||||
case TOTEM_PLACEMENT:
|
||||
return ACTION_RESOLUTION;
|
||||
case ACTION_RESOLUTION:
|
||||
return END_ACTION;
|
||||
case EXTRA_DRAW:
|
||||
return EXTRA_DRAW;
|
||||
case END_ACTION:
|
||||
if(turn != 10) return GAME_OVER;
|
||||
return TOTEM_PLACEMENT;
|
||||
default: return UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static GameState fromString(String s){
|
||||
return switch (s.toUpperCase().charAt(0)) {
|
||||
case 'S' -> SETUP;
|
||||
case 'T' -> TOTEM_PLACEMENT;
|
||||
case 'A' -> ACTION_RESOLUTION;
|
||||
case 'E' -> END_ACTION;
|
||||
case 'X' -> EXTRA_DRAW;
|
||||
case 'G' -> GAME_OVER;
|
||||
case 'N' -> NEXT_ROUND;
|
||||
default -> UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case SETUP:
|
||||
return "SETUP";
|
||||
case TOTEM_PLACEMENT:
|
||||
return "TOTEM_PLACEMENT";
|
||||
case ACTION_RESOLUTION:
|
||||
return "ACTION_RESOLUTION";
|
||||
case END_ACTION:
|
||||
return "END_ACTION";
|
||||
case EVENT_RESOLUTION:
|
||||
return "EVENT_RESOLUTION";
|
||||
case NEXT_ROUND:
|
||||
return "NEXT_ROUND";
|
||||
case EXTRA_DRAW:
|
||||
return "EXTRA_DRAW";
|
||||
case GAME_OVER:
|
||||
return "GAME_OVER";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
}
|
||||
214
src/main/java/Server/BuildingManager.java
Normal file
@@ -0,0 +1,214 @@
|
||||
package Server;
|
||||
|
||||
import Server.Cards.BuildingCard;
|
||||
import Server.Cards.CharacterCard;
|
||||
import Server.Cards.CharacterType;
|
||||
import Server.Cards.Trigger;
|
||||
import Server.Utils.EventsManagerException;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class BuildingManager {
|
||||
private static List<BuildingCard> activeBuildings;
|
||||
|
||||
public BuildingManager() {
|
||||
activeBuildings = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void addActiveBuilding (BuildingCard buildingCard, Player player) {
|
||||
buildingCard.setOwner(player);
|
||||
activeBuildings.add(buildingCard);
|
||||
}
|
||||
|
||||
public static BuildingCard playerHasBuilding(Player player, Trigger trigger) {
|
||||
|
||||
for (BuildingCard buildingCard : activeBuildings) {
|
||||
if(buildingCard.getAbilityTrigger() == trigger && buildingCard.getOwner() == player) {
|
||||
return buildingCard;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int numberOfTargets(Player player, List<BuildingCard> buildingCards) {
|
||||
int numCard = 0;
|
||||
for (BuildingCard buildingCard : buildingCards) {
|
||||
|
||||
List<CharacterCard> playerCharacters = player.getPlayerTribe().getCharacters();
|
||||
|
||||
for (CharacterCard card : playerCharacters) {
|
||||
if (card.getCharacterType() == buildingCard.getEffectTarget()) {
|
||||
numCard++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return numCard;
|
||||
}
|
||||
|
||||
public static List<BuildingCard> playerHasVariousBuildings(Player player, Trigger trigger) {
|
||||
|
||||
List<BuildingCard> buildingCards = new ArrayList<>();
|
||||
|
||||
for (BuildingCard buildingCard : activeBuildings) {
|
||||
if(buildingCard.getAbilityTrigger() == trigger && buildingCard.getOwner() == player) {
|
||||
buildingCards.add(buildingCard);
|
||||
}
|
||||
}
|
||||
return buildingCards;
|
||||
}
|
||||
|
||||
//When a player draw a characterCard, if said card complete a set of 6
|
||||
//different character type, give the player 6 food
|
||||
|
||||
public static void foodForSix(Player player, CharacterCard characterCard) {
|
||||
if(playerHasBuilding(player, Trigger.FOOD_FOR_SIX) == null){
|
||||
return;
|
||||
}
|
||||
|
||||
List<CharacterCard> playerTribe = player.getPlayerTribe().getCharacters();
|
||||
int [] preDraw = new int[CharacterType.values().length];
|
||||
int [] postDraw = new int[CharacterType.values().length];
|
||||
|
||||
for(CharacterCard card: playerTribe){
|
||||
preDraw[card.getCharacterType().ordinal()]++;
|
||||
postDraw[card.getCharacterType().ordinal()]++;
|
||||
}
|
||||
|
||||
postDraw[characterCard.getCharacterType().ordinal()]++;
|
||||
|
||||
int minPre = Arrays.stream(preDraw).min().getAsInt();
|
||||
int minPost = Arrays.stream(postDraw).min().getAsInt();
|
||||
|
||||
if(minPre < minPost){
|
||||
player.addFood(6);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//the method return the discount received for the player based on the cards he owns
|
||||
//the card providing the discount are indicated on the BuildingCard
|
||||
public static int sustainDiscount(Player player) {
|
||||
List<BuildingCard> buildingCards = playerHasVariousBuildings(player, Trigger.SUSTAIN_DISCOUNT);
|
||||
if(buildingCards.isEmpty()){
|
||||
return 0;
|
||||
}
|
||||
return numberOfTargets(player, buildingCards);
|
||||
}
|
||||
|
||||
//if the player is going to lose during the shamanicRitual, the loss are nullif
|
||||
public static boolean shamanNoLoss(Player player) {
|
||||
return playerHasBuilding(player, Trigger.SHAMAN_NO_LOSS) != null;
|
||||
}
|
||||
|
||||
//check if the player has a SHAMAN_DOUBLE_POINTS card
|
||||
public static boolean shamanDoublePoints(Player player) {
|
||||
return playerHasBuilding(player, Trigger.SHAMAN_DOUBLE_POINTS) != null;
|
||||
}
|
||||
|
||||
//if the player has a BONUS_END_TURN buildingCard the player gain additional food
|
||||
//after placing his totem on a tile whit food
|
||||
public static int bonusEndTurn(Player player, int positionReward) {
|
||||
if (playerHasBuilding(player, Trigger.BONUS_FOOD_ENDTURN) == null) return -1;
|
||||
|
||||
if (positionReward >= 1){
|
||||
player.addFood(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//if the player has a BuildingCard whit FOOD_PER_INVENTORS, and he
|
||||
//draws a copy of an inventor that is already in his tribe he gains 3 food
|
||||
public static void foodPerInventors(Player player, CharacterCard characterCard) {
|
||||
if(playerHasBuilding(player, Trigger.FOOD_PER_INVENTORS) == null){
|
||||
return;
|
||||
}
|
||||
|
||||
if(characterCard.getCharacterType()!= CharacterType.INVENTOR){
|
||||
throw new EventsManagerException("Invalid character type");
|
||||
}
|
||||
|
||||
List<CharacterCard> playerTribe = player.getPlayerTribe().getCharacters();
|
||||
int numberOfInventors = 0;
|
||||
|
||||
for(CharacterCard card: playerTribe){
|
||||
if(card.getIconValue() == characterCard.getIconValue() && card.getCharacterType() == CharacterType.INVENTOR){
|
||||
numberOfInventors++;
|
||||
}
|
||||
}
|
||||
|
||||
if(numberOfInventors%2 == 1)
|
||||
player.addFood(3);
|
||||
}
|
||||
|
||||
//if the player has a SHAMAN_BONUS building the function return 3, else return 0
|
||||
public static int shamanBonus(Player player) {
|
||||
if (BuildingManager.playerHasBuilding(player, Trigger.SHAMAN_BONUS) == null) return 0;
|
||||
return 3;
|
||||
}
|
||||
|
||||
//return if HUNT_BONUS is active for the player
|
||||
public static boolean hunterBonus(Player player) {
|
||||
return playerHasBuilding(player, Trigger.HUNT_BONUS) != null;
|
||||
}
|
||||
|
||||
//return if ENDGAME_BUILDER_BONUS is active for the player
|
||||
public static boolean endgameBuilderBonus(Player player) {
|
||||
return playerHasBuilding(player, Trigger.ENDGAME_BUILDER_BONUS) != null;
|
||||
}
|
||||
|
||||
//return the amount of food gained if the player has a BuildingCard with
|
||||
//PAINTING_FOOD_BONUS, a unit for each ARTIST in his tribe
|
||||
public static void paintingFoodBonus(Player player) {
|
||||
if(playerHasBuilding(player, Trigger.PAINTING_FOOD_BONUS) == null) return;
|
||||
|
||||
player.addFood(player.getPlayerTribe().artistsNumber());
|
||||
}
|
||||
|
||||
//return the amount of buildingPoint if the player has a BuildingCard with
|
||||
//ENDGAME_FOR_SIX, a unit for each set of 6 character of different Type
|
||||
public static void endgameForSix(Player player) {
|
||||
if(playerHasBuilding(player, Trigger.ENDGAME_FOR_SIX) == null) return;
|
||||
|
||||
List<CharacterCard> playerTribe = player.getPlayerTribe().getCharacters();
|
||||
|
||||
int [] typeDuplicates = new int[CharacterType.values().length];
|
||||
|
||||
for(CharacterCard card: playerTribe){
|
||||
typeDuplicates[card.getCharacterType().ordinal()]++;
|
||||
}
|
||||
|
||||
int minCharacterType = Arrays.stream(typeDuplicates).min().getAsInt();
|
||||
|
||||
player.addPrestigePoints(minCharacterType*6);
|
||||
}
|
||||
|
||||
//add the bonus prestigePoints due to ENDGAME_BONUS_CHARACTER, the amount is based
|
||||
//on the CharacterType indicated on the BuildingCards, 3 for each character of the same type
|
||||
//A plater can own different BuildingCards with the same effect
|
||||
public static void endgameBonusCharacter(Player player) {
|
||||
List<BuildingCard> buildingCards = playerHasVariousBuildings(player, Trigger.ENDGAME_BONUS_CHARACTER);
|
||||
if(buildingCards.isEmpty()){
|
||||
return;
|
||||
}
|
||||
|
||||
player.addPrestigePoints(numberOfTargets(player, buildingCards)* 3);
|
||||
}
|
||||
|
||||
//return if EXTRA_DRAW is active for the player
|
||||
public static boolean extraDraw(Player player) {
|
||||
return playerHasBuilding(player, Trigger.EXTRA_DRAW) != null;
|
||||
}
|
||||
|
||||
//return if the player has a BuildingCard with
|
||||
//ENDGAME_BONUS_POINTS, then add 25 points if he has
|
||||
public static void endgameBonusPoints(Player player) {
|
||||
if(playerHasBuilding(player, Trigger.ENDGAME_BONUS_POINTS) == null) return;
|
||||
|
||||
player.addPrestigePoints(25);
|
||||
}
|
||||
}
|
||||
48
src/main/java/Server/BuildingRules.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package Server;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BuildingRules {
|
||||
private static final Map<Integer, Map<Era, Integer>> RULES = new HashMap<>();
|
||||
static {
|
||||
// 2 players
|
||||
Map<Era, Integer> p2 = new EnumMap<>(Era.class);
|
||||
p2.put(Era.I, 1);
|
||||
p2.put(Era.II, 2);
|
||||
p2.put(Era.III, 3);
|
||||
|
||||
// 3 players
|
||||
Map<Era, Integer> p3 = new EnumMap<>(Era.class);
|
||||
p3.put(Era.I, 2);
|
||||
p3.put(Era.II, 2);
|
||||
p3.put(Era.III, 4);
|
||||
|
||||
// 4 players
|
||||
Map<Era, Integer> p4 = new EnumMap<>(Era.class);
|
||||
p4.put(Era.I, 2);
|
||||
p4.put(Era.II, 3);
|
||||
p4.put(Era.III, 4);
|
||||
|
||||
// 5 players
|
||||
Map<Era, Integer> p5 = new EnumMap<>(Era.class);
|
||||
p4.put(Era.I, 2);
|
||||
p4.put(Era.II, 3);
|
||||
p4.put(Era.III, 5);
|
||||
|
||||
// insert into main map
|
||||
RULES.put(2, p2);
|
||||
RULES.put(3, p3);
|
||||
RULES.put(4, p4);
|
||||
RULES.put(5, p5);
|
||||
}
|
||||
|
||||
public static int getBuildingCards(int players, Era era) {
|
||||
Map<Era, Integer> eraMap = RULES.get(players);
|
||||
if (eraMap!=null){
|
||||
Integer value = eraMap.get(era);
|
||||
if (value!=null) return value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
84
src/main/java/Server/Cards/BuildingCard.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package Server.Cards;
|
||||
|
||||
import Server.Era;
|
||||
import Server.Player;
|
||||
|
||||
public class BuildingCard extends Card{
|
||||
private final int cost;
|
||||
private final int endPP;
|
||||
private final Trigger abilityTrigger;
|
||||
private final CharacterType effectTarget;
|
||||
private Player owner;
|
||||
|
||||
public BuildingCard(int cardId, int forMinPlayer, Era era, int cost, int endPP, Trigger abilityTrigger,CharacterType characterType, Player owner) {
|
||||
super(cardId, forMinPlayer, era);
|
||||
this.cost = cost;
|
||||
this.endPP = endPP;
|
||||
this.abilityTrigger = abilityTrigger;
|
||||
this.effectTarget = characterType;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public BuildingCard(int cardId, int forMinPlayer, Era era, int cost, int endPP, Trigger abilityTrigger, CharacterType characterType) {
|
||||
super(cardId, forMinPlayer, era);
|
||||
this.cost = cost;
|
||||
this.endPP = endPP;
|
||||
this.abilityTrigger = abilityTrigger;
|
||||
this.effectTarget = characterType;
|
||||
this.owner = null;
|
||||
}
|
||||
|
||||
public BuildingCard(int cardId, int forMinPlayer, Era era, int cost, int endPP, Trigger abilityTrigger) {
|
||||
super(cardId, forMinPlayer, era);
|
||||
this.cost = cost;
|
||||
this.endPP = endPP;
|
||||
this.abilityTrigger = abilityTrigger;
|
||||
this.effectTarget = null;
|
||||
this.owner = null;
|
||||
}
|
||||
|
||||
public void setOwner(Player owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public int getCost() {
|
||||
return cost;
|
||||
}
|
||||
|
||||
public int getEndPP() {
|
||||
return endPP;
|
||||
}
|
||||
|
||||
public Trigger getAbilityTrigger() {
|
||||
return abilityTrigger;
|
||||
}
|
||||
|
||||
public Player getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public CharacterType getEffectTarget() {
|
||||
return effectTarget;
|
||||
}
|
||||
|
||||
public static BuildingCard parsRow(String row) {
|
||||
String cleanRow = row.trim();
|
||||
String[] values = cleanRow.split(";");
|
||||
|
||||
int cardId = Integer.parseInt(values[1]);
|
||||
int forMinPlayer = Integer.parseInt(values[2]);
|
||||
Era era = Era.valueOf(values[3]);
|
||||
int cost = Integer.parseInt(values[4]);
|
||||
int endPP = Integer.parseInt(values[5]);
|
||||
Trigger abilityTrigger = Trigger.valueOf(values[6]);
|
||||
/* MANCA LA COLONNA 8 nel CSV
|
||||
if(abilityTrigger == Trigger.SUSTAIN_DISCOUNT || abilityTrigger == Trigger.ENDGAME_BONUS_CHARACTER){
|
||||
CharacterType effectTarget = CharacterType.valueOf(values[7]);
|
||||
return new BuildingCard(cardId, forMinPlayer, era, cost, endPP, abilityTrigger, effectTarget);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
return new BuildingCard(cardId, forMinPlayer, era, cost, endPP, abilityTrigger);
|
||||
}
|
||||
}
|
||||
35
src/main/java/Server/Cards/Card.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package Server.Cards;
|
||||
|
||||
import Server.Era;
|
||||
|
||||
public abstract class Card {
|
||||
private final int cardId;
|
||||
private final int forMinPlayer;
|
||||
private final Era era;
|
||||
|
||||
public Card(int cardId, int forMinPlayer, Era era) {
|
||||
this.cardId = cardId;
|
||||
this.forMinPlayer = forMinPlayer;
|
||||
this.era = era;
|
||||
}
|
||||
|
||||
public int getCardId() {
|
||||
return cardId;
|
||||
}
|
||||
|
||||
public Era getEra() {
|
||||
return era;
|
||||
}
|
||||
|
||||
public int getForMinPlayer() {
|
||||
return forMinPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Card{" +
|
||||
"cardId=" + cardId +
|
||||
", era=" + era +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
131
src/main/java/Server/Cards/CardDeck.java
Normal file
@@ -0,0 +1,131 @@
|
||||
package Server.Cards;
|
||||
|
||||
import Server.Automaton.Game;
|
||||
import Server.Era;
|
||||
import Server.Utils.LoadingCardsException;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CardDeck {
|
||||
private List<Card> tribeDeck;
|
||||
private Map<Era, List<Card>> buildingDeck;
|
||||
private static final Logger logger = LogManager.getLogger(CardDeck.class);
|
||||
|
||||
public List<Card> getTribeDeck() {
|
||||
return tribeDeck;
|
||||
}
|
||||
|
||||
public List<Card> getBuildingDeck(Era era) {
|
||||
return buildingDeck.get(era);
|
||||
}
|
||||
|
||||
public void setForNPlayer(String path, int n) throws LoadingCardsException {
|
||||
|
||||
List<Card> tribe = new ArrayList<>();
|
||||
List<Card> building = new ArrayList<>();
|
||||
|
||||
try {
|
||||
List<String> rows = Files.readAllLines(Path.of(path));
|
||||
int p=0;
|
||||
for (String row : rows) {
|
||||
String cleanRow = row.trim();
|
||||
String[] fields = cleanRow.split(";");
|
||||
logger.info((p++) + " ROW " +row);
|
||||
switch (fields[0]) {
|
||||
case "C":
|
||||
tribe.add(CharacterCard.parsRow(row));
|
||||
break;
|
||||
case "E":
|
||||
tribe.add(EventCard.parsRow(row));
|
||||
break;
|
||||
case "B":
|
||||
building.add(BuildingCard.parsRow(row));
|
||||
break;
|
||||
default:
|
||||
throw new LoadingCardsException("Content not supported");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error(e);
|
||||
throw new LoadingCardsException("file not found");
|
||||
}
|
||||
|
||||
building = CardDeck.shuffle(building);
|
||||
|
||||
this.tribeDeck = new ArrayList<>();
|
||||
|
||||
for(Card card : tribe) {
|
||||
if (card.getForMinPlayer() <= n)
|
||||
this.tribeDeck.add(card);
|
||||
}
|
||||
this.tribeDeck = CardDeck.shuffle(this.tribeDeck);
|
||||
|
||||
// groups the building cards by era
|
||||
this.buildingDeck = building.stream().collect(Collectors.groupingBy(Card::getEra));
|
||||
}
|
||||
|
||||
public List<Card> drawTribe(int n) {
|
||||
List<Card> cards = new ArrayList<>();
|
||||
for (int i = 0; i < n; i++) {
|
||||
if(tribeDeck.isEmpty()) break;
|
||||
cards.add(tribeDeck.getFirst());
|
||||
tribeDeck.remove(tribeDeck.getFirst());
|
||||
}
|
||||
return cards;
|
||||
}
|
||||
|
||||
public List<Card> drawBuilding(int n, Era era) {
|
||||
List<Card> cards = new ArrayList<>();
|
||||
for (int i = 0; i < n; i++) {
|
||||
if(buildingDeck.isEmpty()) break;
|
||||
Card card = buildingDeck.get(era).getFirst();
|
||||
cards.add(card);
|
||||
buildingDeck.remove(card);
|
||||
}
|
||||
return cards;
|
||||
}
|
||||
|
||||
|
||||
public static List<Card> shuffle(List<Card> cards) {
|
||||
List<Card> shuffled = new ArrayList<>();
|
||||
|
||||
for(Era e: Era.values()) {
|
||||
List<Card> cardsToShuffle = new ArrayList<>();
|
||||
for(Card card : cards) {
|
||||
if(card.getEra() == e){
|
||||
cardsToShuffle.add(card);
|
||||
}
|
||||
}
|
||||
Collections.shuffle(cardsToShuffle);
|
||||
shuffled.addAll(cardsToShuffle);
|
||||
}
|
||||
|
||||
return shuffled;
|
||||
}
|
||||
|
||||
public Card getFirstCardForCover() {
|
||||
if(tribeDeck.isEmpty()) return null;
|
||||
Card card = tribeDeck.getFirst();
|
||||
return card;
|
||||
}
|
||||
|
||||
public Card drawTribeOne() {
|
||||
if(tribeDeck.isEmpty()) return null;
|
||||
Card card = tribeDeck.getFirst();
|
||||
tribeDeck.remove(card);
|
||||
return card;
|
||||
}
|
||||
|
||||
public Card drawBuildingOne(Era era) {
|
||||
if(buildingDeck.isEmpty()) return null;
|
||||
Card card = buildingDeck.get(era).getFirst();
|
||||
buildingDeck.get(era).remove(card);
|
||||
return card;
|
||||
}
|
||||
}
|
||||
58
src/main/java/Server/Cards/CharacterCard.java
Normal file
@@ -0,0 +1,58 @@
|
||||
package Server.Cards;
|
||||
|
||||
import Server.Era;
|
||||
import Server.Utils.LoadingCardsException;
|
||||
|
||||
public class CharacterCard extends Card{
|
||||
private final CharacterType characterType;
|
||||
private final int iconValue;
|
||||
private final int prestigePoints;
|
||||
|
||||
public CharacterCard(int cardId, int forMinPlayer, Era era, CharacterType characterType, int iconValue, int prestigePoints) {
|
||||
super(cardId, forMinPlayer, era);
|
||||
this.characterType = characterType;
|
||||
this.iconValue = iconValue;
|
||||
this.prestigePoints = prestigePoints;
|
||||
}
|
||||
|
||||
public CharacterType getCharacterType() {
|
||||
return characterType;
|
||||
}
|
||||
|
||||
public int getIconValue() {
|
||||
return iconValue;
|
||||
}
|
||||
|
||||
public int getPrestigePoints() {
|
||||
return prestigePoints;
|
||||
}
|
||||
|
||||
public static CharacterCard parsRow(String row){
|
||||
|
||||
String cleanRow = row.trim();
|
||||
String[] values = cleanRow.split(";");
|
||||
|
||||
if(!values[0].equals("C")){
|
||||
throw new LoadingCardsException("Not a character card");
|
||||
}
|
||||
|
||||
int cardId = Integer.parseInt(values[1]);
|
||||
int forMinPlayer = Integer.parseInt(values[2]);
|
||||
Era era = Era.valueOf(values[3]);
|
||||
CharacterType characterType = CharacterType.valueOf(values[4]);
|
||||
int iconValue = Integer.parseInt(values[5]);
|
||||
int prestigePoints = Integer.parseInt(values[6]);
|
||||
|
||||
return new CharacterCard(cardId, forMinPlayer, era, characterType, iconValue, prestigePoints);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CharacterCard{" +
|
||||
"characterType=" + characterType +
|
||||
", value=" + iconValue +
|
||||
", points=" + prestigePoints +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
10
src/main/java/Server/Cards/CharacterType.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package Server.Cards;
|
||||
|
||||
public enum CharacterType {
|
||||
INVENTOR,
|
||||
HUNTER,
|
||||
GATHERER,
|
||||
SHAMAN,
|
||||
ARTIST,
|
||||
BUILDER
|
||||
}
|
||||
8
src/main/java/Server/Cards/Event.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package Server.Cards;
|
||||
|
||||
public enum Event {
|
||||
SUSTAINMENT,
|
||||
HUNT,
|
||||
SHAMANIC_RITUAL,
|
||||
CAVE_PAINTINGS
|
||||
}
|
||||
55
src/main/java/Server/Cards/EventCard.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package Server.Cards;
|
||||
|
||||
import Server.Era;
|
||||
import Server.Utils.LoadingCardsException;
|
||||
|
||||
public class EventCard extends Card {
|
||||
private final Event event;
|
||||
private final int firstValue;
|
||||
private final int secondValue;
|
||||
|
||||
public EventCard(int cardId, int forMinPlayer, Era era, Event event, int firstValue, int secondValue) {
|
||||
super(cardId, forMinPlayer, era);
|
||||
this.event = event;
|
||||
this.firstValue = firstValue;
|
||||
this.secondValue = secondValue;
|
||||
}
|
||||
|
||||
public Event getEvent() {
|
||||
return event;
|
||||
}
|
||||
public int getFirstValue() {
|
||||
return firstValue;
|
||||
}
|
||||
|
||||
public int getSecondValue() {
|
||||
return secondValue;
|
||||
}
|
||||
|
||||
public static EventCard parsRow(String row){
|
||||
String cleanRow = row.trim();
|
||||
String[] values = cleanRow.split(";");
|
||||
|
||||
if (!values[0].equals("E")) {
|
||||
throw new LoadingCardsException("Not an EventCard");
|
||||
}
|
||||
|
||||
int cardId = Integer.parseInt(values[1]);
|
||||
int forMinPlayer = Integer.parseInt(values[2]);
|
||||
Era era = Era.valueOf(values[3]);
|
||||
Event event = Event.valueOf(values[4]);
|
||||
int firstValue = Integer.parseInt(values[5]);
|
||||
int secondValue = Integer.parseInt(values[6]);
|
||||
|
||||
return new EventCard(cardId, forMinPlayer, era, event, firstValue, secondValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EventCard{" +
|
||||
"event=" + event +
|
||||
", firstValue=" + firstValue +
|
||||
", secondValue=" + secondValue +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
18
src/main/java/Server/Cards/Trigger.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package Server.Cards;
|
||||
|
||||
public enum Trigger {
|
||||
FOOD_FOR_SIX,
|
||||
SUSTAIN_DISCOUNT,
|
||||
SHAMAN_NO_LOSS,
|
||||
BONUS_FOOD_ENDTURN,
|
||||
FOOD_PER_INVENTORS,
|
||||
SHAMAN_BONUS,
|
||||
SHAMAN_DOUBLE_POINTS,
|
||||
HUNT_BONUS,
|
||||
ENDGAME_BUILDER_BONUS,
|
||||
PAINTING_FOOD_BONUS,
|
||||
ENDGAME_FOR_SIX,
|
||||
ENDGAME_BONUS_CHARACTER,
|
||||
EXTRA_DRAW,
|
||||
ENDGAME_BONUS_POINTS
|
||||
}
|
||||
684
src/main/java/Server/DeckGridAppFX.java
Normal file
@@ -0,0 +1,684 @@
|
||||
package Server;
|
||||
|
||||
import Server.Automaton.ActionResult;
|
||||
import Server.Automaton.Game;
|
||||
import Server.Cards.*;
|
||||
import Server.Utils.GameException;
|
||||
import javafx.animation.*;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.effect.DropShadow;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Rectangle;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.util.Duration;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DeckGridAppFX extends Application {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(DeckGridAppFX.class);
|
||||
private static final int IMG_HEIGHT=200;
|
||||
private PDDocument documentFront;
|
||||
private PDDocument documentBack;
|
||||
private PDFRenderer pdfRendererFront;
|
||||
private PDFRenderer pdfRendererBack;
|
||||
private int totalCards = 0;
|
||||
|
||||
// Contenitori Layout
|
||||
private HBox topMenu;
|
||||
private HBox topRow;
|
||||
private HBox centerRow;
|
||||
private HBox bottomRow;
|
||||
private HBox playersArea; // NUOVO: Area per i giocatori
|
||||
private Button btnRefresh;
|
||||
private Button btnTop;
|
||||
private Button btnBottom;
|
||||
private Button btnChooseOffering;
|
||||
|
||||
private Button btnMsg;
|
||||
// --------------------------------
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
|
||||
List<Player> players = new ArrayList<>();
|
||||
//players.add(new Player("Yellow", TotemColor.YELLOW));
|
||||
players.add(new Player("Blue", TotemColor.BLUE));
|
||||
//players.add(new Player("Purple", TotemColor.PURPLE));
|
||||
players.add(new Player("Red", TotemColor.RED));
|
||||
|
||||
//players.add(new Player("Green", TotemColor.GREEN));
|
||||
|
||||
Game game = new Game(players);
|
||||
String fileCards="/home/lorenzo/dev/Mesos2/src/main/resources/files/cards.csv";
|
||||
String fileCardsImgFront="/home/lorenzo/dev/Mesos2/src/main/resources/files/Cards_total_front_PROMO.pdf";
|
||||
String fileCardsImgCover="/home/lorenzo/dev/Mesos2/src/main/resources/files/Cards_total_back_PROMO.pdf";
|
||||
|
||||
try {
|
||||
|
||||
File fileFront = new File(fileCardsImgFront);
|
||||
File fileBack = new File(fileCardsImgCover);
|
||||
|
||||
documentFront = PDDocument.load(fileFront);
|
||||
pdfRendererFront = new PDFRenderer(documentFront);
|
||||
documentBack = PDDocument.load(fileBack);
|
||||
pdfRendererBack = new PDFRenderer(documentBack);
|
||||
|
||||
} catch ( IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
game.newGame(fileCards);
|
||||
|
||||
game.setEventListener(notification -> {
|
||||
Platform.runLater(() -> {
|
||||
drawGameState(game);
|
||||
switch (notification.event()) {
|
||||
case TOTEM_PLACEMENT-> showPopup("TOTEM PLACEMENT\n" + (notification.message()!=null?notification.message():""));
|
||||
case SETUP -> showPopup("SETUP \n" + (notification.message()!=null?notification.message():""));
|
||||
case ACTION_RESOLUTION -> showPopup("ACTION_RESOLUTION \n" + (notification.message()!=null?notification.message():"" ));
|
||||
case END_ACTION -> showPopup("END_ACTION \n" + (notification.message()!=null?notification.message():"" ));
|
||||
case EVENT_RESOLUTION -> showPopup("EVENT_RESOLUTION \n" + (notification.message()!=null?notification.message():"" ));
|
||||
case EXTRA_DRAW -> showPopup("EXTRA_DRAW \n" + (notification.message()!=null?notification.message():"" ));
|
||||
case GAME_OVER -> showPopup("GAME OVER");
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
primaryStage.setTitle("Tavolo da Gioco - Board & Players");
|
||||
|
||||
btnTop = new Button("Pick Top");
|
||||
btnBottom = new Button("Pick Bottom");
|
||||
btnMsg = new Button("Game State");
|
||||
btnRefresh= new Button("Refresh");
|
||||
btnChooseOffering= new Button("Choose Offering");
|
||||
//btnNext.setDisable(true);
|
||||
topMenu = new HBox(15, btnRefresh, btnMsg);
|
||||
topMenu.setAlignment(Pos.CENTER);
|
||||
topMenu.setPadding(new Insets(10));
|
||||
|
||||
Label stateLabel = new Label("Game State = " + game.getState() );
|
||||
stateLabel.setFont(Font.font("System", FontWeight.BOLD, 16));
|
||||
stateLabel.setTextFill(Color.DARKBLUE);
|
||||
|
||||
//showPopup(topMenu, "STARTING GAME");
|
||||
|
||||
btnMsg.setOnAction(e -> {
|
||||
new Alert(Alert.AlertType.INFORMATION,
|
||||
game.toString()
|
||||
).showAndWait();
|
||||
});
|
||||
btnRefresh.setOnAction(e -> {
|
||||
drawGameState(game);
|
||||
});
|
||||
|
||||
topRow = createRowContainer();
|
||||
centerRow = createRowContainer();
|
||||
bottomRow = createRowContainer();
|
||||
|
||||
// NUOVO: Inizializza l'area giocatori
|
||||
playersArea = new HBox(30);
|
||||
playersArea.setAlignment(Pos.CENTER);
|
||||
playersArea.setPadding(new Insets(20));
|
||||
|
||||
|
||||
|
||||
|
||||
VBox tableArea = new VBox(20,
|
||||
new Label(" "), topRow,
|
||||
new Label(" "), centerRow,
|
||||
new Label(" "), bottomRow,
|
||||
new Label("--- ASSET PLAYERS ---"), playersArea
|
||||
);
|
||||
tableArea.setAlignment(Pos.CENTER);
|
||||
tableArea.setPadding(new Insets(20));
|
||||
|
||||
ScrollPane scrollPane = new ScrollPane(tableArea);
|
||||
scrollPane.setFitToWidth(true);
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
root.setTop(topMenu);
|
||||
root.setCenter(scrollPane);
|
||||
|
||||
Scene scene = new Scene(root, 1300, 900);
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
|
||||
drawGameState(game);
|
||||
}
|
||||
|
||||
private HBox createRowContainer() {
|
||||
HBox row = new HBox(10);
|
||||
row.setAlignment(Pos.CENTER);
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
private void drawGameState(Game game) {
|
||||
if (documentFront == null) return;
|
||||
|
||||
|
||||
topMenu.getChildren().clear();
|
||||
topRow.getChildren().clear();
|
||||
centerRow.getChildren().clear();
|
||||
bottomRow.getChildren().clear();
|
||||
playersArea.getChildren().clear();
|
||||
|
||||
drawTopMenu(topMenu, game);
|
||||
drawTopRow(topRow, game);
|
||||
drawTurnTileAndOffering(centerRow, game.getPlayers().size(), game);
|
||||
drawBottomRow(bottomRow, game );
|
||||
|
||||
|
||||
List<Player> players =game.getPlayers();
|
||||
renderPlayers(players, game);
|
||||
logger.info(game.getCurrentPlayer());
|
||||
|
||||
}
|
||||
|
||||
private void pickTopCardAction(Player player, GameBoard board, int cardid){
|
||||
Card card = board.getTopRow().stream()
|
||||
.filter(CharacterCard.class::isInstance)
|
||||
.map(CharacterCard.class::cast)
|
||||
.filter(c -> c.getCardId() == cardid)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (card != null) {
|
||||
board.getTopRow().remove(card);
|
||||
CharacterCard charCard = (CharacterCard)card;
|
||||
player.addCharacterToTribe((CharacterCard) card);
|
||||
}
|
||||
}
|
||||
|
||||
private void pickBottomCardAction(Player player, GameBoard board, int cardid){
|
||||
Card card = board.getBottomRow().stream()
|
||||
.filter(CharacterCard.class::isInstance)
|
||||
.map(CharacterCard.class::cast)
|
||||
.filter(c -> c.getCardId() == cardid)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (card != null) {
|
||||
board.getBottomRow().remove(card);
|
||||
player.addCharacterToTribe((CharacterCard) card);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void drawBottomRow(HBox row, Game game) {
|
||||
for (Card c : game.getGameBoard().getBottomRow()) {
|
||||
ImageView cardImage = createCardImageFromPdf(c.getCardId(), IMG_HEIGHT, true);
|
||||
|
||||
if (cardImage != null) {
|
||||
// 1. Create a Label for your debugging text
|
||||
Label debugLabel = new Label("ID: " + c.getCardId());
|
||||
|
||||
// 2. Style the label so it's readable over any card background
|
||||
// (White text with a semi-transparent black background)
|
||||
debugLabel.setStyle("-fx-background-color: rgba(0, 0, 0, 0.7); " +
|
||||
"-fx-text-fill: white; " +
|
||||
"-fx-padding: 3px; " +
|
||||
"-fx-font-weight: bold;");
|
||||
|
||||
// 3. Create a StackPane and add both the image and the text
|
||||
StackPane cardContainer = new StackPane();
|
||||
cardContainer.getChildren().addAll(cardImage, debugLabel);
|
||||
|
||||
// 4. Align the text wherever you want (e.g., Top-Left corner of the card)
|
||||
StackPane.setAlignment(debugLabel, Pos.TOP_LEFT);
|
||||
// You can also use Pos.CENTER, Pos.BOTTOM_RIGHT, etc.
|
||||
cardImage.setOnMouseClicked(event -> {
|
||||
logger.info("Bottom Card clicked");
|
||||
Player p = game.getCurrentPlayer();
|
||||
//pickBottomCardAction(p, game.getGameBoard(), c.getCardId());
|
||||
ActionResult result = game.resolveCardAction(p, false, c.getCardId());
|
||||
if (!result.isSuccess()) {
|
||||
new Alert(Alert.AlertType.ERROR,
|
||||
result.getErrorMessage()
|
||||
).showAndWait();
|
||||
}
|
||||
drawGameState(game);
|
||||
});
|
||||
// 5. Add the StackPane (which now holds both) to the row
|
||||
row.getChildren().add(cardContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void drawTopMenu(HBox row, Game game) {
|
||||
//topMenu = new HBox(15, btnChooseOffering, btnAction, btnTop, btnBottom, btnMsg);
|
||||
//topMenu.setAlignment(Pos.CENTER);
|
||||
//topMenu.setPadding(new Insets(10));
|
||||
|
||||
Label stateLabel = new Label("Game State = " + game.getState() );
|
||||
stateLabel.setFont(Font.font("System", FontWeight.BOLD, 16));
|
||||
stateLabel.setTextFill(Color.DARKBLUE);
|
||||
row.getChildren().add(stateLabel);
|
||||
row.getChildren().add(btnRefresh);
|
||||
row.getChildren().add(btnMsg);
|
||||
|
||||
|
||||
|
||||
}
|
||||
private void drawTopRow(HBox row, Game game) {
|
||||
for (Card c : game.getGameBoard().getTopRow()) {
|
||||
ImageView cardImage = createCardImageFromPdf(c.getCardId(), IMG_HEIGHT, true);
|
||||
|
||||
if (cardImage != null) {
|
||||
// 1. Create a Label for your debugging text
|
||||
Label debugLabel = new Label("ID: " + c.getCardId());
|
||||
|
||||
// 2. Style the label so it's readable over any card background
|
||||
// (White text with a semi-transparent black background)
|
||||
debugLabel.setStyle("-fx-background-color: rgba(0, 0, 0, 0.7); " +
|
||||
"-fx-text-fill: white; " +
|
||||
"-fx-padding: 3px; " +
|
||||
"-fx-font-weight: bold;");
|
||||
|
||||
// 3. Create a StackPane and add both the image and the text
|
||||
StackPane cardContainer = new StackPane();
|
||||
cardContainer.getChildren().addAll(cardImage, debugLabel);
|
||||
|
||||
// 4. Align the text wherever you want (e.g., Top-Left corner of the card)
|
||||
StackPane.setAlignment(debugLabel, Pos.TOP_LEFT);
|
||||
// You can also use Pos.CENTER, Pos.BOTTOM_RIGHT, etc.
|
||||
cardImage.setOnMouseClicked(event -> {
|
||||
logger.info("Card clicked");
|
||||
Player p = game.getCurrentPlayer();
|
||||
//pickTopCardAction(p, game.getGameBoard(), c.getCardId());
|
||||
//game.resolveCardAction(p, true, c.getCardId());
|
||||
|
||||
ActionResult result = game.resolveCardAction(p, true, c.getCardId());
|
||||
if (!result.isSuccess()) {
|
||||
new Alert(Alert.AlertType.ERROR,
|
||||
result.getErrorMessage()
|
||||
).showAndWait();
|
||||
}
|
||||
|
||||
drawGameState(game);
|
||||
});
|
||||
// 5. Add the StackPane (which now holds both) to the row
|
||||
row.getChildren().add(cardContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private StackPane drawTurnTileCardImageWithPlayers(String imagePath, int height, Player[] players) {
|
||||
try {
|
||||
Image fxImage = new Image("file:" + imagePath);
|
||||
|
||||
ImageView imageView = new ImageView(fxImage);
|
||||
imageView.setFitHeight(height);
|
||||
imageView.setPreserveRatio(true);
|
||||
imageView.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.4), 4, 0, 0, 0);");
|
||||
|
||||
StackPane stack = new StackPane(imageView);
|
||||
|
||||
VBox playerBox = new VBox(5);
|
||||
playerBox.setPadding(new Insets(5));
|
||||
playerBox.setAlignment(Pos.CENTER_RIGHT);
|
||||
|
||||
// 🔥 DEBUG background (to SEE the box)
|
||||
playerBox.setStyle("-fx-background-color: rgba(255,0,0,0.3);");
|
||||
|
||||
for (Player p : players) {
|
||||
if (p==null) continue;
|
||||
Rectangle rect = new Rectangle(15,15);
|
||||
rect.setFill(p.getTotemColor().getFxColor());
|
||||
rect.setStroke(Color.WHITE);
|
||||
rect.setStrokeWidth(1);
|
||||
|
||||
playerBox.getChildren().add(rect);
|
||||
}
|
||||
playerBox.setPadding(new Insets(22));
|
||||
// 🔥 IMPORTANT: bring to front
|
||||
playerBox.toFront();
|
||||
|
||||
// position it clearly
|
||||
StackPane.setAlignment(playerBox, Pos.CENTER);
|
||||
|
||||
stack.getChildren().add(playerBox);
|
||||
|
||||
return stack;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Errore caricamento immagine {}", imagePath, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void drawTurnTileAndOffering(HBox row, int n, Game game) {
|
||||
|
||||
// Clear row if needed (optional but recommended)
|
||||
row.getChildren().clear();
|
||||
|
||||
// --- LEFT BLOCK (Turn + initial card) ---
|
||||
VBox turnBox = new VBox(5);
|
||||
turnBox.setAlignment(Pos.CENTER);
|
||||
|
||||
// Turn label
|
||||
int round = game.getRound(); // adjust if different
|
||||
Label turnLabel = new Label("Round = " + round);
|
||||
turnLabel.setFont(Font.font("System", FontWeight.BOLD, 16));
|
||||
turnLabel.setTextFill(Color.DARKBLUE);
|
||||
|
||||
Card first = game.getGameBoard().getCardDeck().getFirstCardForCover();
|
||||
if (first!=null){
|
||||
ImageView imgCover = createCardImageFromPdf(first.getCardId(), 120, false);
|
||||
turnBox.getChildren().addAll(turnLabel, imgCover);
|
||||
} else turnBox.getChildren().addAll(turnLabel);
|
||||
|
||||
// Add FIRST
|
||||
row.getChildren().add(turnBox);
|
||||
|
||||
// --- TURN TILE ---
|
||||
StackPane pane = drawTurnTileCardImageWithPlayers(
|
||||
"/home/lorenzo/dev/Mesos2/src/main/resources/files/Start_" + n + "P.png",
|
||||
IMG_HEIGHT,
|
||||
game.getGameBoard().getTurnTile().getPositions()
|
||||
);
|
||||
|
||||
row.getChildren().add(pane);
|
||||
|
||||
// --- OFFERINGS ---
|
||||
for (OfferingTile offering : game.getGameBoard().getOfferingTiles()) {
|
||||
Player occupant = offering.getOccupant();
|
||||
StackPane offPane =drawOfferingCardImageWithTotem(
|
||||
"/home/lorenzo/dev/Mesos2/src/main/resources/files/offering" + offering.getLetter() + ".png",
|
||||
IMG_HEIGHT,
|
||||
occupant, game, offering);
|
||||
|
||||
if (offPane != null) {
|
||||
row.getChildren().add(offPane);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- NUOVO: RENDERIZZAZIONE GIOCATORI E RAGGRUPPAMENTO (JAVA 8) ---
|
||||
private void renderPlayers(List<Player> players, Game game) {
|
||||
playersArea.getChildren().clear();
|
||||
for (Player player : players) {
|
||||
boolean active = player.equals(game.getCurrentPlayer());
|
||||
|
||||
VBox playerBox = new VBox(10);
|
||||
playerBox.setPadding(new Insets(15));
|
||||
playerBox.setStyle("-fx-border-color: #555; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-color: #f9f9f9; -fx-background-radius: 10;");
|
||||
|
||||
if (active) {
|
||||
// Strong highlight (gold border + soft background)
|
||||
playerBox.setStyle(
|
||||
"-fx-border-color: gold;" +
|
||||
"-fx-border-width: 3;" +
|
||||
"-fx-border-radius: 10;" +
|
||||
"-fx-background-color: linear-gradient(to bottom, #fffbe6, #f9f9f9);" +
|
||||
"-fx-background-radius: 10;"
|
||||
);
|
||||
|
||||
// Slight scale-up
|
||||
playerBox.setScaleX(1.05);
|
||||
playerBox.setScaleY(1.05);
|
||||
|
||||
// Glow effect
|
||||
DropShadow glow = new DropShadow();
|
||||
glow.setColor(Color.GOLD);
|
||||
glow.setRadius(20);
|
||||
playerBox.setEffect(glow);
|
||||
|
||||
// Smooth pulse animation (NOT blinking)
|
||||
Timeline pulse = new Timeline(
|
||||
new KeyFrame(Duration.ZERO,
|
||||
new KeyValue(glow.radiusProperty(), 10)
|
||||
),
|
||||
new KeyFrame(Duration.seconds(1.2),
|
||||
new KeyValue(glow.radiusProperty(), 25)
|
||||
)
|
||||
);
|
||||
pulse.setAutoReverse(true);
|
||||
pulse.setCycleCount(Animation.INDEFINITE);
|
||||
pulse.play();
|
||||
}
|
||||
|
||||
HBox nameRow = new HBox(8);
|
||||
nameRow.setAlignment(Pos.CENTER_LEFT);
|
||||
|
||||
Rectangle rect = new Rectangle(12, 12);
|
||||
|
||||
TotemColor color = player.getTotemColor();
|
||||
rect.setFill(color.getFxColor());
|
||||
|
||||
|
||||
rect.setStroke(Color.BLACK);
|
||||
rect.setStrokeWidth(1);
|
||||
|
||||
Label nameLbl = new Label(player.getNickname());
|
||||
nameLbl.setFont(Font.font("System", FontWeight.BOLD, 16));
|
||||
|
||||
if (active) {
|
||||
Label turnLbl = new Label(" ▶ Your Turn");
|
||||
turnLbl.setTextFill(Color.GOLDENROD);
|
||||
turnLbl.setFont(Font.font("System", FontWeight.BOLD, 14));
|
||||
nameRow.getChildren().addAll(rect, nameLbl, turnLbl);
|
||||
} else {
|
||||
nameRow.getChildren().addAll(rect, nameLbl);
|
||||
}
|
||||
|
||||
// Risorse Cibo e Soldi
|
||||
Label statsLbl = new Label("🍖 Food: " + player.getFoodTokens() + " | 💰 Points: " + player.getPrestigePoints());
|
||||
statsLbl.setTextFill(Color.DARKRED);
|
||||
statsLbl.setFont(Font.font("System", FontWeight.BOLD, 14));
|
||||
|
||||
playerBox.getChildren().addAll(nameRow, statsLbl);
|
||||
|
||||
Map<CharacterType, List<CharacterCard>> groupedCards = player.getPlayerTribe().getCharacters().stream()
|
||||
.collect(Collectors.groupingBy(CharacterCard::getCharacterType));
|
||||
|
||||
// Itera sui gruppi creati e genera la grafica
|
||||
groupedCards.forEach((type, cardsOfType) -> {
|
||||
Label typeLbl = new Label("Tipo: " + type.name() + " (" + cardsOfType.size() + ")");
|
||||
typeLbl.setFont(Font.font("System", FontWeight.NORMAL, 12));
|
||||
|
||||
HBox cardImagesRow = new HBox(5);
|
||||
for (Card c : cardsOfType) {
|
||||
// Carte più piccole (90px) per l'area giocatore
|
||||
ImageView img = createCardImageFromPdf(c.getCardId(), 90, true);
|
||||
if (img != null) cardImagesRow.getChildren().add(img);
|
||||
}
|
||||
|
||||
playerBox.getChildren().addAll(typeLbl, cardImagesRow);
|
||||
});
|
||||
|
||||
Map<Era, List<BuildingCard>> groupedBuildCards = player.getPlayerTribe().getBuildingCard().stream()
|
||||
.collect(Collectors.groupingBy(BuildingCard::getEra));
|
||||
|
||||
groupedBuildCards.forEach((type, cardsOfType) -> {
|
||||
Label typeLbl = new Label("Build Tipo: " + type.name() + " (" + cardsOfType.size() + ")");
|
||||
typeLbl.setFont(Font.font("System", FontWeight.NORMAL, 12));
|
||||
|
||||
HBox cardImagesRow = new HBox(5);
|
||||
for (Card c : cardsOfType) {
|
||||
// Carte più piccole (90px) per l'area giocatore
|
||||
ImageView img = createCardImageFromPdf(c.getCardId(), 90, true);
|
||||
if (img != null) cardImagesRow.getChildren().add(img);
|
||||
}
|
||||
|
||||
playerBox.getChildren().addAll(typeLbl, cardImagesRow);
|
||||
//playerBox.getChildren().addAll(nameRow, statsLbl);
|
||||
});
|
||||
playersArea.getChildren().add(playerBox);
|
||||
}
|
||||
}
|
||||
|
||||
private ImageView createCardImageFromPdf(int pageIndex, int height, boolean front) {
|
||||
try {
|
||||
BufferedImage bim =null;
|
||||
if (front) bim = pdfRendererFront.renderImageWithDPI(pageIndex-1, 100);
|
||||
else bim = pdfRendererBack.renderImageWithDPI(pageIndex-1, 100);
|
||||
|
||||
Image fxImage = SwingFXUtils.toFXImage(bim, null);
|
||||
ImageView imageView = new ImageView(fxImage);
|
||||
imageView.setFitHeight(height);
|
||||
imageView.setPreserveRatio(true);
|
||||
imageView.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.4), 4, 0, 0, 0);");
|
||||
return imageView;
|
||||
} catch (IOException e) {
|
||||
logger.error("Errore rendering pagina {}", pageIndex, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private StackPane drawOfferingCardImageWithTotem(String imagePath, int height, Player occupant, Game game, OfferingTile offering) {
|
||||
try {
|
||||
Image fxImage = new Image("file:" + imagePath);
|
||||
|
||||
ImageView imageView = new ImageView(fxImage);
|
||||
imageView.setFitHeight(height);
|
||||
imageView.setPreserveRatio(true);
|
||||
imageView.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.4), 4, 0, 0, 0);");
|
||||
|
||||
imageView.setOnMouseClicked(event -> {
|
||||
int idx = game.getGameBoard().getOfferingTiles().indexOf(offering);
|
||||
game.placeTotem(game.getCurrentPlayer(), idx);
|
||||
logger.info(" PLAYER {} choose {} ", game.getCurrentPlayer().getNickname() , offering );
|
||||
drawGameState(game);
|
||||
});
|
||||
|
||||
StackPane stack = new StackPane(imageView);
|
||||
if(occupant!=null){
|
||||
Rectangle rect = new Rectangle(25, 25);
|
||||
rect.setFill(occupant.getTotemColor().getFxColor());
|
||||
rect.setStroke(Color.WHITE);
|
||||
rect.setStrokeWidth(1);
|
||||
|
||||
StackPane.setAlignment(rect, Pos.TOP_CENTER);
|
||||
rect.setTranslateY(20);
|
||||
StackPane.setMargin(rect, new Insets(5));
|
||||
|
||||
stack.getChildren().add(rect);
|
||||
}
|
||||
|
||||
return stack;
|
||||
} catch (Exception e) {
|
||||
logger.error("Errore caricamento immagine {}", imagePath, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private ImageView createCardImage(String imagePath, int height) {
|
||||
try {
|
||||
Image fxImage = new Image("file:" + imagePath);
|
||||
|
||||
ImageView imageView = new ImageView(fxImage);
|
||||
imageView.setFitHeight(height);
|
||||
imageView.setPreserveRatio(true);
|
||||
imageView.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.4), 4, 0, 0, 0);");
|
||||
|
||||
return imageView;
|
||||
} catch (Exception e) {
|
||||
logger.error("Errore caricamento immagine {}", imagePath, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
private void showPopup(String message) {
|
||||
Platform.runLater(() -> {
|
||||
|
||||
Label label = new Label("⚡ " + message); // icon improves readability
|
||||
label.setWrapText(true);
|
||||
label.setMaxWidth(400);
|
||||
|
||||
label.setStyle(
|
||||
"-fx-background-color: rgba(20,20,20,0.9);" +
|
||||
"-fx-text-fill: white;" +
|
||||
"-fx-font-size: 20px;" +
|
||||
"-fx-font-weight: bold;" +
|
||||
"-fx-padding: 15 25 15 25;" +
|
||||
"-fx-background-radius: 12;" +
|
||||
"-fx-border-radius: 12;" +
|
||||
"-fx-border-color: #00c3ff;"
|
||||
);
|
||||
|
||||
label.setOpacity(0); // start invisible
|
||||
|
||||
topMenu.getChildren().add(label);
|
||||
|
||||
// Fade IN
|
||||
FadeTransition fadeIn = new FadeTransition(Duration.millis(250), label);
|
||||
fadeIn.setFromValue(0);
|
||||
fadeIn.setToValue(1);
|
||||
|
||||
// Stay visible
|
||||
PauseTransition pause = new PauseTransition(Duration.seconds(4));
|
||||
|
||||
// Fade OUT
|
||||
FadeTransition fadeOut = new FadeTransition(Duration.millis(400), label);
|
||||
fadeOut.setFromValue(1.0);
|
||||
fadeOut.setToValue(0.0);
|
||||
|
||||
fadeOut.setOnFinished(f -> topMenu.getChildren().remove(label));
|
||||
|
||||
fadeIn.play();
|
||||
fadeIn.setOnFinished(e -> pause.play());
|
||||
pause.setOnFinished(e -> fadeOut.play());
|
||||
});
|
||||
}
|
||||
private void showPopupNo(String message) {
|
||||
Platform.runLater(() -> {
|
||||
Label label = new Label(message);
|
||||
label.setStyle(
|
||||
"-fx-background-color: rgba(0,0,0,0.75);" +
|
||||
"-fx-text-fill: white;" +
|
||||
"-fx-font-size: 28px;" +
|
||||
"-fx-font-weight: bold;" +
|
||||
"-fx-padding: 20 40 20 40;" +
|
||||
"-fx-background-radius: 12;"
|
||||
);
|
||||
label.setMouseTransparent(true);
|
||||
|
||||
topMenu.getChildren().add(label);
|
||||
|
||||
PauseTransition pause = new PauseTransition(Duration.seconds(5));
|
||||
pause.setOnFinished(e -> {
|
||||
FadeTransition fade = new FadeTransition(Duration.millis(400), label);
|
||||
fade.setFromValue(1.0);
|
||||
fade.setToValue(0.0);
|
||||
fade.setOnFinished(f -> topMenu.getChildren().remove(label));
|
||||
fade.play();
|
||||
});
|
||||
pause.play();
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
if (documentFront != null) documentFront.close();
|
||||
super.stop();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
}
|
||||
19
src/main/java/Server/Era.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package Server;
|
||||
|
||||
public enum Era {
|
||||
I,
|
||||
II,
|
||||
III,
|
||||
FINAL;
|
||||
|
||||
|
||||
public Era next() {
|
||||
Era[] eras = values();
|
||||
// Calcola l'indice del prossimo elemento
|
||||
int nextOrdinal = this.ordinal() + 1;
|
||||
if (nextOrdinal < eras.length) {
|
||||
return eras[nextOrdinal];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
136
src/main/java/Server/EventsSolver.java
Normal file
@@ -0,0 +1,136 @@
|
||||
package Server;
|
||||
|
||||
import Server.Cards.Event;
|
||||
import Server.Cards.EventCard;
|
||||
import Server.Cards.Trigger;
|
||||
import Server.Utils.EventsManagerException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class EventsSolver {
|
||||
|
||||
public static boolean solveEvents(List<EventCard> events, List<Player> players){
|
||||
|
||||
for(EventCard event: events){
|
||||
switch (event.getEvent()){
|
||||
case Event.SUSTAINMENT:
|
||||
EventsSolver.sustainment(event, players);
|
||||
break;
|
||||
case Event.HUNT:
|
||||
EventsSolver.hunt(event, players);
|
||||
break;
|
||||
case Event.SHAMANIC_RITUAL:
|
||||
EventsSolver.shamanicRitual(event, players);
|
||||
break;
|
||||
case Event.CAVE_PAINTINGS:
|
||||
EventsSolver.cavePaintings(event, players);
|
||||
break;
|
||||
default:
|
||||
throw new EventsManagerException("Unknown event type");
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<Integer> sustainment(EventCard event, List<Player> players){
|
||||
|
||||
if(event.getEvent() != Event.SUSTAINMENT){throw new EventsManagerException("Not a sustainment card");}
|
||||
|
||||
List<Integer> result = new ArrayList<>();
|
||||
for(Player p: players){
|
||||
int subpoints = p.getPlayerTribe().getCharacters().size();
|
||||
int discount = p.getPlayerTribe().gathererDiscount() + BuildingManager.sustainDiscount(p);
|
||||
|
||||
if(subpoints <= discount){subpoints = 0;}else{
|
||||
subpoints -= discount;
|
||||
}
|
||||
|
||||
|
||||
if(p.getFoodTokens() >= subpoints){
|
||||
p.removeFood(subpoints);
|
||||
}else{
|
||||
subpoints -= p.getFoodTokens();
|
||||
p.removeFood(p.getFoodTokens());
|
||||
p.removePrestigePoints(subpoints*event.getFirstValue());
|
||||
}
|
||||
|
||||
result.add(p.getFoodTokens());
|
||||
result.add(p.getPrestigePoints());
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<Integer> hunt(EventCard event, List<Player> players){
|
||||
if(event.getEvent() != Event.HUNT){throw new EventsManagerException("Not a hunt card");}
|
||||
|
||||
List<Integer> result = new ArrayList<>();
|
||||
|
||||
for(Player p: players){
|
||||
p.addFood(p.getPlayerTribe().huntersNumber());
|
||||
p.addPrestigePoints(p.getPlayerTribe().huntersNumber()*event.getFirstValue());
|
||||
|
||||
if(BuildingManager.hunterBonus(p)){
|
||||
p.addFood(p.getPlayerTribe().huntersNumber());
|
||||
p.addPrestigePoints(p.getPlayerTribe().huntersNumber());
|
||||
}
|
||||
|
||||
result.add(p.getFoodTokens());
|
||||
result.add(p.getPrestigePoints());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<Integer> shamanicRitual(EventCard event, List<Player> players){
|
||||
if(event.getEvent() != Event.SHAMANIC_RITUAL){throw new EventsManagerException("Not a shamanic ritual card");}
|
||||
List<Integer> result = new ArrayList<>();
|
||||
int maxSymbols = 0;
|
||||
int minSymbols = 999;
|
||||
|
||||
for(Player p: players){
|
||||
int symbols = p.getPlayerTribe().shamansIcons() + BuildingManager.shamanBonus(p);
|
||||
if (symbols > maxSymbols){maxSymbols = p.getPlayerTribe().shamansIcons();}
|
||||
if (symbols < minSymbols){minSymbols = p.getPlayerTribe().shamansIcons();}
|
||||
}
|
||||
|
||||
for(Player p: players){
|
||||
if(p.getPlayerTribe().shamansIcons() == maxSymbols){
|
||||
p.addPrestigePoints(event.getFirstValue());
|
||||
|
||||
//activating building shamanDoublePoints card effect
|
||||
if(BuildingManager.shamanDoublePoints(p))
|
||||
p.addPrestigePoints(event.getFirstValue());
|
||||
}
|
||||
if(p.getPlayerTribe().shamansIcons() == minSymbols){
|
||||
|
||||
//activating building shamanNoLoss card effect
|
||||
if(!BuildingManager.shamanNoLoss(p))
|
||||
p.removePrestigePoints(event.getSecondValue());
|
||||
}
|
||||
result.add(p.getPrestigePoints());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<Integer> cavePaintings(EventCard event, List<Player> players){
|
||||
|
||||
if(event.getEvent() != Event.CAVE_PAINTINGS){throw new EventsManagerException("Not a cave painting card");}
|
||||
List<Integer> result = new ArrayList<>();
|
||||
for(Player p: players){
|
||||
BuildingManager.paintingFoodBonus(p);
|
||||
if(p.getPlayerTribe().artistsNumber() >= event.getFirstValue()){
|
||||
p.addPrestigePoints(p.getPlayerTribe().artistsNumber()*event.getSecondValue());
|
||||
}else{
|
||||
p.removePrestigePoints(event.getSecondValue());
|
||||
}
|
||||
|
||||
result.add(p.getPrestigePoints());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
395
src/main/java/Server/GameBoard.java
Normal file
@@ -0,0 +1,395 @@
|
||||
package Server;
|
||||
|
||||
import Server.Automaton.Game;
|
||||
import Server.Cards.*;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Represents the physical game board: the two card rows, the offering tiles,
|
||||
* the turn-order tile, and the card deck.
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Owning and mutating the top and bottom card rows.
|
||||
* - Owning the OfferingTiles and the TurnTile.
|
||||
* - Performing end-of-round row transitions and era-change building swaps.
|
||||
* - Exposing visible EventCards to Game for resolution.
|
||||
*
|
||||
* NOT responsible for:
|
||||
* - Resolving events (that is EventsSolver's job, called by Game).
|
||||
* - Applying player rewards/penalties (that is Game's job).
|
||||
* - Holding a reference to the player list.
|
||||
*/
|
||||
public class GameBoard {
|
||||
private static final Logger logger = LogManager.getLogger(GameBoard.class);
|
||||
// -------------------------------------------------------------------------
|
||||
// Fields
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
private Era era;
|
||||
|
||||
private final CardDeck cardDeck;
|
||||
private final List<Card> topRow;
|
||||
private final List<Card> bottomRow;
|
||||
private final List<OfferingTile> offeringTiles;
|
||||
private final TurnTile turnTile;
|
||||
private final BuildingManager buildingManager;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates the board for a new game.
|
||||
* Call {@link #setupInitialRows(int)} and {@link #initOfferingTiles(int)}
|
||||
* separately after construction (mirrors the rulebook setup steps).
|
||||
*/
|
||||
public GameBoard(Era startingEra, CardDeck cardDeck, int numPlayers) {
|
||||
this.era = startingEra;
|
||||
this.cardDeck = cardDeck;
|
||||
this.topRow = new ArrayList<>();
|
||||
this.bottomRow = new ArrayList<>();
|
||||
this.offeringTiles = new ArrayList<>();
|
||||
this.turnTile = new TurnTile(numPlayers);
|
||||
this.buildingManager = new BuildingManager();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Setup
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates and places the correct OfferingTiles for the given player count.
|
||||
*
|
||||
* Tile layout (from the rulebook):
|
||||
* orderId 0 → tile A: 3 food (5-player only)
|
||||
* orderId 1 → tile B: 1 DOWN (all)
|
||||
* orderId 2 → tile C: 1 UP (all)
|
||||
* orderId 3 → tile D: 2 DOWN (3+ players)
|
||||
* orderId 4 → tile E: 1 DOWN 1 UP (all)
|
||||
* orderId 5 → tile F: 2 UP (all)
|
||||
* orderId 6 → tile G: 1 DOWN 2 UP (4+ players)
|
||||
*
|
||||
* With n players, exactly n tiles are used, starting from tile A if
|
||||
* 5 players, otherwise starting from tile B.
|
||||
*/
|
||||
public void initOfferingTiles(int numPlayers) {
|
||||
offeringTiles.clear();
|
||||
switch (numPlayers) {
|
||||
case 2:
|
||||
offeringTiles.add(new OfferingTile(1));
|
||||
offeringTiles.add(new OfferingTile(2));
|
||||
offeringTiles.add(new OfferingTile(4));
|
||||
offeringTiles.add(new OfferingTile(5));
|
||||
break;
|
||||
case 3:
|
||||
offeringTiles.add(new OfferingTile(1));
|
||||
offeringTiles.add(new OfferingTile(2));
|
||||
offeringTiles.add(new OfferingTile(3));
|
||||
offeringTiles.add(new OfferingTile(4));
|
||||
offeringTiles.add(new OfferingTile(5));
|
||||
break;
|
||||
case 4:
|
||||
offeringTiles.add(new OfferingTile(1));
|
||||
offeringTiles.add(new OfferingTile(2));
|
||||
offeringTiles.add(new OfferingTile(3));
|
||||
offeringTiles.add(new OfferingTile(4));
|
||||
offeringTiles.add(new OfferingTile(5));
|
||||
offeringTiles.add(new OfferingTile(6));
|
||||
break;
|
||||
case 5:
|
||||
offeringTiles.add(new OfferingTile(0));
|
||||
offeringTiles.add(new OfferingTile(1));
|
||||
offeringTiles.add(new OfferingTile(2));
|
||||
offeringTiles.add(new OfferingTile(3));
|
||||
offeringTiles.add(new OfferingTile(4));
|
||||
offeringTiles.add(new OfferingTile(5));
|
||||
offeringTiles.add(new OfferingTile(6));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Find the oddertingTile selected by Player
|
||||
public OfferingTile getOfferingTile(Player p){
|
||||
OfferingTile offering = offeringTiles.stream().filter(o -> p.equals(o.getOccupant())).findFirst().orElse(null);
|
||||
return offering;
|
||||
}
|
||||
/**
|
||||
* Draws the initial two rows of cards according to rulebook setup steps 4-5:
|
||||
*
|
||||
* Bottom row: draw cards one at a time until (numPlayers + 1) Character cards
|
||||
* have been placed. Any Event card drawn is placed in the top row instead.
|
||||
* Top row: fill to (numPlayers + 4) with additional draws (accounting for
|
||||
* any events already placed there from the bottom-row draw).
|
||||
*/
|
||||
public void setupInitialRows(int numPlayers) {
|
||||
topRow.clear();
|
||||
bottomRow.clear();
|
||||
|
||||
// Draw bottom row — events are bumped to top row
|
||||
while (bottomRow.size() < numPlayers + 1) {
|
||||
Card card = cardDeck.drawTribeOne();
|
||||
if (card instanceof EventCard) {
|
||||
topRow.add(card);
|
||||
logger.info("Setup: Event card " + card.getCardId() + " moved to top row.");
|
||||
} else {
|
||||
bottomRow.add(card);
|
||||
}
|
||||
}
|
||||
|
||||
// Fill top row up to numPlayers + 4
|
||||
int needed = (numPlayers + 4) - topRow.size();
|
||||
if (needed > 0) {
|
||||
topRow.addAll(cardDeck.drawTribe(needed));
|
||||
}
|
||||
|
||||
// Add all Building Era.I on top row 2P 1 3-4-5 2
|
||||
topRow.add(cardDeck.drawBuildingOne(Era.I));
|
||||
if (numPlayers > 2){
|
||||
topRow.add(cardDeck.drawBuildingOne(Era.I));
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// End-of-round row management (rulebook "Fine del Round" steps 2-4)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Performs the three row-management steps at the end of every round:
|
||||
*
|
||||
* Step 2 — Discard all Character and Event cards from the bottom row.
|
||||
* Building cards stay.
|
||||
* Step 3 — Move all Character and Event cards from the top row down to
|
||||
* the bottom row. Building cards stay in the top row.
|
||||
* Step 4 — Draw (numPlayers + 4) new cards into the top row.
|
||||
*
|
||||
* @return true if the newly drawn cards contain a card from the next Era,
|
||||
* signalling that {@link #triggerEraChange()} should be called.
|
||||
*/
|
||||
public boolean advanceRows(int numPlayers) {
|
||||
|
||||
Era eraBeforeDraw = this.era;
|
||||
|
||||
// Step 2: discard non-building cards from the bottom row
|
||||
bottomRow.removeIf(
|
||||
c -> !(c instanceof BuildingCard)
|
||||
);
|
||||
|
||||
// Step 3: move non-building cards from top row down to bottom row
|
||||
Iterator<Card> it = topRow.iterator();
|
||||
while (it.hasNext()) {
|
||||
Card c = it.next();
|
||||
if (!(c instanceof BuildingCard)) {
|
||||
logger.debug("move card from top to bottom " + c);
|
||||
bottomRow.add(c);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: draw fresh cards into the top row
|
||||
List<Card> newCards = cardDeck.drawTribe(numPlayers + 4);
|
||||
topRow.addAll(newCards);
|
||||
logger.info("NEW CARDS ON TOP {} " , newCards);
|
||||
return isNewEraRevealed(eraBeforeDraw, newCards);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if any of the newly drawn cards belongs to an era
|
||||
* that is strictly later than the current one.
|
||||
*/
|
||||
private boolean isNewEraRevealed(Era currentEra, List<Card> newCards) {
|
||||
for (Card c : newCards) {
|
||||
Era cardEra = eraOf(c);
|
||||
if (cardEra != null && cardEra.ordinal() > currentEra.ordinal()) {
|
||||
logger.info("FOUND NEW ERA {} " , cardEra);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Era change (rulebook "Inizio della Nuova Era")
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Advances the era and performs the three building-row transitions:
|
||||
*
|
||||
* Step 1 — (Era III only) Discard all Building cards from the bottom row.
|
||||
* Step 2 — Move all Building cards from the top row to the bottom row
|
||||
* (to the right of the Tribe cards). [Era II and III]
|
||||
* Step 3 — Place the new era's Building cards face-up in the top row.
|
||||
* [Era II and III]
|
||||
*
|
||||
* @return the new Era after the transition
|
||||
*/
|
||||
public Era triggerEraChange(int numPlayers) {
|
||||
era = era.next(); // Era.I → II → III → FINAL
|
||||
logger.info("ERA CHANGED → {} ", era);
|
||||
|
||||
// Step 1 (Era III only): remove old era buildings from the bottom row
|
||||
if (era == Era.III) {
|
||||
bottomRow.removeIf(c -> c instanceof BuildingCard);
|
||||
}
|
||||
|
||||
// Step 2: move buildings from top row to bottom row
|
||||
List<BuildingCard> descending = new ArrayList<>();
|
||||
Iterator<Card> it = topRow.iterator();
|
||||
while (it.hasNext()) {
|
||||
Card c = it.next();
|
||||
if (c instanceof BuildingCard) {
|
||||
descending.add((BuildingCard) c);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
bottomRow.addAll(descending);
|
||||
logger.info("event=MOVED_BUILING era={} count={} cards={}", era, descending.size(), descending);
|
||||
|
||||
// Step 3: place the new era's building cards in the top row
|
||||
int n = BuildingRules.getBuildingCards(numPlayers, era);
|
||||
List<Card> newEraBuildings = cardDeck.drawBuilding(n , era);
|
||||
topRow.addAll(newEraBuildings);
|
||||
|
||||
logger.info("event=ADD_BUILDINGS era={} count={} cards={}", era, n, newEraBuildings);
|
||||
return era;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Offering tiles
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Attempts to place a player's totem on an offering tile.
|
||||
*
|
||||
* @return true if successful; false if the tile was already occupied
|
||||
*/
|
||||
public boolean placeTotem(Player player, OfferingTile tile, TurnTile turntile) {
|
||||
if (!tile.isEmpty()) return false;
|
||||
tile.setOccupant(player);
|
||||
turntile.leaveTurnTile(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all totems from offering tiles. Call at the start of each new round.
|
||||
*/
|
||||
public void clearOfferingTiles() {
|
||||
for (OfferingTile tile : offeringTiles) {
|
||||
tile.removeOccupant();
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Card removal (called by Game when a player takes a card)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Removes a card from the top row by ID and returns it.
|
||||
*
|
||||
* @return the card, or null if no card with that ID exists in the top row
|
||||
*/
|
||||
public Card takeFromTopRow(int cardId) {
|
||||
return takeFromRow(topRow, cardId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a card from the bottom row by ID and returns it.
|
||||
*
|
||||
* @return the card, or null if no card with that ID exists in the bottom row
|
||||
*/
|
||||
public Card takeFromBottomRow(int cardId) {
|
||||
return takeFromRow(bottomRow, cardId);
|
||||
}
|
||||
|
||||
private Card takeFromRow(List<Card> row, int cardId) {
|
||||
Iterator<Card> it = row.iterator();
|
||||
while (it.hasNext()) {
|
||||
Card c = it.next();
|
||||
if (c.getCardId() == cardId) {
|
||||
it.remove();
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Event visibility
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns all EventCards currently in the bottom row, sorted by era
|
||||
* (ascending) so they are resolved in the correct order.
|
||||
* Sustainment is NOT sorted last here — that is Game's responsibility.
|
||||
*/
|
||||
public List<EventCard> getVisibleEvents() {
|
||||
List<EventCard> events = new ArrayList<>();
|
||||
for (Card c : bottomRow) {
|
||||
if (c instanceof EventCard) {
|
||||
events.add((EventCard) c);
|
||||
}
|
||||
}
|
||||
events.sort((a, b) -> a.getEra().ordinal() - b.getEra().ordinal());
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns EventCards from BOTH rows.
|
||||
* Used during the final round when all visible events must be resolved.
|
||||
*/
|
||||
public List<EventCard> getAllVisibleEvents() {
|
||||
List<EventCard> events = new ArrayList<>();
|
||||
for (Card c : bottomRow) {
|
||||
if (c instanceof EventCard) events.add((EventCard) c);
|
||||
}
|
||||
for (Card c : topRow) {
|
||||
if (c instanceof EventCard) events.add((EventCard) c);
|
||||
}
|
||||
events.sort((a, b) -> a.getEra().ordinal() - b.getEra().ordinal());
|
||||
return events;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Extracts the Era from a card, returning null for building cards. */
|
||||
private Era eraOf(Card c) {
|
||||
if (c instanceof CharacterCard) return ((CharacterCard) c).getEra();
|
||||
if (c instanceof EventCard) return ((EventCard) c).getEra();
|
||||
return null;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Getters
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public Era getEra() { return era; }
|
||||
public List<Card> getTopRow() { return topRow; }
|
||||
public List<Card> getBottomRow() { return bottomRow; }
|
||||
public List<OfferingTile> getOfferingTiles() { return offeringTiles; }
|
||||
public TurnTile getTurnTile() { return turnTile; }
|
||||
public BuildingManager getBuildingManager() { return buildingManager; }
|
||||
public CardDeck getCardDeck() { return cardDeck; }
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GameBoard{" +
|
||||
"era=" + era +
|
||||
",\n offeringTiles=" + offeringTiles +
|
||||
",\n turnTile=" + turnTile +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
148
src/main/java/Server/OfferingTile.java
Normal file
@@ -0,0 +1,148 @@
|
||||
package Server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Represents a single tile on the offering track.
|
||||
*
|
||||
* Each tile has a fixed letter (A–G) and a fixed list of actions the
|
||||
* occupying player must resolve. The tile is either empty or occupied
|
||||
* by exactly one player's totem at any given time.
|
||||
*
|
||||
* Tile layout (from the rulebook):
|
||||
*
|
||||
* Letter │ orderId │ Actions │ Player count
|
||||
* ───────┼─────────┼──────────────────────┼─────────────
|
||||
* A │ 0 │ FOOD FOOD FOOD │ 5 only
|
||||
* B │ 1 │ BOTTOM │ all
|
||||
* C │ 2 │ UP │ all
|
||||
* D │ 3 │ BOTTOM BOTTOM │ 3+
|
||||
* E │ 4 │ BOTTOM UP │ all
|
||||
* F │ 5 │ UP UP │ all
|
||||
* G │ 6 │ BOTTOM UP UP │ 4+
|
||||
*
|
||||
* Which tiles are included in a game is decided by GameBoard.initOfferingTiles(),
|
||||
* not by this class.
|
||||
*/
|
||||
public class OfferingTile {
|
||||
|
||||
private static final char FIRST_LETTER = 'A';
|
||||
|
||||
private final int orderId;
|
||||
private final char letter;
|
||||
private final List<Symbol> actions; // unmodifiable after construction
|
||||
private Player occupant;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Constructor
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public OfferingTile(int orderId) {
|
||||
this.orderId = orderId;
|
||||
this.letter = (char) (FIRST_LETTER + orderId);
|
||||
this.occupant = null;
|
||||
this.actions = Collections.unmodifiableList(buildActions(orderId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fixed action list for each tile orderId.
|
||||
* Extracted into a private method to keep the constructor clean.
|
||||
*/
|
||||
private static List<Symbol> buildActions(int orderId) {
|
||||
List<Symbol> list = new ArrayList<>();
|
||||
switch (orderId) {
|
||||
case 0: // A — food tile (5p only)
|
||||
list.add(Symbol.FOOD);
|
||||
list.add(Symbol.FOOD);
|
||||
list.add(Symbol.FOOD);
|
||||
break;
|
||||
case 1: // B
|
||||
list.add(Symbol.DOWN);
|
||||
break;
|
||||
case 2: // C
|
||||
list.add(Symbol.UP);
|
||||
break;
|
||||
case 3: // D
|
||||
list.add(Symbol.DOWN);
|
||||
list.add(Symbol.DOWN);
|
||||
break;
|
||||
case 4: // E
|
||||
list.add(Symbol.DOWN);
|
||||
list.add(Symbol.UP);
|
||||
break;
|
||||
case 5: // F
|
||||
list.add(Symbol.UP);
|
||||
list.add(Symbol.UP);
|
||||
break;
|
||||
case 6: // G
|
||||
list.add(Symbol.DOWN);
|
||||
list.add(Symbol.UP);
|
||||
list.add(Symbol.UP);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid OfferingTile orderId: " + orderId);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Occupant management
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Returns true if no totem is currently placed on this tile. */
|
||||
public boolean isEmpty() {
|
||||
return occupant == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Places a player's totem on this tile.
|
||||
* Callers should check {@link #isEmpty()} before calling this.
|
||||
*/
|
||||
public void setOccupant(Player player) {
|
||||
this.occupant = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the totem from this tile and returns the player who was on it,
|
||||
* or null if the tile was already empty.
|
||||
*/
|
||||
public Player removeOccupant() {
|
||||
Player previous = this.occupant;
|
||||
this.occupant = null;
|
||||
return previous;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Getters
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** The player currently occupying this tile, or null if empty. */
|
||||
public Player getOccupant() {
|
||||
return occupant;
|
||||
}
|
||||
|
||||
/**
|
||||
* The actions this tile grants to its occupant (e.g. [BOTTOM, UP]).
|
||||
* The returned list is unmodifiable.
|
||||
*/
|
||||
public List<Symbol> getActions() {
|
||||
return actions;
|
||||
}
|
||||
|
||||
/** 0-based position index; determines the tile's letter and action set. */
|
||||
public int getOrderId() {
|
||||
return orderId;
|
||||
}
|
||||
|
||||
/** The tile's letter label ('A'–'G'), useful for display and logging. */
|
||||
public char getLetter() {
|
||||
return letter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Tile " + letter + " " + actions + (isEmpty() ? " [empty]" : " [" + occupant.getNickname() + "]");
|
||||
}
|
||||
}
|
||||
96
src/main/java/Server/Player.java
Normal file
@@ -0,0 +1,96 @@
|
||||
package Server;
|
||||
|
||||
import Server.Cards.CharacterCard;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Player {
|
||||
|
||||
//Attributes
|
||||
private String nickname;
|
||||
private TotemColor totemColor;
|
||||
private int foodTokens;
|
||||
private int prestigePoints;
|
||||
private Tribe playerTribe;
|
||||
|
||||
|
||||
//Constructor
|
||||
public Player(String nickname, TotemColor totemColor) {
|
||||
this.nickname = nickname;
|
||||
this.totemColor = totemColor;
|
||||
this.foodTokens = 0;
|
||||
this.prestigePoints = 0;
|
||||
this.playerTribe = new Tribe();
|
||||
}
|
||||
|
||||
//Methods
|
||||
public void addFood(int food){
|
||||
this.foodTokens += food;
|
||||
}
|
||||
|
||||
public boolean removeFood(int food){
|
||||
if (this.foodTokens >= food) {
|
||||
this.foodTokens -= food;
|
||||
return true; // Pagamento andato a buon fine
|
||||
}
|
||||
return false; // Il giocatore non ha abbastanza cibo, transazione negata, la quantità di cibo rimane quella di prima.
|
||||
}
|
||||
|
||||
public void addPrestigePoints(int prestige){
|
||||
this.prestigePoints += prestige;
|
||||
}
|
||||
|
||||
public int removePrestigePoints(int prestige){
|
||||
this.prestigePoints -= prestige;
|
||||
return prestigePoints;
|
||||
}
|
||||
|
||||
public void addCharacterToTribe(CharacterCard card) {
|
||||
int foodGained = this.playerTribe.addCharacter(card);
|
||||
this.addFood(foodGained);
|
||||
}
|
||||
|
||||
//Getters
|
||||
public String getNickname() {
|
||||
return nickname;
|
||||
}
|
||||
|
||||
public int getFoodTokens() {
|
||||
return foodTokens;
|
||||
}
|
||||
|
||||
public int getPrestigePoints() {
|
||||
return prestigePoints;
|
||||
}
|
||||
|
||||
public TotemColor getTotemColor() {
|
||||
return totemColor;
|
||||
}
|
||||
|
||||
public Tribe getPlayerTribe() {
|
||||
return playerTribe;
|
||||
}
|
||||
|
||||
// two Player objects to be considered equal only by nickname
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Player player = (Player) o;
|
||||
return Objects.equals(nickname, player.nickname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(nickname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Player(" +
|
||||
"name='" + nickname + '\'' +
|
||||
", food=" + foodTokens +
|
||||
", pp=" + prestigePoints +
|
||||
')';
|
||||
}
|
||||
}
|
||||
7
src/main/java/Server/Symbol.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package Server;
|
||||
|
||||
public enum Symbol {
|
||||
UP,
|
||||
DOWN,
|
||||
FOOD
|
||||
}
|
||||
21
src/main/java/Server/TotemColor.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package Server;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
|
||||
public enum TotemColor {
|
||||
RED(Color.RED),
|
||||
BLUE(Color.BLUE),
|
||||
YELLOW(Color.YELLOW),
|
||||
GREEN(Color.GREEN),
|
||||
PURPLE(Color.PURPLE);
|
||||
|
||||
private final Color fxColor;
|
||||
|
||||
TotemColor(Color fxColor) {
|
||||
this.fxColor = fxColor;
|
||||
}
|
||||
|
||||
public Color getFxColor() {
|
||||
return fxColor;
|
||||
}
|
||||
}
|
||||
239
src/main/java/Server/Tribe.java
Normal file
@@ -0,0 +1,239 @@
|
||||
package Server;
|
||||
|
||||
import Server.Cards.BuildingCard;
|
||||
import Server.Cards.CharacterCard;
|
||||
import Server.Cards.CharacterType;
|
||||
import Server.Cards.Trigger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
|
||||
public class Tribe {
|
||||
// Attributes
|
||||
private List<CharacterCard> characters;
|
||||
private List<BuildingCard> buildings;
|
||||
|
||||
// Constructor
|
||||
public Tribe() {
|
||||
this.characters = new ArrayList<>();
|
||||
this.buildings = new ArrayList<>();
|
||||
}
|
||||
|
||||
public List<CharacterCard> getCharacters() {
|
||||
return characters;
|
||||
}
|
||||
public List<BuildingCard> getBuildingCard() {
|
||||
return buildings;
|
||||
}
|
||||
// METODI
|
||||
|
||||
|
||||
public int addCharacter(CharacterCard card) {
|
||||
this.characters.add(card);
|
||||
if (card.getCharacterType().equals(CharacterType.HUNTER)) {
|
||||
return hunterGetFood(card);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Metodo per aggiungere un nuovo building alla tribù
|
||||
public void addBuilding(BuildingCard card) {
|
||||
this.buildings.add(card);
|
||||
}
|
||||
|
||||
// Metodo per ottenere lo sconto in cibo in base a quanti gatherer abbiamo nella tribù
|
||||
public int gathererDiscount() {
|
||||
int discount = 0;
|
||||
for (CharacterCard c : characters) {
|
||||
if (c.getCharacterType() == CharacterType.GATHERER) {
|
||||
discount += 3; // i gatherers prendono sempre 3 cibi
|
||||
}
|
||||
}
|
||||
return discount;
|
||||
}
|
||||
|
||||
// Metodo per ottenere lo sconto totale sugli edifici grazie ai builder nella tribù
|
||||
public int buildersDiscount() {
|
||||
int discount = 0;
|
||||
for (CharacterCard c : characters) {
|
||||
if (c.getCharacterType() == CharacterType.BUILDER) {
|
||||
discount += c.getIconValue(); // con getIconValue intendo lo sconto del costruttore
|
||||
}
|
||||
}
|
||||
return discount;
|
||||
}
|
||||
|
||||
// Metodo che conta quante stelle degli sciamani abbiamo in totale nella tribù
|
||||
public int shamansIcons() {
|
||||
int totalIcons = 0;
|
||||
for (CharacterCard c : characters) {
|
||||
if (c.getCharacterType() == CharacterType.SHAMAN) {
|
||||
totalIcons += c.getIconValue();
|
||||
}
|
||||
}
|
||||
return totalIcons;
|
||||
}
|
||||
|
||||
// Metodo che restituisce il numero di artisti nella tribù
|
||||
public int artistsNumber() {
|
||||
return countCharactersByType(CharacterType.ARTIST);
|
||||
}
|
||||
|
||||
// Metodo che restituisce il numero di cacciatori nella tribù
|
||||
public int huntersNumber() {
|
||||
return countCharactersByType(CharacterType.HUNTER);
|
||||
}
|
||||
|
||||
// Metodo universale per contare le carte di un certo tipo all'interno della tribù
|
||||
public int countCharactersByType(CharacterType typeToCount) {
|
||||
int count = 0;
|
||||
for (CharacterCard c : characters) {
|
||||
if (c.getCharacterType() == typeToCount) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Metodo che ritorna il numero totale di cibi ottenuti dopo aver pescato il cacciatore col cosciotto
|
||||
public int hunterGetFood(CharacterCard hunter) {
|
||||
return huntersNumber() * hunter.getIconValue(); // getIconValue = 1 se il cacciatore ha il cosciotto
|
||||
}
|
||||
|
||||
// Metodo che restituisce i punti finali degli inventori
|
||||
public int inventorsEndPoints() {
|
||||
int inventorCount = 0;
|
||||
List<Integer> uniqueInventions = new ArrayList<>();
|
||||
|
||||
for (CharacterCard c : characters) {
|
||||
if (c.getCharacterType() == CharacterType.INVENTOR) {
|
||||
inventorCount++;
|
||||
|
||||
int inventionId = c.getIconValue(); // Usiamo l'iconValue del file cards.csv
|
||||
|
||||
// Se non abbiamo ancora contato questa invenzione, la aggiungiamo
|
||||
if (!uniqueInventions.contains(inventionId)) {
|
||||
uniqueInventions.add(inventionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return inventorCount * uniqueInventions.size();
|
||||
}
|
||||
|
||||
// Metodo che restituisce i punti finali degli artisti
|
||||
public int artistsEndPoints() {
|
||||
return (artistsNumber() / 2) * 10; // in java 1/2 fa 0
|
||||
}
|
||||
|
||||
// Metodo che restituisce i punti finali dei costruttori
|
||||
public int buildersEndPoints() {
|
||||
int points = 0;
|
||||
for (CharacterCard c : characters) {
|
||||
if (c.getCharacterType() == CharacterType.BUILDER) {
|
||||
points += c.getPrestigePoints();
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
// Metodo che restituisce i punti finali guadagnati grazie agli EFFETTI delle carte building
|
||||
private int buildingAbilitiesEndPoints() {
|
||||
int bonusPoints = 0;
|
||||
|
||||
for (BuildingCard b : buildings) {
|
||||
Trigger trigger = b.getAbilityTrigger(); // leggiamo il trigger della carta edificio
|
||||
|
||||
// Se la carta per qualche motivo non ha trigger, passiamo alla prossima
|
||||
if (trigger == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (trigger) {
|
||||
case ENDGAME_BUILDER_BONUS: // id carta: 107
|
||||
bonusPoints += (buildersEndPoints() * 2);
|
||||
break;
|
||||
|
||||
case ENDGAME_FOR_SIX: // id carta: 109
|
||||
// Prepariamo i contatori per tutti e 6 i tipi di characters
|
||||
int inv = 0, hun = 0, gat = 0, sha = 0, art = 0, bui = 0;
|
||||
|
||||
// contiamo le carte nella tribù
|
||||
for (CharacterCard c : characters) {
|
||||
switch (c.getCharacterType()) {
|
||||
case INVENTOR: inv++; break;
|
||||
case HUNTER: hun++; break;
|
||||
case GATHERER: gat++; break;
|
||||
case SHAMAN: sha++; break;
|
||||
case ARTIST: art++; break;
|
||||
case BUILDER: bui++; break;
|
||||
}
|
||||
}
|
||||
|
||||
// troviamo il numero di set completi
|
||||
int min1 = Math.min(inv, hun);
|
||||
int min2 = Math.min(gat, sha);
|
||||
int min3 = Math.min(art, bui);
|
||||
int completeSets = Math.min(Math.min(min1, min2), min3);
|
||||
|
||||
// aggiungiamo 6 punti prestigio per ogni set completo
|
||||
bonusPoints += (completeSets * 6);
|
||||
break;
|
||||
|
||||
case ENDGAME_BONUS_CHARACTER:
|
||||
|
||||
int id = b.getCardId(); // uso l'id della carta per capire che edificio è
|
||||
|
||||
// il numero id corrisponde al numero di pagina nel pdf
|
||||
if (id == 110) { // edificio dei cacciatori
|
||||
bonusPoints += countCharactersByType(CharacterType.HUNTER) * 3;
|
||||
}
|
||||
else if (id == 111) { // edificio dei gatherer
|
||||
bonusPoints += countCharactersByType(CharacterType.GATHERER) * 4;
|
||||
}
|
||||
else if (id == 112) { // edificio degli sciamani
|
||||
bonusPoints += countCharactersByType(CharacterType.SHAMAN) * 4;
|
||||
}
|
||||
else if (id == 113) { // edificio dei costruttori
|
||||
bonusPoints += countCharactersByType(CharacterType.BUILDER) * 4;
|
||||
}
|
||||
else if (id == 114) { // edificio degli artisti
|
||||
bonusPoints += countCharactersByType(CharacterType.ARTIST) * 4;
|
||||
}
|
||||
else if (id == 115) { // edificio degli inventori
|
||||
bonusPoints += countCharactersByType(CharacterType.INVENTOR) * 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case ENDGAME_BONUS_POINTS: // id carta: 117
|
||||
bonusPoints += 25; // dà 25 punti bonus
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return bonusPoints;
|
||||
}
|
||||
|
||||
// Metodo che calcola i punti finali totali
|
||||
public int endPoints() {
|
||||
int total = 0;
|
||||
|
||||
// sommiamo i punti calcolati dai vari personaggi
|
||||
total += inventorsEndPoints();
|
||||
total += artistsEndPoints();
|
||||
total += buildersEndPoints();
|
||||
|
||||
// sommiamo i punti prestigio BASE di tutti gli edifici (EndPP)
|
||||
for (BuildingCard b : buildings) {
|
||||
total += b.getEndPP();
|
||||
}
|
||||
|
||||
// sommiamo gli effetti degli edifici sul punteggio finale, NON quelli durante la partita
|
||||
total += buildingAbilitiesEndPoints();
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
176
src/main/java/Server/TurnTile.java
Normal file
@@ -0,0 +1,176 @@
|
||||
package Server;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the Turn Order tile.
|
||||
*
|
||||
* Lifecycle per round:
|
||||
* 1. At round start, read positions top-to-bottom via nextToPlace() to know
|
||||
* which player places their totem on the offering track first.
|
||||
* 2. After a player resolves all their offering actions, they call returnTotem().
|
||||
* returnTotem() places them in the next free slot (top-to-bottom) and
|
||||
* immediately gives them the position reward/penalty.
|
||||
* 3. The order in which players called returnTotem() becomes the new turn
|
||||
* order for the NEXT round.
|
||||
* 4. resetTrack() is called at the start of each new round to restart the
|
||||
* placement cursor and the return-slot counter, WITHOUT clearing positions
|
||||
* (they already hold the new order from step 2-3).
|
||||
*/
|
||||
public class TurnTile {
|
||||
private static final Logger logger = LogManager.getLogger(TurnTile.class);
|
||||
private final Player[] positions; // current turn order; updated each round via returnTotem()
|
||||
private int nextFreeSlot; // next available slot for a returning totem
|
||||
private int placementCursor; // cursor used during the totem-placement phase
|
||||
|
||||
public TurnTile(int numP) {
|
||||
this.positions = new Player[numP];
|
||||
this.nextFreeSlot = 0;
|
||||
this.placementCursor = 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Setup
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Randomises the initial turn order. Call once during game setup.
|
||||
*/
|
||||
public void setInitialOrder(List<Player> players) {
|
||||
|
||||
List<Player> shuffled = new ArrayList<>(players);
|
||||
Collections.shuffle(shuffled);
|
||||
for (int i = 0; i < shuffled.size(); i++) {
|
||||
positions[i] = shuffled.get(i);
|
||||
}
|
||||
logger.info("setInitialOrder " + this);
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Totem-placement phase (phase 1 of a round)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the next player who must place their totem on the offering track
|
||||
* (following the current turn order, top to bottom).
|
||||
* Returns null when all players have already been served this round.
|
||||
*/
|
||||
public Player nextToPlace() {
|
||||
if (placementCursor < positions.length) {
|
||||
return positions[placementCursor++];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the player who is currently expected to place their totem
|
||||
* (i.e. the last player returned by nextToPlace), or null if none yet.
|
||||
*/
|
||||
public Player getLastPlacedPlayer() {
|
||||
if (placementCursor > 0) {
|
||||
return positions[placementCursor - 1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Action-resolution phase (phase 2 of a round)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Called when a player has finished resolving all their offering actions.
|
||||
* Places the player's totem in the next free slot (determining next-round
|
||||
* order) and applies the food reward or penalty for that slot.
|
||||
*
|
||||
* Reward rules (from the rulebook):
|
||||
* - Slot 0 (first to return): +1 food (2p), +2 food (3-4p), +3 food (5p)
|
||||
* - Slot 1 (second to return, only 4-5 player games): +1 food
|
||||
* - Last slot: pay 1 food; if unable, lose 2 PP instead
|
||||
*
|
||||
* @return the slot index the player was placed in
|
||||
*/
|
||||
public int returnTotem(Player player) {
|
||||
logger.info("returnTotem " + player);
|
||||
int slot = nextFreeSlot;
|
||||
|
||||
// --- Position food reward ---
|
||||
int positionFood = 0;
|
||||
if (slot == 0) {
|
||||
positionFood = (positions.length == 2) ? 1
|
||||
: (positions.length == 5) ? 3
|
||||
: 2; // 3 or 4 players
|
||||
} else if (slot == 1 && positions.length >= 4) {
|
||||
positionFood = 1;
|
||||
}
|
||||
player.addFood(positionFood);
|
||||
|
||||
// --- Activate BONUS_FOOD_ENDTURN building if the player has it ---
|
||||
// (The building gives +1 extra food whenever the player lands on a food slot)
|
||||
BuildingManager.bonusEndTurn(player, positionFood);
|
||||
|
||||
// --- Last-slot penalty ---
|
||||
if (slot == positions.length - 1) {
|
||||
if (!player.removeFood(1)) {
|
||||
player.removePrestigePoints(2);
|
||||
}
|
||||
}
|
||||
|
||||
positions[slot] = player;
|
||||
nextFreeSlot++;
|
||||
|
||||
logger.info(player.getNickname() + " returned totem to slot " + slot
|
||||
+ (positionFood > 0 ? " and received " + positionFood + " food" : ""));
|
||||
return slot;
|
||||
}
|
||||
|
||||
public void leaveTurnTile(Player player) {
|
||||
for(int i=0;i<positions.length;i++)
|
||||
if (positions[i] !=null && positions[i].equals(player)) positions[i]=null;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Round reset
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Resets the cursors for a new round.
|
||||
* Does NOT clear positions: those already contain the new turn order
|
||||
* established during the previous round's returnTotem() calls.
|
||||
*/
|
||||
public void resetTrack() {
|
||||
nextFreeSlot = 0;
|
||||
placementCursor = 0;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Getters
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the full positions array (turn order).
|
||||
* Index 0 = first to act, last index = last to act.
|
||||
*/
|
||||
public Player[] getPositions() {
|
||||
return positions;
|
||||
}
|
||||
|
||||
/** How many players have already returned their totem this round. */
|
||||
public int getReturnedCount() {
|
||||
return nextFreeSlot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TurnTile{" +
|
||||
"positions=" + Arrays.toString(positions) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
89
src/main/java/Server/TurnTileOld.java
Normal file
@@ -0,0 +1,89 @@
|
||||
package Server;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class TurnTileOld {
|
||||
|
||||
private final Player[] positions;
|
||||
private int place;
|
||||
private int currentplayer;
|
||||
|
||||
|
||||
public TurnTileOld(int numP) {
|
||||
|
||||
this.positions = new Player[numP];
|
||||
this.place = 0;
|
||||
this.currentplayer = 0;
|
||||
|
||||
}
|
||||
|
||||
public Player[] startOrder (List<Player> players){
|
||||
|
||||
for (Player p: players){
|
||||
|
||||
positions[place]=p;
|
||||
place++;
|
||||
|
||||
}
|
||||
//Collections.shuffle(Arrays.asList(positions));
|
||||
|
||||
return positions;
|
||||
}
|
||||
|
||||
public Player giveReward (Player player){
|
||||
|
||||
if (player == positions[positions.length-1]){
|
||||
|
||||
if (!player.removeFood(1)){
|
||||
|
||||
player.removePrestigePoints(2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
else if (player == positions[0]){
|
||||
|
||||
if (positions.length==2){
|
||||
|
||||
player.addFood(1);
|
||||
}
|
||||
else if (positions.length == 5){
|
||||
|
||||
player.addFood(3);
|
||||
}
|
||||
else{
|
||||
|
||||
player.addFood(2);
|
||||
}
|
||||
}
|
||||
|
||||
else if (player == positions[1] && positions.length >= 4){
|
||||
|
||||
player.addFood(1);
|
||||
}
|
||||
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
public Player nextPlayer() {
|
||||
|
||||
currentplayer++;
|
||||
if (currentplayer== positions.length){
|
||||
currentplayer=0;
|
||||
}
|
||||
|
||||
return positions[currentplayer];
|
||||
}
|
||||
|
||||
public Player addPlayer(Player player){
|
||||
|
||||
positions[currentplayer]=player;
|
||||
|
||||
return positions[currentplayer];
|
||||
|
||||
}
|
||||
}
|
||||
7
src/main/java/Server/Utils/EventsManagerException.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package Server.Utils;
|
||||
|
||||
public class EventsManagerException extends RuntimeException {
|
||||
public EventsManagerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
7
src/main/java/Server/Utils/GameException.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package Server.Utils;
|
||||
|
||||
public class GameException extends RuntimeException {
|
||||
public GameException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
7
src/main/java/Server/Utils/LoadingCardsException.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package Server.Utils;
|
||||
|
||||
public class LoadingCardsException extends RuntimeException {
|
||||
public LoadingCardsException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
18
src/main/java/module-info.java
Normal file
@@ -0,0 +1,18 @@
|
||||
module org.example.mesosll07 {
|
||||
requires javafx.controls;
|
||||
requires javafx.fxml;
|
||||
|
||||
requires org.controlsfx.controls;
|
||||
requires javafx.swing;
|
||||
requires org.apache.pdfbox;
|
||||
requires org.apache.logging.log4j;
|
||||
|
||||
opens org.example.mesosll07 to javafx.fxml;
|
||||
exports org.example.mesosll07;
|
||||
exports Server;
|
||||
opens Server to javafx.fxml;
|
||||
exports Server.Cards;
|
||||
opens Server.Cards to javafx.fxml;
|
||||
exports Server.Automaton;
|
||||
opens Server.Automaton to javafx.fxml;
|
||||
}
|
||||
208
src/main/java/org/example/mesosll07/DeckGridApp.java
Normal file
@@ -0,0 +1,208 @@
|
||||
package org.example.mesosll07;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class DeckGridApp extends Application {
|
||||
|
||||
// Inizializza il Logger
|
||||
private static final Logger logger = LogManager.getLogger(DeckGridApp.class);
|
||||
|
||||
private PDDocument document;
|
||||
private PDFRenderer pdfRenderer;
|
||||
private int totalCards = 0;
|
||||
|
||||
// Contenitori per le tre righe
|
||||
private HBox topRow;
|
||||
private HBox centerRow;
|
||||
private HBox bottomRow;
|
||||
private Button btnShuffle;
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
primaryStage.setTitle("Tavolo da Gioco - Carte Casuali");
|
||||
logger.info("Avvio dell'applicazione JavaFX");
|
||||
|
||||
// Pulsanti
|
||||
Button btnLoad = new Button("Carica PDF Mazzo");
|
||||
btnShuffle = new Button("Rimescola Carte");
|
||||
btnShuffle.setDisable(true); // Disabilitato finché non si carica un PDF
|
||||
|
||||
btnLoad.setOnAction(e -> loadPdf(primaryStage));
|
||||
btnShuffle.setOnAction(e -> distributeRandomCards());
|
||||
|
||||
HBox topMenu = new HBox(15, btnLoad, btnShuffle);
|
||||
topMenu.setAlignment(Pos.CENTER);
|
||||
topMenu.setPadding(new Insets(10));
|
||||
|
||||
// Setup delle tre righe (spazio tra le carte impostato a 10px)
|
||||
topRow = createRowContainer();
|
||||
centerRow = createRowContainer();
|
||||
bottomRow = createRowContainer();
|
||||
|
||||
// Contenitore verticale per le righe
|
||||
VBox tableArea = new VBox(30,
|
||||
new Label("TOP (8 Carte):"), topRow,
|
||||
new Label("CENTER (6 Carte):"), centerRow,
|
||||
new Label("BOTTOM (7 Carte):"), bottomRow
|
||||
);
|
||||
tableArea.setAlignment(Pos.CENTER);
|
||||
tableArea.setPadding(new Insets(20));
|
||||
|
||||
// Mettiamo il tavolo in uno ScrollPane nel caso le carte siano troppo grandi per lo schermo
|
||||
ScrollPane scrollPane = new ScrollPane(tableArea);
|
||||
scrollPane.setFitToWidth(true);
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
root.setTop(topMenu);
|
||||
root.setCenter(scrollPane);
|
||||
|
||||
// Finestra un po' più grande per contenere tutte queste carte
|
||||
Scene scene = new Scene(root, 1200, 800);
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
private HBox createRowContainer() {
|
||||
HBox row = new HBox(15); // 15px di spazio tra una carta e l'altra
|
||||
row.setAlignment(Pos.CENTER);
|
||||
return row;
|
||||
}
|
||||
|
||||
private void loadPdf(Stage stage) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Seleziona il PDF del mazzo di carte");
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("File PDF", "*.pdf"));
|
||||
File file = fileChooser.showOpenDialog(stage);
|
||||
|
||||
if (file != null) {
|
||||
try {
|
||||
if (document != null) {
|
||||
document.close();
|
||||
}
|
||||
logger.info("Caricamento file PDF: {}", file.getAbsolutePath());
|
||||
document = PDDocument.load(file);
|
||||
pdfRenderer = new PDFRenderer(document);
|
||||
totalCards = document.getNumberOfPages();
|
||||
|
||||
logger.info("PDF caricato. Pagine totali (carte): {}", totalCards);
|
||||
btnShuffle.setDisable(false);
|
||||
|
||||
// Distribuisci le carte per la prima volta
|
||||
distributeRandomCards();
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.error("Errore nel caricamento del PDF", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void distributeRandomCards() {
|
||||
if (document == null || totalCards == 0) return;
|
||||
|
||||
logger.info("Inizio rimescolamento e distribuzione carte...");
|
||||
|
||||
// Pulisce il tavolo dalle carte precedenti
|
||||
topRow.getChildren().clear();
|
||||
centerRow.getChildren().clear();
|
||||
bottomRow.getChildren().clear();
|
||||
|
||||
// 1. Crea una lista con tutti gli indici (da 0 al numero totale di pagine)
|
||||
List<Integer> deckIndices = new ArrayList<>();
|
||||
for (int i = 0; i < totalCards; i++) {
|
||||
deckIndices.add(i);
|
||||
}
|
||||
|
||||
// 2. Mescola la lista (Simula la mescolata del mazzo)
|
||||
Collections.shuffle(deckIndices);
|
||||
|
||||
// 3. Distribuisci nelle righe (evitando IndexOutOfBounds se il PDF ha meno di 21 pagine)
|
||||
// Riga Top: 8 carte
|
||||
populateRow(topRow, deckIndices, 0, 8);
|
||||
|
||||
// Riga Center: 6 carte
|
||||
populateRow(centerRow, deckIndices, 8, 6);
|
||||
|
||||
// Riga Bottom: 7 carte
|
||||
populateRow(bottomRow, deckIndices, 14, 7);
|
||||
|
||||
logger.info("Distribuzione completata.");
|
||||
}
|
||||
|
||||
private void populateRow(HBox row, List<Integer> deckIndices, int startIndex, int numberOfCards) {
|
||||
for (int i = 0; i < numberOfCards; i++) {
|
||||
int actualIndex = startIndex + i;
|
||||
|
||||
// Se abbiamo esaurito le carte nel PDF, interrompiamo
|
||||
if (actualIndex >= deckIndices.size()) {
|
||||
logger.warn("Il PDF non ha abbastanza carte per riempire questa riga.");
|
||||
break;
|
||||
}
|
||||
|
||||
int pageNumber = deckIndices.get(actualIndex);
|
||||
ImageView cardImage = createCardImageView(pageNumber);
|
||||
|
||||
if (cardImage != null) {
|
||||
row.getChildren().add(cardImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ImageView createCardImageView(int pageIndex) {
|
||||
try {
|
||||
// Renderizza la pagina. Usiamo 100 DPI invece di 150 per risparmiare RAM,
|
||||
// dato che ora stiamo generando 21 immagini contemporaneamente.
|
||||
BufferedImage bim = pdfRenderer.renderImageWithDPI(pageIndex, 100);
|
||||
Image fxImage = SwingFXUtils.toFXImage(bim, null);
|
||||
|
||||
ImageView imageView = new ImageView(fxImage);
|
||||
// Impostiamo l'altezza fissa per le carte, in modo che stiano sullo schermo
|
||||
imageView.setFitHeight(180);
|
||||
imageView.setPreserveRatio(true);
|
||||
imageView.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.5), 5, 0, 0, 0);");
|
||||
|
||||
return imageView;
|
||||
} catch (IOException e) {
|
||||
logger.error("Errore durante il rendering della pagina {}", pageIndex, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
if (document != null) {
|
||||
document.close();
|
||||
logger.info("Documento PDF chiuso correttamente.");
|
||||
}
|
||||
logger.info("Applicazione terminata.");
|
||||
super.stop();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
}
|
||||
263
src/main/java/org/example/mesosll07/DeckGridApp2.java
Normal file
@@ -0,0 +1,263 @@
|
||||
package org.example.mesosll07;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DeckGridApp2 extends Application {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(DeckGridApp2.class);
|
||||
|
||||
private PDDocument document;
|
||||
private PDFRenderer pdfRenderer;
|
||||
private int totalCards = 0;
|
||||
|
||||
// Contenitori Layout
|
||||
private HBox topRow;
|
||||
private HBox centerRow;
|
||||
private HBox bottomRow;
|
||||
private HBox playersArea; // NUOVO: Area per i giocatori
|
||||
private Button btnShuffle;
|
||||
|
||||
// --- LOGICA DI GIOCO SIMULATA ---
|
||||
public enum CardType {
|
||||
CACCIA, UTENSILI, RITUALI, COSTRUZIONI
|
||||
}
|
||||
|
||||
public static class Card {
|
||||
int pdfPageIndex;
|
||||
CardType type;
|
||||
|
||||
public Card(int pdfPageIndex, CardType type) {
|
||||
this.pdfPageIndex = pdfPageIndex;
|
||||
this.type = type;
|
||||
}
|
||||
public CardType getType() { return type; }
|
||||
}
|
||||
|
||||
public static class Player {
|
||||
String name;
|
||||
int food;
|
||||
int money;
|
||||
List<Card> hand = new ArrayList<>();
|
||||
|
||||
public Player(String name, int food, int money) {
|
||||
this.name = name;
|
||||
this.food = food;
|
||||
this.money = money;
|
||||
}
|
||||
public List<Card> getHand() { return hand; }
|
||||
}
|
||||
// --------------------------------
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
primaryStage.setTitle("Tavolo da Gioco - Board & Players");
|
||||
|
||||
Button btnLoad = new Button("Carica PDF Mazzo");
|
||||
btnShuffle = new Button("Rimescola & Distribuisci");
|
||||
btnShuffle.setDisable(true);
|
||||
|
||||
btnLoad.setOnAction(e -> loadPdf(primaryStage));
|
||||
btnShuffle.setOnAction(e -> distributeAll());
|
||||
|
||||
HBox topMenu = new HBox(15, btnLoad, btnShuffle);
|
||||
topMenu.setAlignment(Pos.CENTER);
|
||||
topMenu.setPadding(new Insets(10));
|
||||
|
||||
topRow = createRowContainer();
|
||||
centerRow = createRowContainer();
|
||||
bottomRow = createRowContainer();
|
||||
|
||||
// NUOVO: Inizializza l'area giocatori
|
||||
playersArea = new HBox(30);
|
||||
playersArea.setAlignment(Pos.CENTER);
|
||||
playersArea.setPadding(new Insets(20));
|
||||
|
||||
VBox tableArea = new VBox(20,
|
||||
new Label("TOP (8 Carte):"), topRow,
|
||||
new Label("CENTER (6 Carte):"), centerRow,
|
||||
new Label("BOTTOM (7 Carte):"), bottomRow,
|
||||
new Label("--- SITUAZIONE GIOCATORI ---"), playersArea
|
||||
);
|
||||
tableArea.setAlignment(Pos.CENTER);
|
||||
tableArea.setPadding(new Insets(20));
|
||||
|
||||
ScrollPane scrollPane = new ScrollPane(tableArea);
|
||||
scrollPane.setFitToWidth(true);
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
root.setTop(topMenu);
|
||||
root.setCenter(scrollPane);
|
||||
|
||||
Scene scene = new Scene(root, 1300, 900);
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
private HBox createRowContainer() {
|
||||
HBox row = new HBox(10);
|
||||
row.setAlignment(Pos.CENTER);
|
||||
return row;
|
||||
}
|
||||
|
||||
private void loadPdf(Stage stage) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("File PDF", "*.pdf"));
|
||||
File file = fileChooser.showOpenDialog(stage);
|
||||
|
||||
if (file != null) {
|
||||
try {
|
||||
if (document != null) document.close();
|
||||
document = PDDocument.load(file);
|
||||
pdfRenderer = new PDFRenderer(document);
|
||||
totalCards = document.getNumberOfPages();
|
||||
btnShuffle.setDisable(false);
|
||||
|
||||
distributeAll();
|
||||
} catch (IOException e) {
|
||||
logger.error("Errore PDF", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void distributeAll() {
|
||||
if (document == null || totalCards == 0) return;
|
||||
|
||||
topRow.getChildren().clear();
|
||||
centerRow.getChildren().clear();
|
||||
bottomRow.getChildren().clear();
|
||||
playersArea.getChildren().clear();
|
||||
|
||||
List<Integer> deck = new ArrayList<>();
|
||||
for (int i = 0; i < totalCards; i++) deck.add(i);
|
||||
Collections.shuffle(deck);
|
||||
|
||||
// Distribuisce sul tavolo le prime 21 carte
|
||||
int index = 0;
|
||||
index = populateTable(topRow, deck, index, 8);
|
||||
index = populateTable(centerRow, deck, index, 6);
|
||||
index = populateTable(bottomRow, deck, index, 7);
|
||||
|
||||
// NUOVO: Simula 2 giocatori con le carte rimanenti
|
||||
Random rand = new Random();
|
||||
List<Player> players = Arrays.asList(
|
||||
new Player("Giocatore 1 (Tribù Rossa)", rand.nextInt(15), rand.nextInt(50)),
|
||||
new Player("Giocatore 2 (Tribù Blu)", rand.nextInt(15), rand.nextInt(50))
|
||||
);
|
||||
|
||||
// Assegna 5 carte a caso a ogni giocatore e simula il loro Tipo
|
||||
CardType[] types = CardType.values();
|
||||
for (Player p : players) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (index < deck.size()) {
|
||||
CardType randomType = types[rand.nextInt(types.length)];
|
||||
p.getHand().add(new Card(deck.get(index), randomType));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Renderizza i giocatori nella UI
|
||||
renderPlayers(players);
|
||||
}
|
||||
|
||||
private int populateTable(HBox row, List<Integer> deck, int startIndex, int amount) {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
if (startIndex >= deck.size()) break;
|
||||
ImageView card = createCardImage(deck.get(startIndex), 150); // Altezza 150px
|
||||
if (card != null) row.getChildren().add(card);
|
||||
startIndex++;
|
||||
}
|
||||
return startIndex;
|
||||
}
|
||||
|
||||
// --- NUOVO: RENDERIZZAZIONE GIOCATORI E RAGGRUPPAMENTO (JAVA 8) ---
|
||||
private void renderPlayers(List<Player> players) {
|
||||
for (Player player : players) {
|
||||
VBox playerBox = new VBox(10);
|
||||
playerBox.setPadding(new Insets(15));
|
||||
playerBox.setStyle("-fx-border-color: #555; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-color: #f9f9f9; -fx-background-radius: 10;");
|
||||
|
||||
// Intestazione Giocatore
|
||||
Label nameLbl = new Label(player.name);
|
||||
nameLbl.setFont(Font.font("System", FontWeight.BOLD, 16));
|
||||
|
||||
// Risorse Cibo e Soldi
|
||||
Label statsLbl = new Label("🍖 Cibo: " + player.food + " | 💰 Money: " + player.money);
|
||||
statsLbl.setTextFill(Color.DARKRED);
|
||||
statsLbl.setFont(Font.font("System", FontWeight.BOLD, 14));
|
||||
|
||||
playerBox.getChildren().addAll(nameLbl, statsLbl);
|
||||
|
||||
// JAVA 8 MAGIA: Raggruppa le carte del giocatore per Tipo!
|
||||
Map<CardType, List<Card>> groupedCards = player.getHand().stream()
|
||||
.collect(Collectors.groupingBy(Card::getType));
|
||||
|
||||
// Itera sui gruppi creati e genera la grafica
|
||||
groupedCards.forEach((type, cardsOfType) -> {
|
||||
Label typeLbl = new Label("Tipo: " + type.name() + " (" + cardsOfType.size() + ")");
|
||||
typeLbl.setFont(Font.font("System", FontWeight.NORMAL, 12));
|
||||
|
||||
HBox cardImagesRow = new HBox(5);
|
||||
for (Card c : cardsOfType) {
|
||||
// Carte più piccole (90px) per l'area giocatore
|
||||
ImageView img = createCardImage(c.pdfPageIndex, 90);
|
||||
if (img != null) cardImagesRow.getChildren().add(img);
|
||||
}
|
||||
|
||||
playerBox.getChildren().addAll(typeLbl, cardImagesRow);
|
||||
});
|
||||
|
||||
playersArea.getChildren().add(playerBox);
|
||||
}
|
||||
}
|
||||
|
||||
private ImageView createCardImage(int pageIndex, int height) {
|
||||
try {
|
||||
BufferedImage bim = pdfRenderer.renderImageWithDPI(pageIndex, 100);
|
||||
Image fxImage = SwingFXUtils.toFXImage(bim, null);
|
||||
ImageView imageView = new ImageView(fxImage);
|
||||
imageView.setFitHeight(height);
|
||||
imageView.setPreserveRatio(true);
|
||||
imageView.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.4), 4, 0, 0, 0);");
|
||||
return imageView;
|
||||
} catch (IOException e) {
|
||||
logger.error("Errore rendering pagina {}", pageIndex, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
if (document != null) document.close();
|
||||
super.stop();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
}
|
||||
271
src/main/java/org/example/mesosll07/DeckGridAppFX.java
Normal file
@@ -0,0 +1,271 @@
|
||||
package org.example.mesosll07;
|
||||
|
||||
import Server.Automaton.Game;
|
||||
import Server.Era;
|
||||
import Server.Player;
|
||||
import Server.TotemColor;
|
||||
import javafx.application.Application;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import Server.Cards.*;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
public class DeckGridAppFX extends Application {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger(DeckGridAppFX.class);
|
||||
|
||||
private PDDocument documentFront;
|
||||
private PDDocument documentBack;
|
||||
private PDFRenderer pdfRendererFront;
|
||||
private PDFRenderer pdfRendererBack;
|
||||
private int totalCards = 0;
|
||||
|
||||
// Contenitori Layout
|
||||
private HBox topRow;
|
||||
private HBox centerRow;
|
||||
private HBox bottomRow;
|
||||
private HBox playersArea; // NUOVO: Area per i giocatori
|
||||
private Button btnShuffle;
|
||||
|
||||
|
||||
|
||||
// --------------------------------
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
|
||||
List<Player> players = new ArrayList<>();
|
||||
players.add(new Player("Yoshi", TotemColor.YELLOW));
|
||||
players.add(new Player("Pippo", TotemColor.PURPLE));
|
||||
players.add(new Player("John", TotemColor.RED));
|
||||
players.add(new Player("Baggio", TotemColor.BLUE));
|
||||
players.add(new Player("Gino", TotemColor.GREEN));
|
||||
|
||||
Game game = new Game(players);
|
||||
String fileCards="/home/lorenzo/dev/Mesos2/src/main/resources/files/cards.csv";
|
||||
String fileCardsImgFront="/home/lorenzo/dev/Mesos2/src/main/resources/files/Cards_total_front_PROMO.pdf";
|
||||
String fileCardsImgCover="/home/lorenzo/dev/Mesos2/src/main/resources/files/Cards_total_back_PROMO.pdf";
|
||||
|
||||
try {
|
||||
|
||||
File fileFront = new File(fileCardsImgFront);
|
||||
File fileBack = new File(fileCardsImgCover);
|
||||
|
||||
documentFront = PDDocument.load(fileFront);
|
||||
pdfRendererFront = new PDFRenderer(documentFront);
|
||||
documentBack = PDDocument.load(fileBack);
|
||||
pdfRendererBack = new PDFRenderer(documentBack);
|
||||
|
||||
} catch ( IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
game.newGame(fileCards);
|
||||
|
||||
|
||||
|
||||
primaryStage.setTitle("Tavolo da Gioco - Board & Players");
|
||||
|
||||
|
||||
btnShuffle = new Button("Rimescola & Distribuisci");
|
||||
btnShuffle.setDisable(true);
|
||||
|
||||
|
||||
btnShuffle.setOnAction(e -> distributeAll(game));
|
||||
|
||||
HBox topMenu = new HBox(15, btnShuffle);
|
||||
topMenu.setAlignment(Pos.CENTER);
|
||||
topMenu.setPadding(new Insets(10));
|
||||
|
||||
topRow = createRowContainer();
|
||||
centerRow = createRowContainer();
|
||||
bottomRow = createRowContainer();
|
||||
|
||||
|
||||
|
||||
// NUOVO: Inizializza l'area giocatori
|
||||
playersArea = new HBox(30);
|
||||
playersArea.setAlignment(Pos.CENTER);
|
||||
playersArea.setPadding(new Insets(20));
|
||||
|
||||
distributeAll(game);
|
||||
VBox tableArea = new VBox(20,
|
||||
new Label("TOP"), topRow,
|
||||
new Label("CENTER "), centerRow,
|
||||
new Label("DOWN"), bottomRow,
|
||||
new Label("--- SITUAZIONE GIOCATORI ---"), playersArea
|
||||
);
|
||||
tableArea.setAlignment(Pos.CENTER);
|
||||
tableArea.setPadding(new Insets(20));
|
||||
|
||||
ScrollPane scrollPane = new ScrollPane(tableArea);
|
||||
scrollPane.setFitToWidth(true);
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
root.setTop(topMenu);
|
||||
root.setCenter(scrollPane);
|
||||
|
||||
Scene scene = new Scene(root, 1300, 900);
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
private HBox createRowContainer() {
|
||||
HBox row = new HBox(10);
|
||||
row.setAlignment(Pos.CENTER);
|
||||
return row;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void distributeAll(Game game) {
|
||||
if (documentFront == null) return;
|
||||
|
||||
topRow.getChildren().clear();
|
||||
centerRow.getChildren().clear();
|
||||
bottomRow.getChildren().clear();
|
||||
playersArea.getChildren().clear();
|
||||
|
||||
List<Integer> deck = new ArrayList<>();
|
||||
for (int i = 0; i < 118; i++) deck.add(i);
|
||||
Collections.shuffle(deck);
|
||||
|
||||
// Distribuisce sul tavolo le prime 21 carte
|
||||
int index = 0;
|
||||
index = populateTable(topRow, deck, index, 8);
|
||||
index = populateTable(centerRow, deck, index, 6);
|
||||
index = populateTable(bottomRow, deck, index, 7);
|
||||
|
||||
// NUOVO: Simula 2 giocatori con le carte rimanenti
|
||||
Random rand = new Random();
|
||||
List<Player> players =game.getPlayers();
|
||||
|
||||
// Assegna 5 carte a caso a ogni giocatore e simula il loro Tipo
|
||||
|
||||
|
||||
|
||||
for (Player p : players) {
|
||||
for (int j=0;j<4;j++){
|
||||
int idx = rand.nextInt(game.getGameBoard().getCardDeck().getTribeDeck().size());
|
||||
Card c = game.getGameBoard().getCardDeck().drawTribeOne();
|
||||
p.getPlayerTribe().addCharacter((CharacterCard) c);
|
||||
}
|
||||
for (int j=0;j<2;j++){
|
||||
int idx = rand.nextInt(game.getGameBoard().getCardDeck().getBuildingDeck(Era.I).size());
|
||||
Card c = game.getGameBoard().getCardDeck().drawBuildingOne(Era.I);
|
||||
p.getPlayerTribe().addBuilding((BuildingCard) c);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Renderizza i giocatori nella UI
|
||||
renderPlayers(players);
|
||||
}
|
||||
|
||||
private int populateTable(HBox row, List<Integer> deck, int startIndex, int amount) {
|
||||
for (int i = 0; i < amount; i++) {
|
||||
if (startIndex >= deck.size()) break;
|
||||
ImageView card = createCardImage(deck.get(startIndex), 150, true); // Altezza 150px
|
||||
if (card != null) row.getChildren().add(card);
|
||||
startIndex++;
|
||||
}
|
||||
return startIndex;
|
||||
}
|
||||
|
||||
// --- NUOVO: RENDERIZZAZIONE GIOCATORI E RAGGRUPPAMENTO (JAVA 8) ---
|
||||
private void renderPlayers(List<Player> players) {
|
||||
for (Player player : players) {
|
||||
VBox playerBox = new VBox(10);
|
||||
playerBox.setPadding(new Insets(15));
|
||||
playerBox.setStyle("-fx-border-color: #555; -fx-border-width: 2; -fx-border-radius: 10; -fx-background-color: #f9f9f9; -fx-background-radius: 10;");
|
||||
|
||||
// Intestazione Giocatore
|
||||
Label nameLbl = new Label(player.getNickname());
|
||||
nameLbl.setFont(Font.font("System", FontWeight.BOLD, 16));
|
||||
|
||||
// Risorse Cibo e Soldi
|
||||
Label statsLbl = new Label("🍖 Cibo: " + player.getFoodTokens() + " | 💰 Money: " + player.getPrestigePoints());
|
||||
statsLbl.setTextFill(Color.DARKRED);
|
||||
statsLbl.setFont(Font.font("System", FontWeight.BOLD, 14));
|
||||
|
||||
playerBox.getChildren().addAll(nameLbl, statsLbl);
|
||||
|
||||
// JAVA 8 MAGIA: Raggruppa le carte del giocatore per Tipo!
|
||||
Map<CharacterType, List<CharacterCard>> groupedCards = player.getPlayerTribe().getCharacters().stream()
|
||||
.collect(Collectors.groupingBy(CharacterCard::getCharacterType));
|
||||
|
||||
// Itera sui gruppi creati e genera la grafica
|
||||
groupedCards.forEach((type, cardsOfType) -> {
|
||||
Label typeLbl = new Label("Tipo: " + type.name() + " (" + cardsOfType.size() + ")");
|
||||
typeLbl.setFont(Font.font("System", FontWeight.NORMAL, 12));
|
||||
|
||||
HBox cardImagesRow = new HBox(5);
|
||||
for (Card c : cardsOfType) {
|
||||
// Carte più piccole (90px) per l'area giocatore
|
||||
ImageView img = createCardImage(c.getCardId(), 90, true);
|
||||
if (img != null) cardImagesRow.getChildren().add(img);
|
||||
}
|
||||
|
||||
playerBox.getChildren().addAll(typeLbl, cardImagesRow);
|
||||
});
|
||||
|
||||
playersArea.getChildren().add(playerBox);
|
||||
}
|
||||
}
|
||||
|
||||
private ImageView createCardImage(int pageIndex, int height, boolean front) {
|
||||
try {
|
||||
BufferedImage bim =null;
|
||||
if (front) bim = pdfRendererFront.renderImageWithDPI(pageIndex, 100);
|
||||
else bim = pdfRendererBack.renderImageWithDPI(pageIndex, 100);
|
||||
|
||||
Image fxImage = SwingFXUtils.toFXImage(bim, null);
|
||||
ImageView imageView = new ImageView(fxImage);
|
||||
imageView.setFitHeight(height);
|
||||
imageView.setPreserveRatio(true);
|
||||
imageView.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.4), 4, 0, 0, 0);");
|
||||
return imageView;
|
||||
} catch (IOException e) {
|
||||
logger.error("Errore rendering pagina {}", pageIndex, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
if (documentFront != null) documentFront.close();
|
||||
super.stop();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
}
|
||||
159
src/main/java/org/example/mesosll07/DeckViewerFX.java
Normal file
@@ -0,0 +1,159 @@
|
||||
package org.example.mesosll07;
|
||||
|
||||
import Server.Automaton.Game;
|
||||
import Server.Player;
|
||||
import Server.TotemColor;
|
||||
import javafx.application.Application;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.FileChooser;
|
||||
import javafx.stage.Stage;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.rendering.PDFRenderer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DeckViewerFX extends Application {
|
||||
|
||||
private PDDocument document;
|
||||
private PDFRenderer pdfRenderer;
|
||||
private int currentIndex = 0;
|
||||
private int totalCards = 0;
|
||||
|
||||
private ImageView cardImageView;
|
||||
private Label pageLabel;
|
||||
private Button btnPrev;
|
||||
private Button btnNext;
|
||||
|
||||
@Override
|
||||
public void start(Stage primaryStage) {
|
||||
|
||||
List<Player> players = new ArrayList<>();
|
||||
players.add(new Player("Yoshi", TotemColor.YELLOW));
|
||||
players.add(new Player("Pippo", TotemColor.PURPLE));
|
||||
players.add(new Player("John", TotemColor.RED));
|
||||
players.add(new Player("Baggio", TotemColor.BLUE));
|
||||
players.add(new Player("Gino", TotemColor.GREEN));
|
||||
|
||||
Game game = new Game(players);
|
||||
game.newGame("/home/lorenzo/dev/Mesos2/src/main/resources/files/cards.csv");
|
||||
|
||||
primaryStage.setTitle("Visualizzatore Mazzo di Carte (PDF)");
|
||||
|
||||
// Componente per mostrare la carta
|
||||
cardImageView = new ImageView();
|
||||
cardImageView.setFitHeight(500); // Altezza fissa, larghezza in proporzione
|
||||
cardImageView.setPreserveRatio(true);
|
||||
cardImageView.setStyle("-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.5), 10, 0, 0, 0);");
|
||||
|
||||
// Controlli UI
|
||||
btnPrev = new Button("⬅ Carta Precedente");
|
||||
btnNext = new Button("Carta Successiva ➡");
|
||||
pageLabel = new Label("Nessun mazzo caricato");
|
||||
Button btnLoad = new Button("Carica PDF Mazzo");
|
||||
|
||||
// Azioni dei pulsanti
|
||||
btnLoad.setOnAction(e -> loadPdf(primaryStage));
|
||||
btnPrev.setOnAction(e -> showCard(currentIndex - 1));
|
||||
btnNext.setOnAction(e -> showCard(currentIndex + 1));
|
||||
|
||||
updateButtons();
|
||||
|
||||
// Layout
|
||||
HBox controls = new HBox(15, btnPrev, pageLabel, btnNext);
|
||||
controls.setAlignment(Pos.CENTER);
|
||||
|
||||
VBox topBox = new VBox(10, btnLoad);
|
||||
topBox.setAlignment(Pos.CENTER);
|
||||
topBox.setPadding(new Insets(10));
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
root.setTop(topBox);
|
||||
root.setCenter(cardImageView);
|
||||
root.setBottom(controls);
|
||||
BorderPane.setMargin(cardImageView, new Insets(20));
|
||||
BorderPane.setMargin(controls, new Insets(20));
|
||||
|
||||
Scene scene = new Scene(root, 600, 700);
|
||||
primaryStage.setScene(scene);
|
||||
primaryStage.show();
|
||||
}
|
||||
|
||||
private void loadPdf(Stage stage) {
|
||||
FileChooser fileChooser = new FileChooser();
|
||||
fileChooser.setTitle("Seleziona il PDF del mazzo di carte");
|
||||
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("File PDF", "*.pdf"));
|
||||
File file = fileChooser.showOpenDialog(stage);
|
||||
|
||||
if (file != null) {
|
||||
try {
|
||||
// Chiude il documento precedente se esiste
|
||||
if (document != null) {
|
||||
document.close();
|
||||
}
|
||||
|
||||
// Carica il nuovo PDF
|
||||
document = PDDocument.load(file);
|
||||
pdfRenderer = new PDFRenderer(document);
|
||||
totalCards = document.getNumberOfPages();
|
||||
|
||||
// Mostra la prima carta
|
||||
showCard(0);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
pageLabel.setText("Errore nel caricamento del file!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showCard(int index) {
|
||||
if (document == null || index < 0 || index >= totalCards) return;
|
||||
|
||||
try {
|
||||
// Renderizza la pagina del PDF in un'immagine BufferedImage (DPI 150 per buona qualità)
|
||||
BufferedImage bim = pdfRenderer.renderImageWithDPI(index, 150);
|
||||
|
||||
// Converte l'immagine di AWT (Swing) in un'immagine JavaFX
|
||||
Image fxImage = SwingFXUtils.toFXImage(bim, null);
|
||||
|
||||
cardImageView.setImage(fxImage);
|
||||
currentIndex = index;
|
||||
pageLabel.setText("Carta " + (currentIndex + 1) + " di " + totalCards);
|
||||
|
||||
updateButtons();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateButtons() {
|
||||
btnPrev.setDisable(document == null || currentIndex == 0);
|
||||
btnNext.setDisable(document == null || currentIndex == totalCards - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
// Importante: chiudere il documento per liberare la memoria quando l'app si chiude
|
||||
if (document != null) {
|
||||
document.close();
|
||||
}
|
||||
super.stop();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
launch(args);
|
||||
}
|
||||
}
|
||||
19
src/main/java/org/example/mesosll07/HelloApplication.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.example.mesosll07;
|
||||
|
||||
import javafx.application.Application;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class HelloApplication extends Application {
|
||||
@Override
|
||||
public void start(Stage stage) throws IOException {
|
||||
FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
|
||||
Scene scene = new Scene(fxmlLoader.load(), 320, 240);
|
||||
stage.setTitle("Hello!");
|
||||
stage.setScene(scene);
|
||||
stage.show();
|
||||
}
|
||||
}
|
||||
14
src/main/java/org/example/mesosll07/HelloController.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package org.example.mesosll07;
|
||||
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
|
||||
public class HelloController {
|
||||
@FXML
|
||||
private Label welcomeText;
|
||||
|
||||
@FXML
|
||||
protected void onHelloButtonClick() {
|
||||
welcomeText.setText("Welcome to JavaFX Application!");
|
||||
}
|
||||
}
|
||||
9
src/main/java/org/example/mesosll07/Launcher.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package org.example.mesosll07;
|
||||
|
||||
import javafx.application.Application;
|
||||
|
||||
public class Launcher {
|
||||
public static void main(String[] args) {
|
||||
Application.launch(HelloApplication.class, args);
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/files/Cards_total_back_PROMO.pdf
Normal file
BIN
src/main/resources/files/Cards_total_front_PROMO.pdf
Normal file
BIN
src/main/resources/files/Start_2P.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
src/main/resources/files/Start_3P.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
src/main/resources/files/Start_4P.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
src/main/resources/files/Start_5P.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
117
src/main/resources/files/cards.csv
Normal file
@@ -0,0 +1,117 @@
|
||||
C;1;0;I;HUNTER;1;0
|
||||
C;2;0;I;HUNTER;1;0
|
||||
C;3;0;I;HUNTER;0;0
|
||||
C;4;3;I;HUNTER;0;0
|
||||
C;5;3;I;HUNTER;0;0
|
||||
C;6;0;I;BUILDER;1;3
|
||||
C;7;0;I;BUILDER;2;0
|
||||
C;8;5;I;BUILDER;2;1
|
||||
C;9;0;I;BUILDER;1;2
|
||||
C;10;0;I;GATHERER;3;0
|
||||
C;11;0;I;GATHERER;3;0
|
||||
C;12;3;I;GATHERER;3;0
|
||||
C;13;5;I;GATHERER;3;0
|
||||
C;14;0;I;ARTIST;0;0
|
||||
C;15;0;I;ARTIST;0;0
|
||||
C;16;0;I;ARTIST;0;0
|
||||
C;17;3;I;ARTIST;0;0
|
||||
C;18;4;I;ARTIST;0;0
|
||||
C;19;0;I;INVENTOR;8;0
|
||||
C;20;0;I;INVENTOR;0;0
|
||||
C;21;0;I;INVENTOR;1;0
|
||||
C;22;0;I;INVENTOR;9;0
|
||||
C;23;4;I;INVENTOR;5;0
|
||||
C;24;4;I;INVENTOR;7;0
|
||||
C;25;4;I;INVENTOR;4;0
|
||||
C;26;5;I;SHAMAN;2;0
|
||||
C;27;0;I;SHAMAN;2;0
|
||||
C;28;0;I;SHAMAN;1;0
|
||||
C;29;4;I;SHAMAN;1;0
|
||||
C;30;0;II;HUNTER;0;0
|
||||
C;31;0;II;HUNTER;0;0
|
||||
C;32;3;II;HUNTER;1;0
|
||||
C;33;0;II;HUNTER;1;0
|
||||
C;34;4;II;HUNTER;1;0
|
||||
C;35;5;II;HUNTER;0;0
|
||||
C;36;0;II;BUILDER;1;4
|
||||
C;37;0;II;BUILDER;2;1
|
||||
C;38;3;II;BUILDER;1;2
|
||||
C;39;0;II;BUILDER;2;3
|
||||
C;40;0;II;GATHERER;3;0
|
||||
C;41;3;II;GATHERER;3;0
|
||||
C;42;4;II;GATHERER;3;0
|
||||
C;43;5;II;GATHERER;3;0
|
||||
C;44;3;II;ARTIST;0;0
|
||||
C;45;0;II;ARTIST;0;0
|
||||
C;46;0;II;ARTIST;0;0
|
||||
C;47;0;II;ARTIST;0;0
|
||||
C;48;0;II;INVENTOR;0;0
|
||||
C;49;4;II;INVENTOR;0;0
|
||||
C;50;0;II;INVENTOR;0;0
|
||||
C;51;0;II;INVENTOR;0;0
|
||||
C;52;0;II;INVENTOR;0;0
|
||||
C;53;0;II;INVENTOR;0;0
|
||||
C;54;0;II;SHAMAN;2;0
|
||||
C;55;0;II;SHAMAN;2;0
|
||||
C;56;5;II;SHAMAN;1;0
|
||||
C;57;5;II;SHAMAN;2;0
|
||||
C;58;5;III;HUNTER;1;0
|
||||
C;59;0;III;HUNTER;0;0
|
||||
C;60;0;III;HUNTER;0;0
|
||||
C;61;0;III;HUNTER;1;0
|
||||
C;62;0;III;BUILDER;1;5
|
||||
C;63;0;III;BUILDER;2;3
|
||||
C;64;5;III;BUILDER;1;4
|
||||
C;65;0;III;BUILDER;2;2
|
||||
C;66;5;III;GATHERER;3;0
|
||||
C;67;4;III;GATHERER;3;0
|
||||
C;68;0;III;GATHERER;3;0
|
||||
C;69;5;III;ARTIST;0;0
|
||||
C;70;0;III;ARTIST;0;0
|
||||
C;71;0;III;ARTIST;0;0
|
||||
C;72;0;III;ARTIST;0;0
|
||||
C;73;4;III;INVENTOR;0;0
|
||||
C;74;3;III;INVENTOR;0;0
|
||||
C;75;3;III;INVENTOR;0;0
|
||||
C;76;0;III;INVENTOR;0;0
|
||||
C;77;0;III;INVENTOR;0;0
|
||||
C;78;0;III;INVENTOR;0;0
|
||||
C;79;0;III;INVENTOR;0;0
|
||||
C;80;3;III;SHAMAN;2;0
|
||||
C;81;0;III;SHAMAN;3;0
|
||||
C;82;0;III;SHAMAN;2;0
|
||||
C;83;0;III;SHAMAN;3;0
|
||||
C;84;4;III;SHAMAN;2;0
|
||||
E;85;0;I;HUNT;1;1
|
||||
E;86;0;I;SUSTAINMENT;1;1
|
||||
E;87;0;I;SHAMANIC_RITUAL;5;3
|
||||
E;88;0;I;CAVE_PAINTINGS;2;1
|
||||
E;89;0;II;HUNT;1;2
|
||||
E;90;0;II;SUSTAINMENT;1;2
|
||||
E;91;0;II;SHAMANIC_RITUAL;10;5
|
||||
E;92;0;II;CAVE_PAINTINGS;2;2
|
||||
E;93;0;III;HUNT;1;3
|
||||
E;94;0;III;CAVE_PAINTINGS;2;3
|
||||
E;95;0;FINAL;SUSTAINMENT;1;3
|
||||
E;96;0;FINAL;SHAMANIC_RITUAL;15;7
|
||||
B;97;0;I;4;3;FOOD_FOR_SIX
|
||||
B;98;0;I;4;4;SUSTAIN_DISCOUNT
|
||||
B;99;0;I;5;3;SUSTAIN_DISCOUNT
|
||||
B;100;0;I;5;2;SHAMAN_NO_LOSS
|
||||
B;101;0;I;3;3;BONUS_FOOD_ENDTURN
|
||||
B;102;0;I;3;4;FOOD_PER_INVENTORS
|
||||
B;103;0;II;7;0;SHAMAN_DOUBLE_POINTS
|
||||
B;104;0;II;6;4;SHAMAN_BONUS
|
||||
B;105;0;II;7;4;SUSTAIN_DISCOUNT
|
||||
B;106;0;II;7;2;HUNT_BONUS
|
||||
B;107;0;II;6;4;ENDGAME_BUILDER_BONUS
|
||||
B;108;0;II;5;6;PAINTING_FOOD_BONUS
|
||||
B;109;0;II;5;6;ENDGAME_FOR_SIX
|
||||
B;110;0;III;8;8;ENDGAME_BONUS_CHARACTER
|
||||
B;111;0;III;7;6;ENDGAME_BONUS_CHARACTER
|
||||
B;112;0;III;7;4;ENDGAME_BONUS_CHARACTER
|
||||
B;113;0;III;6;3;ENDGAME_BONUS_CHARACTER
|
||||
B;114;0;III;7;4;ENDGAME_BONUS_CHARACTER
|
||||
B;115;0;III;6;6;ENDGAME_BONUS_CHARACTER
|
||||
B;116;0;III;9;3;EXTRA_DRAW
|
||||
B;117;0;III;10;0;ENDGAME_BONUS_POINTS
|
||||
|
BIN
src/main/resources/files/offeringA.png
Normal file
|
After Width: | Height: | Size: 834 KiB |
BIN
src/main/resources/files/offeringB.png
Normal file
|
After Width: | Height: | Size: 858 KiB |
BIN
src/main/resources/files/offeringC.png
Normal file
|
After Width: | Height: | Size: 927 KiB |
BIN
src/main/resources/files/offeringD.png
Normal file
|
After Width: | Height: | Size: 878 KiB |
BIN
src/main/resources/files/offeringE.png
Normal file
|
After Width: | Height: | Size: 876 KiB |
BIN
src/main/resources/files/offeringF.png
Normal file
|
After Width: | Height: | Size: 826 KiB |
BIN
src/main/resources/files/offeringG.png
Normal file
|
After Width: | Height: | Size: 904 KiB |
22
src/main/resources/log4j2.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
<Appenders>
|
||||
<!-- Appender per scrivere sulla Console -->
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
|
||||
</Console>
|
||||
|
||||
<!-- Appender per scrivere su un file chiamato app.log -->
|
||||
<File name="LogFile" fileName="logs/mesos2.log">
|
||||
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
|
||||
</File>
|
||||
</Appenders>
|
||||
|
||||
<Loggers>
|
||||
<!-- Configurazione base: registra tutto ciò che è livello INFO o superiore -->
|
||||
<Root level="info">
|
||||
<AppenderRef ref="Console"/>
|
||||
<AppenderRef ref="LogFile"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
16
src/main/resources/org/example/mesosll07/hello-view.fxml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
|
||||
<?import javafx.scene.control.Button?>
|
||||
<VBox alignment="CENTER" spacing="20.0" xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.example.mesosll07.HelloController">
|
||||
<padding>
|
||||
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
|
||||
</padding>
|
||||
|
||||
<Label fx:id="welcomeText"/>
|
||||
<Button text="Hello!" onAction="#onHelloButtonClick"/>
|
||||
</VBox>
|
||||
36
src/test/java/Server/Automaton/GameTest.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package Server.Automaton;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class GameTest {
|
||||
|
||||
@Test
|
||||
void newGame() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void placeTotem() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveCardAction() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void extraDrawAction() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void skipExtraDraw() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void endGame() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void getPendingActions() {
|
||||
}
|
||||
}
|
||||
205
src/test/java/Server/BuildingManagerTest.java
Normal file
@@ -0,0 +1,205 @@
|
||||
package Server;
|
||||
|
||||
import Server.Cards.BuildingCard;
|
||||
|
||||
import Server.Cards.CardDeck;
|
||||
import Server.Cards.CharacterCard;
|
||||
import Server.Cards.EventCard;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class BuildingManagerTest {
|
||||
|
||||
static List<Player> players = new ArrayList<>();
|
||||
|
||||
@BeforeAll
|
||||
static void setUp(){
|
||||
BuildingManager buildingManager = new BuildingManager();
|
||||
|
||||
Player winner = new Player("Winner", TotemColor.YELLOW);
|
||||
winner.addFood(10);
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;1;2;I;SHAMAN;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;2;2;I;SHAMAN;2;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;3;2;I;BUILDER;3;1"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;14;0;I;ARTIST;0;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;15;0;I;ARTIST;0;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;21;0;I;ARTIST;1;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;22;0;I;INVENTOR;9;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;23;4;I;INVENTOR;5;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;43;0;I;HUNTER;0;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;44;3;I;HUNTER;0;0"));
|
||||
players.add(winner);
|
||||
|
||||
Player medium = new Player("Medium", TotemColor.RED);
|
||||
medium.addFood(10);
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;56;2;I;SHAMAN;3;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;34;2;I;BUILDER;3;1"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;32;3;I;GATHERER;3;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;33;0;I;ARTIST;0;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;45;3;I;HUNTER;0;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;72;0;I;ARTIST;9;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;73;4;I;INVENTOR;5;0"));
|
||||
players.add(medium);
|
||||
|
||||
Player loser = new Player("Loser", TotemColor.BLUE);
|
||||
loser.addFood(2);
|
||||
loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;54;2;I;SHAMAN;3;0"));
|
||||
loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;36;2;I;BUILDER;3;1"));
|
||||
loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;82;0;I;INVENTOR;9;0"));
|
||||
loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;93;4;I;INVENTOR;5;0"));
|
||||
players.add(loser);
|
||||
|
||||
CardDeck cardDeck = new CardDeck();
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/only_building_deck.csv", 5);
|
||||
|
||||
//for(BuildingCard c: cardDeck.drawBuilding(30)){
|
||||
// buildingManager.addActiveBuilding(c, players.getFirst());
|
||||
//}
|
||||
//buildingManager.addActiveBuilding(BuildingCard.parsRow("B;5;3;III;6;2;SHAMAN_NO_LOSS"), players.get(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void foodForSix() {
|
||||
int initialFood = players.getFirst().getFoodTokens();
|
||||
CharacterCard cardForSix = CharacterCard.parsRow("C;39;2;I;BUILDER;3;1");
|
||||
BuildingManager.foodForSix(players.getFirst(), cardForSix);
|
||||
assertEquals(initialFood + 6, players.getFirst().getFoodTokens());
|
||||
|
||||
players.getFirst().getPlayerTribe().addCharacter(cardForSix);
|
||||
BuildingManager.foodForSix(players.getFirst(), cardForSix);
|
||||
assertEquals(initialFood + 6, players.getFirst().getFoodTokens());
|
||||
}
|
||||
|
||||
@Test
|
||||
void sustainDiscount() {
|
||||
|
||||
EventCard sustainment = EventCard.parsRow("E;1;0;I;SUSTAINMENT;2;0");
|
||||
ArrayList<Integer> target = new ArrayList<>();
|
||||
target.add(players.getFirst().getFoodTokens());
|
||||
target.add(players.getFirst().getPrestigePoints());
|
||||
target.add(players.get(1).getFoodTokens() - 4);
|
||||
target.add(players.get(1).getPrestigePoints());
|
||||
target.add(0);
|
||||
target.add(players.get(2).getPrestigePoints()-4);
|
||||
assertEquals(target, EventsSolver.sustainment(sustainment, players));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shamanicBuildings() {
|
||||
EventCard shamanicRitual = EventCard.parsRow("E;1;0;I;SHAMANIC_RITUAL;10;5");
|
||||
ArrayList<Integer> target = new ArrayList<>();
|
||||
target.add(players.getFirst().getPrestigePoints() + 20);
|
||||
target.add(players.get(1).getPrestigePoints()-5);
|
||||
target.add(players.get(2).getPrestigePoints());
|
||||
assertEquals(target, EventsSolver.shamanicRitual(shamanicRitual, players));
|
||||
}
|
||||
|
||||
@Test
|
||||
void bonusEndTurn() {
|
||||
assertEquals(1, BuildingManager.bonusEndTurn(players.getFirst(), 1));
|
||||
assertEquals(0, BuildingManager.bonusEndTurn(players.getFirst(), 0));
|
||||
assertEquals(0, BuildingManager.bonusEndTurn(players.getFirst(), -1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void foodPerInventors() {
|
||||
int initialFood = players.getFirst().getFoodTokens();
|
||||
CharacterCard builder = CharacterCard.parsRow("C;57;2;I;INVENTOR;9;0");
|
||||
BuildingManager.foodPerInventors(players.getFirst(), builder);
|
||||
assertEquals(initialFood + 3, players.getFirst().getFoodTokens());
|
||||
|
||||
players.getFirst().getPlayerTribe().addCharacter(builder);
|
||||
BuildingManager.foodPerInventors(players.getFirst(), builder);
|
||||
assertEquals(initialFood+3, players.getFirst().getFoodTokens());
|
||||
|
||||
initialFood = players.get(2).getFoodTokens();
|
||||
BuildingManager.foodPerInventors(players.get(2), builder);
|
||||
assertEquals(initialFood, players.get(2).getFoodTokens());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shamanBonus() {
|
||||
assertEquals(3, BuildingManager.shamanBonus(players.getFirst()));
|
||||
assertEquals(0, BuildingManager.shamanBonus(players.get(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void hunterBonus() {
|
||||
EventCard hunt = EventCard.parsRow("E;1;0;I;HUNT;2;0");
|
||||
ArrayList<Integer> target = new ArrayList<>();
|
||||
target.add(players.getFirst().getFoodTokens()+4);
|
||||
target.add(players.getFirst().getPrestigePoints()+6);
|
||||
target.add(players.get(1).getFoodTokens()+1);
|
||||
target.add(players.get(1).getPrestigePoints()+2);
|
||||
target.add(players.get(2).getFoodTokens());
|
||||
target.add(players.get(2).getPrestigePoints());
|
||||
assertEquals(target, EventsSolver.hunt(hunt, players));
|
||||
}
|
||||
|
||||
@Test
|
||||
void endgameBuilderBonus() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void paintingFoodBonus() {
|
||||
int winnerInitial = players.getFirst().getFoodTokens();
|
||||
int middleInitial = players.get(1).getFoodTokens();
|
||||
|
||||
EventCard cavePainting = EventCard.parsRow("E;4;4;FINAL;CAVE_PAINTINGS;2;2");
|
||||
EventsSolver.cavePaintings(cavePainting, players);
|
||||
assertEquals(winnerInitial + 3 , players.getFirst().getFoodTokens());
|
||||
assertEquals(middleInitial, players.get(1).getFoodTokens());
|
||||
}
|
||||
|
||||
@Test
|
||||
void endgameForSix() {
|
||||
int winnerInitial = players.getFirst().getPrestigePoints();
|
||||
int middleInitial = players.get(1).getPrestigePoints();
|
||||
|
||||
BuildingManager.endgameForSix(players.getFirst());
|
||||
BuildingManager.endgameForSix(players.get(1));
|
||||
assertEquals(winnerInitial + 6 , players.getFirst().getPrestigePoints());
|
||||
assertEquals(middleInitial, players.get(1).getPrestigePoints());
|
||||
}
|
||||
|
||||
@Test
|
||||
void endgameBonusCharacter() {
|
||||
int winnerInitial = players.getFirst().getPrestigePoints();
|
||||
int middleInitial = players.get(1).getPrestigePoints();
|
||||
|
||||
BuildingManager.endgameBonusCharacter(players.getFirst());
|
||||
BuildingManager.endgameBonusCharacter(players.get(1));
|
||||
assertEquals(winnerInitial + 9 , players.getFirst().getPrestigePoints());
|
||||
assertEquals(middleInitial, players.get(1).getPrestigePoints());
|
||||
}
|
||||
|
||||
@Test
|
||||
void extraDraw() {
|
||||
assertTrue(BuildingManager.extraDraw(players.getFirst()));
|
||||
assertFalse(BuildingManager.extraDraw(players.get(1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void endgameBonusPoints() {
|
||||
int initialWinner = players.getFirst().getPrestigePoints();
|
||||
int initialMedium = players.get(1).getPrestigePoints();
|
||||
|
||||
BuildingManager.endgameBonusPoints(players.getFirst());
|
||||
BuildingManager.endgameBonusPoints(players.get(1));
|
||||
assertEquals(initialWinner+25, players.getFirst().getPrestigePoints());
|
||||
assertEquals(initialMedium, players.get(1).getPrestigePoints());
|
||||
}
|
||||
}
|
||||
39
src/test/java/Server/Cards/BuildingCardTest.java
Normal file
@@ -0,0 +1,39 @@
|
||||
package Server.Cards;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static Server.Era.I;
|
||||
import static Server.Era.II;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class BuildingCardTest {
|
||||
|
||||
|
||||
//Test if the method parsRow is able to create a correct BuildingCard
|
||||
@Test
|
||||
void registerBuildingCard() {
|
||||
BuildingCard buildingCard = BuildingCard.parsRow("B;1;2;I;3;1;SHAMAN_BONUS");
|
||||
|
||||
assertEquals(1, buildingCard.getCardId());
|
||||
assertEquals(2, buildingCard.getForMinPlayer());
|
||||
assertEquals(I, buildingCard.getEra());
|
||||
assertEquals(3, buildingCard.getCost());
|
||||
assertEquals(1, buildingCard.getCardId());
|
||||
assertEquals(Trigger.SHAMAN_BONUS, buildingCard.getAbilityTrigger());
|
||||
assertNull(buildingCard.getEffectTarget());
|
||||
}
|
||||
|
||||
void registerBuildingCardWithTarget() {
|
||||
BuildingCard buildingCard = BuildingCard.parsRow("B;17;5;II;6;2;SUSTAIN_DISCOUNT;ARTIST");
|
||||
|
||||
assertEquals(17, buildingCard.getCardId());
|
||||
assertEquals(5, buildingCard.getForMinPlayer());
|
||||
assertEquals(II, buildingCard.getEra());
|
||||
assertEquals(6, buildingCard.getCost());
|
||||
assertEquals(2, buildingCard.getCardId());
|
||||
assertEquals(Trigger.SUSTAIN_DISCOUNT, buildingCard.getAbilityTrigger());
|
||||
assertEquals(CharacterType.ARTIST, buildingCard.getEffectTarget());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
103
src/test/java/Server/Cards/CardDeckTest.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package Server.Cards;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import Server.Era;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
class CardDeckTest {
|
||||
|
||||
//Load 2 cards from CSV to cardDeck
|
||||
@Test
|
||||
void loadOnlyCharacter(){
|
||||
CardDeck cardDeck = new CardDeck();
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/only_character_deck.csv", 4);
|
||||
assertEquals(2, cardDeck.getTribeDeck().size());
|
||||
}
|
||||
|
||||
//First create a new CardDeck filled with a 14 cards then he recreates said deck
|
||||
// with a different set of cards to emulate a new game
|
||||
@Test
|
||||
void doubleLoad(){
|
||||
CardDeck cardDeck = new CardDeck();
|
||||
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/only_building_deck.csv", 4);
|
||||
assertEquals(0, cardDeck.getTribeDeck().size());
|
||||
assertEquals(6, cardDeck.getBuildingDeck(Era.I).size());
|
||||
assertEquals(7, cardDeck.getBuildingDeck(Era.II).size());
|
||||
assertEquals(8, cardDeck.getBuildingDeck(Era.III).size());
|
||||
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/only_event_deck.csv", 4);
|
||||
assertEquals(3, cardDeck.getTribeDeck().size());
|
||||
assertEquals(0, cardDeck.getBuildingDeck(Era.I).size());
|
||||
assertEquals(0, cardDeck.getBuildingDeck(Era.II).size());
|
||||
assertEquals(0, cardDeck.getBuildingDeck(Era.III).size());
|
||||
}
|
||||
|
||||
//Draw 5 cards from TribeDeck and 3 from BuildingDeck, then check if they are correctly
|
||||
// removed from cardDeck
|
||||
@Test
|
||||
void draw() {
|
||||
|
||||
int tribeDraw = 5;
|
||||
int buildingDraw = 3;
|
||||
int drawnCards = tribeDraw + buildingDraw;
|
||||
|
||||
CardDeck cardDeck = new CardDeck();
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/test_deck.csv", 5);
|
||||
//int deckSize = cardDeck.getTribeDeck().size() + cardDeck.getBuildingDeck().size();
|
||||
|
||||
List<Card> cards = cardDeck.drawTribe(tribeDraw);
|
||||
assertEquals(tribeDraw, cards.size());
|
||||
//List<BuildingCard> buildingCards = cardDeck.drawBuilding(buildingDraw);
|
||||
//assertEquals(buildingDraw, buildingCards.size());
|
||||
|
||||
//int newDeckSize = cardDeck.getTribeDeck().size() + cardDeck.getBuildingDeck().size();
|
||||
//assertEquals(deckSize - drawnCards, newDeckSize);
|
||||
}
|
||||
|
||||
//draw 5 cards from TribeDeck
|
||||
@Test
|
||||
void drawTribe() {
|
||||
CardDeck cardDeck = new CardDeck();
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/test_deck.csv", 5);
|
||||
|
||||
List<Card> cards = cardDeck.drawTribe(5);
|
||||
assertEquals(5, cards.size());
|
||||
}
|
||||
|
||||
//draw 3 cards from BuildingDeck
|
||||
@Test
|
||||
void drawBuilding() {
|
||||
CardDeck cardDeck = new CardDeck();
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/test_deck.csv", 5);
|
||||
|
||||
// List<BuildingCard> buildingCards = cardDeck.drawBuilding(3);
|
||||
// assertEquals(3, buildingCards.size());
|
||||
}
|
||||
|
||||
//Try to draw 5 cards from a deck of only 3, then he returns only the remaining
|
||||
//cards in the deck
|
||||
@Test
|
||||
void drawTooManyCards() {
|
||||
CardDeck cardDeck = new CardDeck();
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/only_character_deck.csv", 5);
|
||||
|
||||
List<Card> cards = cardDeck.drawTribe(5);
|
||||
assertEquals(3, cards.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void shuffledDeck() {
|
||||
CardDeck cardDeck = new CardDeck();
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/test_deck.csv", 5);
|
||||
|
||||
assertEquals(Era.I, cardDeck.drawTribe(1).getFirst().getEra());
|
||||
assertEquals(Era.FINAL, cardDeck.drawTribe(100).getLast().getEra());
|
||||
|
||||
// assertEquals(Era.I, cardDeck.drawBuilding(1).getFirst().getEra());
|
||||
// assertEquals(Era.III, cardDeck.drawBuilding(100).getLast().getEra());
|
||||
}
|
||||
}
|
||||
36
src/test/java/Server/Cards/CharacterCardTest.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package Server.Cards;
|
||||
|
||||
import Server.Utils.LoadingCardsException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static Server.Era.I;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CharacterCardTest {
|
||||
|
||||
//Test if the method parsRow is able to create a correct CharacterCard
|
||||
@Test
|
||||
void parsRow() {
|
||||
CharacterCard characterCard = CharacterCard.parsRow("C;1;2;I;SHAMAN;3;4");
|
||||
|
||||
assertEquals(1, characterCard.getCardId());
|
||||
assertEquals(2, characterCard.getForMinPlayer());
|
||||
assertEquals(I, characterCard.getEra());
|
||||
assertEquals(CharacterType.SHAMAN, characterCard.getCharacterType());
|
||||
assertEquals(3, characterCard.getIconValue());
|
||||
assertEquals(4, characterCard.getPrestigePoints());
|
||||
}
|
||||
|
||||
//Tests if the method parsRow send an exception with the message "Not a character" when is given
|
||||
//as an input the wrong type of card
|
||||
|
||||
@Test
|
||||
void wrongTypeOfCard(){
|
||||
Exception exception = assertThrows(LoadingCardsException.class, () -> CharacterCard.parsRow("B;1;2;I;3;1;SHAMANIC_RITUAL"));
|
||||
|
||||
String actualMessage = exception.getMessage();
|
||||
assertTrue(actualMessage.contains("Not a character card"));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
34
src/test/java/Server/Cards/EventCardTest.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package Server.Cards;
|
||||
|
||||
import Server.Utils.LoadingCardsException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static Server.Era.I;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class EventCardTest {
|
||||
|
||||
//Test if the method parsRow is able to create a correct EventCard
|
||||
@Test
|
||||
void parsRow() {
|
||||
EventCard eventCard = EventCard.parsRow("E;1;2;I;CAVE_PAINTINGS;3;4");
|
||||
|
||||
assertEquals(1, eventCard.getCardId());
|
||||
assertEquals(2, eventCard.getForMinPlayer());
|
||||
assertEquals(I, eventCard.getEra());
|
||||
assertEquals(Event.CAVE_PAINTINGS, eventCard.getEvent());
|
||||
assertEquals(3, eventCard.getFirstValue());
|
||||
assertEquals(4, eventCard.getSecondValue());
|
||||
}
|
||||
|
||||
//Tests if the method parsRow send an exception with the message "Not an EventCard" when is given
|
||||
//as an input the wrong type of card
|
||||
|
||||
@Test
|
||||
void wrongTypeOfCard(){
|
||||
Exception exception = assertThrows(LoadingCardsException.class, () -> EventCard.parsRow("B;1;2;I;3;1;SHAMANIC_RITUAL"));
|
||||
|
||||
String actualMessage = exception.getMessage();
|
||||
assertTrue(actualMessage.contains("Not an EventCard"));
|
||||
}
|
||||
}
|
||||
178
src/test/java/Server/EventsSolverTest.java
Normal file
@@ -0,0 +1,178 @@
|
||||
package Server;
|
||||
|
||||
import Server.Cards.Card;
|
||||
import Server.Cards.CardDeck;
|
||||
import Server.Cards.CharacterCard;
|
||||
import Server.Cards.EventCard;
|
||||
import Server.Utils.EventsManagerException;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class EventsSolverTest {
|
||||
|
||||
static List<Player> players = new ArrayList<>();
|
||||
|
||||
//Creating 4 players with a predefined tribe
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp(){
|
||||
BuildingManager buildingManager = new BuildingManager();
|
||||
|
||||
Player winner = new Player("Winner", TotemColor.YELLOW);
|
||||
winner.addFood(10);
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;1;2;I;SHAMAN;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;2;2;I;SHAMAN;2;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;3;2;I;BUILDER;3;1"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;12;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;13;3;I;GATHERER;3;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;14;0;I;ARTIST;0;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;15;0;I;ARTIST;0;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;21;0;I;ARTIST;1;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;22;0;I;INVENTOR;9;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;23;4;I;INVENTOR;5;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;43;0;I;HUNTER;0;0"));
|
||||
winner.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;44;3;I;HUNTER;0;0"));
|
||||
players.add(winner);
|
||||
|
||||
Player medium = new Player("Medium", TotemColor.RED);
|
||||
medium.addFood(10);
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;56;2;I;SHAMAN;3;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;34;2;I;BUILDER;3;1"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;32;3;I;GATHERER;3;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;33;0;I;ARTIST;0;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;45;3;I;HUNTER;0;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;72;0;I;ARTIST;9;0"));
|
||||
medium.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;73;4;I;INVENTOR;5;0"));
|
||||
players.add(medium);
|
||||
|
||||
Player loser = new Player("Loser", TotemColor.BLUE);
|
||||
loser.addFood(2);
|
||||
loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;54;2;I;SHAMAN;2;0"));
|
||||
loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;36;2;I;BUILDER;3;1"));
|
||||
loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;82;0;I;INVENTOR;9;0"));
|
||||
loser.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;93;4;I;INVENTOR;5;0"));
|
||||
players.add(loser);
|
||||
|
||||
Player loser2 = new Player("Loser2", TotemColor.PURPLE);
|
||||
loser2.addFood(2);
|
||||
loser2.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;54;2;I;SHAMAN;2;0"));
|
||||
loser2.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;36;2;I;BUILDER;3;1"));
|
||||
loser2.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;82;0;I;ARTIST;9;0"));
|
||||
loser2.getPlayerTribe().addCharacter(CharacterCard.parsRow("C;93;4;I;INVENTOR;5;0"));
|
||||
players.add(loser2);
|
||||
}
|
||||
|
||||
|
||||
//Testing if solveEvents is able to execute a series of events
|
||||
@Test
|
||||
void solveEvents() {
|
||||
CardDeck cardDeck = new CardDeck();
|
||||
cardDeck.setForNPlayer("./src/test/resources/files/only_event_deck.csv", 5);
|
||||
|
||||
List<EventCard> events = new ArrayList<>();
|
||||
for(Card c: cardDeck.getTribeDeck()){
|
||||
events.add((EventCard) c);
|
||||
}
|
||||
|
||||
assertTrue(EventsSolver.solveEvents(events, players));
|
||||
|
||||
}
|
||||
|
||||
//Testing if sustainment is giving the correct output after inserting a valid input
|
||||
|
||||
@Test
|
||||
void sustainment() {
|
||||
EventCard sustainment = EventCard.parsRow("E;1;0;I;SUSTAINMENT;2;0");
|
||||
ArrayList<Integer> target = new ArrayList<>();
|
||||
target.add(players.getFirst().getFoodTokens());
|
||||
target.add(players.getFirst().getPrestigePoints());
|
||||
target.add(players.get(1).getFoodTokens() - 4);
|
||||
target.add(players.get(1).getPrestigePoints());
|
||||
target.add(0);
|
||||
target.add(players.get(3).getPrestigePoints()-8);
|
||||
target.add(0);
|
||||
target.add(players.get(3).getPrestigePoints()-8);
|
||||
assertEquals(target, EventsSolver.sustainment(sustainment, players));
|
||||
|
||||
}
|
||||
|
||||
//Testing if hunt is giving the correct output after inserting a valid input
|
||||
|
||||
@Test
|
||||
void hunt() {
|
||||
EventCard hunt = EventCard.parsRow("E;1;0;I;HUNT;3;0");
|
||||
ArrayList<Integer> target = new ArrayList<>();
|
||||
target.add(players.getFirst().getFoodTokens() + 2);
|
||||
target.add(players.getFirst().getPrestigePoints() + 6);
|
||||
target.add(players.get(1).getFoodTokens() + 1);
|
||||
target.add(players.get(1).getPrestigePoints() + 3);
|
||||
target.add(players.get(2).getFoodTokens());
|
||||
target.add(players.get(2).getPrestigePoints());
|
||||
target.add(players.get(3).getFoodTokens());
|
||||
target.add(players.get(3).getPrestigePoints());
|
||||
assertEquals(target, EventsSolver.hunt(hunt, players));
|
||||
|
||||
}
|
||||
|
||||
//Testing if shamanicRitual is giving the correct output after inserting a valid input
|
||||
|
||||
@Test
|
||||
void shamanicRitual() {
|
||||
EventCard shamanicRitual = EventCard.parsRow("E;1;0;I;SHAMANIC_RITUAL;10;5");
|
||||
|
||||
ArrayList<Integer> target = new ArrayList<>();
|
||||
target.add(players.getFirst().getPrestigePoints() + 10);
|
||||
target.add(players.get(1).getPrestigePoints());
|
||||
target.add(players.get(2).getPrestigePoints()-5);
|
||||
target.add(players.get(3).getPrestigePoints()-5);
|
||||
assertEquals(target, EventsSolver.shamanicRitual(shamanicRitual, players));
|
||||
}
|
||||
|
||||
//Testing if cavePainting is giving the correct output after inserting a valid input
|
||||
|
||||
@Test
|
||||
void cavePaintings() {
|
||||
EventCard cavePainting = EventCard.parsRow("E;4;4;FINAL;CAVE_PAINTINGS;2;2");
|
||||
ArrayList<Integer> target = new ArrayList<>();
|
||||
target.add(players.getFirst().getPrestigePoints() + 6);
|
||||
target.add(players.get(1).getPrestigePoints() + 4);
|
||||
target.add(players.get(2).getPrestigePoints()-2);
|
||||
target.add(players.get(3).getPrestigePoints()-2);
|
||||
assertEquals(target, EventsSolver.cavePaintings(cavePainting, players));
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrongInputs(){
|
||||
EventCard cavePainting = EventCard.parsRow("E;4;4;FINAL;CAVE_PAINTINGS;2;2");
|
||||
|
||||
Exception sustainmentException = assertThrows(EventsManagerException.class, () -> EventsSolver.sustainment(cavePainting, players));
|
||||
String SustainmentMessage = sustainmentException.getMessage();
|
||||
assertTrue(SustainmentMessage.contains("Not a sustainment card"));
|
||||
|
||||
Exception shamanicException = assertThrows(EventsManagerException.class, () -> EventsSolver.shamanicRitual(cavePainting, players));
|
||||
String shamanicMessage = shamanicException.getMessage();
|
||||
assertTrue(shamanicMessage.contains("Not a shamanic ritual card"));
|
||||
|
||||
Exception huntException = assertThrows(EventsManagerException.class, () -> EventsSolver.hunt(cavePainting, players));
|
||||
String huntMessage = huntException.getMessage();
|
||||
assertTrue(huntMessage.contains("Not a hunt card"));
|
||||
|
||||
EventCard sustainment = EventCard.parsRow("E;1;0;I;SUSTAINMENT;2;0");
|
||||
|
||||
Exception cavePaintingException = assertThrows(EventsManagerException.class, () -> EventsSolver.cavePaintings(sustainment, players));
|
||||
String cavePaintingMessage = cavePaintingException.getMessage();
|
||||
assertTrue(cavePaintingMessage.contains("Not a cave painting card"));
|
||||
|
||||
}
|
||||
}
|
||||
134
src/test/java/Server/GameBoardTest.java
Normal file
@@ -0,0 +1,134 @@
|
||||
package Server;
|
||||
|
||||
import Server.Cards.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class GameBoardTest {
|
||||
|
||||
CardDeck deck = new CardDeck();
|
||||
Player player1 = new Player("A", TotemColor.PURPLE);
|
||||
Player player2 = new Player("B", TotemColor.YELLOW);
|
||||
Player player3 = new Player("C", TotemColor.BLUE);
|
||||
Player player4 = new Player("D", TotemColor.GREEN);
|
||||
Player player5 = new Player("E", TotemColor.RED);
|
||||
List<Player> players = new ArrayList<>();
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
players.add(player1);
|
||||
players.add(player2);
|
||||
players.add(player3);
|
||||
players.add(player4);
|
||||
players.add(player5);
|
||||
deck.setForNPlayer(".\\src\\test\\resources\\files\\test_gameboard.csv",5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void setTotemOnTile() {
|
||||
|
||||
//tests that the tile is occupied
|
||||
|
||||
GameBoard gameBoard = new GameBoard(Era.I,deck, players.size());
|
||||
Player player = new Player("Lucy", TotemColor.BLUE);
|
||||
OfferingTile tile = new OfferingTile(4);
|
||||
assertTrue(gameBoard.placeTotem(player,tile,gameBoard.getTurnTile() ));
|
||||
}
|
||||
|
||||
@Test
|
||||
void drawBottomCard() {
|
||||
|
||||
//test that a hunter card has been added to the player
|
||||
CardDeck deck2 = new CardDeck();
|
||||
deck2.setForNPlayer("./src/test/resources/files/test_gameboard_characters.csv",5);
|
||||
GameBoard gameBoard = new GameBoard(Era.I,deck2,players.size());
|
||||
Player player = new Player("Lucy", TotemColor.BLUE);
|
||||
gameBoard.setupInitialRows(5);
|
||||
// gameBoard.takeFromBottomRow(gameBoard.getBottomrow().get(2),player);
|
||||
// assertEquals(1,player.getPlayerTribe().countCharactersByType(CharacterType.HUNTER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void drawTopCard() {
|
||||
//tests that a hunter card has been added to the player
|
||||
CardDeck deck2 = new CardDeck();
|
||||
deck2.setForNPlayer("./src/test/resources/files/test_gameboard_characters.csv",5);
|
||||
GameBoard gameBoard = new GameBoard(Era.I,deck2,players.size());
|
||||
Player player = new Player("Lucy", TotemColor.BLUE);
|
||||
gameBoard.setupInitialRows(5);
|
||||
//gameBoard.DrawTopCard(gameBoard.getToprow().get(2),player);
|
||||
//assertEquals(1,player.getPlayerTribe().countCharactersByType(CharacterType.HUNTER));
|
||||
}
|
||||
|
||||
@Test
|
||||
void eventsToSolve() {
|
||||
|
||||
//tests that the result is a list of event cards
|
||||
CardDeck deck2 = new CardDeck();
|
||||
deck2.setForNPlayer(".\\src\\test\\resources\\files\\test_gameboard_events.csv",5);
|
||||
GameBoard gameBoard = new GameBoard(Era.I,deck2,players.size());
|
||||
|
||||
gameBoard.setupInitialRows(5);
|
||||
//assertTrue(gameBoard.EventsToSolve().getFirst().getCardId() > 84);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void setRows() {
|
||||
//tests that the top row has n+4 cards
|
||||
GameBoard gameBoard = new GameBoard(Era.I,deck,players.size());
|
||||
//assertEquals(9,gameBoard.SetRows(5).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
void setOffersToNull() {
|
||||
|
||||
//tests that the tiles are free
|
||||
|
||||
GameBoard gameBoard = new GameBoard(Era.I,deck,players.size());
|
||||
|
||||
// assertEquals(Collections.emptyList(),gameBoard.SetOffersToNull(5));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void nextEra() {
|
||||
|
||||
//tests that the eras progress
|
||||
|
||||
GameBoard gameBoard = new GameBoard(Era.I,deck,players.size());
|
||||
// assertEquals(Era.II,gameBoard.NextEra());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void changeBuildings() {
|
||||
|
||||
//tests that with era change the top row of building is of era II
|
||||
CardDeck deck2 = new CardDeck();
|
||||
deck2.setForNPlayer(".\\src\\test\\resources\\files\\only_building_deck.csv",5);
|
||||
GameBoard gameBoard = new GameBoard(Era.II,deck2,players.size());
|
||||
|
||||
//assertEquals(Era.II,gameBoard.ChangeBuildings().getFirst().getEra());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void getBuilding() {
|
||||
|
||||
//tests that the building has gained the player as owner
|
||||
|
||||
GameBoard gameBoard = new GameBoard(Era.I,deck,players.size());
|
||||
Player player = new Player("Diego",TotemColor.BLUE);
|
||||
player.addFood(4);
|
||||
//BuildingCard target = new BuildingCard(111,0,Era.II,4,3, Trigger.ENDGAME_BONUS_POINTS,null);
|
||||
//assertEquals(target.getOwner(),gameBoard.GetBuilding(player,target).getOwner());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
64
src/test/java/Server/OfferingTileTest.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package Server;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class OfferingTileTest {
|
||||
|
||||
OfferingTile offeringTile;
|
||||
|
||||
@Test
|
||||
void isEmpty() {
|
||||
|
||||
//test the ability of the method to recognize an occupied tile
|
||||
|
||||
OfferingTile offeringTile = new OfferingTile(4);
|
||||
|
||||
assertTrue(offeringTile.isEmpty());
|
||||
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void init(){
|
||||
offeringTile = new OfferingTile(4);
|
||||
offeringTile.setOccupant(new Player("Johnny", TotemColor.BLUE));
|
||||
}
|
||||
@Test
|
||||
void RemoveOccupant(){
|
||||
|
||||
//test that the occupant has been removed
|
||||
|
||||
assertNull(offeringTile.removeOccupant());
|
||||
}
|
||||
|
||||
@Test
|
||||
void GetOccupant(){
|
||||
|
||||
assertEquals("Johnny",offeringTile.getOccupant().getNickname());
|
||||
}
|
||||
|
||||
@Test
|
||||
void SetOccupant(){
|
||||
|
||||
//test that the player has been set
|
||||
|
||||
|
||||
assertEquals("Johnny",offeringTile.getOccupant().getNickname());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getActions(){
|
||||
|
||||
//tests that the actions associated to tile are the correct ones
|
||||
OfferingTile offeringTile = new OfferingTile(4);
|
||||
|
||||
List<Symbol> correct = List.of(Symbol.DOWN,Symbol.UP);
|
||||
|
||||
assertEquals(correct,offeringTile.getActions());
|
||||
|
||||
}
|
||||
}
|
||||
99
src/test/java/Server/PlayerTest.java
Normal file
@@ -0,0 +1,99 @@
|
||||
package Server;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class PlayerTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("Dovrebbe aggiungere la quantità di cibo indicata")
|
||||
void shouldAddFood() {
|
||||
//Arrange
|
||||
Player player = new Player("Giovanni", TotemColor.YELLOW);
|
||||
|
||||
//Act
|
||||
player.addFood(5);
|
||||
player.addFood(2);
|
||||
|
||||
//Assert
|
||||
assertEquals(7, player.getFoodTokens(), "5 + 2 deve fare 7");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Dovrebbe sottrarre il cibo quando i fondi sono sufficienti")
|
||||
void shouldSubtractFoodWhenFundsAreSufficient() {
|
||||
//Arrange
|
||||
Player player = new Player("Mario", TotemColor.PURPLE);
|
||||
|
||||
//Act
|
||||
player.addFood(5);
|
||||
player.removeFood(2);
|
||||
|
||||
//Assert
|
||||
assertEquals(3, player.getFoodTokens());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Non dovrebbe far scendere il cibo sotto zero quando i fondi sono insufficienti")
|
||||
void shouldNotGoNegativeWhenFoodIsInsufficient() {
|
||||
//Arrange
|
||||
Player player = new Player("Luigi", TotemColor.YELLOW);
|
||||
|
||||
//Act
|
||||
player.addFood(2);
|
||||
player.removeFood(5);
|
||||
|
||||
//Assert
|
||||
assertEquals(2, player.getFoodTokens()); //Se il cibo è insufficiente, il cibo rimane lo stesso di prima, non diminuisce!
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Dovrebbe sommare correttamente i Punti Prestigio aggiunti")
|
||||
void shouldAddPrestigePoints() {
|
||||
// Arrange
|
||||
Player player = new Player("Yoshi", TotemColor.YELLOW);
|
||||
|
||||
// Act
|
||||
player.addPrestigePoints(3);
|
||||
player.addPrestigePoints(4);
|
||||
player.addPrestigePoints(10);
|
||||
|
||||
// Assert
|
||||
assertEquals(17, player.getPrestigePoints());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Dovrebbe sottrarre correttamente i Punti Prestigio persi")
|
||||
void shouldRemovePrestigePoints() {
|
||||
//Arrange
|
||||
Player player = new Player("Gianbruno", TotemColor.BLUE);
|
||||
player.addPrestigePoints(10);
|
||||
|
||||
// Act
|
||||
player.removePrestigePoints(4);
|
||||
|
||||
// Assert
|
||||
assertEquals(6, player.getPrestigePoints());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Dovrebbe sottrarre correttamente i Punti Prestigio persi")
|
||||
void shouldRemovePrestigePoints2() {
|
||||
//Arrange
|
||||
Player player1 = new Player("Gino", TotemColor.BLUE);
|
||||
Player player2 = new Player("Olivia", TotemColor.RED);
|
||||
|
||||
player1.addPrestigePoints(10);
|
||||
player2.addPrestigePoints(2);
|
||||
|
||||
// Act
|
||||
player1.removePrestigePoints(4);
|
||||
player2.removePrestigePoints(7);
|
||||
|
||||
// Assert
|
||||
assertEquals(6, player1.getPrestigePoints());
|
||||
assertEquals(-5, player2.getPrestigePoints());
|
||||
}
|
||||
}
|
||||
131
src/test/java/Server/TribeTest.java
Normal file
@@ -0,0 +1,131 @@
|
||||
package Server;
|
||||
|
||||
import Server.Cards.BuildingCard;
|
||||
import Server.Cards.CharacterCard;
|
||||
import Server.Cards.CharacterType;
|
||||
import Server.Cards.Trigger;
|
||||
import Server.Era;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class TribeTest {
|
||||
private Tribe tribe;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(){
|
||||
tribe = new Tribe(); // creiamo una tribù nuova prima di ogni test
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGathererDiscount() {
|
||||
// 2 gatherer -> 6 cibi scontati
|
||||
tribe.addCharacter(new CharacterCard(1, 2, Era.I, CharacterType.GATHERER, 3, 0));
|
||||
tribe.addCharacter(new CharacterCard(2, 2, Era.I, CharacterType.GATHERER, 3, 0));
|
||||
|
||||
assertEquals(6,tribe.gathererDiscount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArtistsEndPoints() {
|
||||
// 5 artisti = 2 coppie. 2 * 10 = 20 punti.
|
||||
tribe.addCharacter(new CharacterCard(14, 2, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
tribe.addCharacter(new CharacterCard(15, 2, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
tribe.addCharacter(new CharacterCard(16, 2, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
tribe.addCharacter(new CharacterCard(17, 3, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
tribe.addCharacter(new CharacterCard(18, 4, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
|
||||
assertEquals(20, tribe.artistsEndPoints());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInventorsEndPoints() {
|
||||
// 3 Inventori, ma solo 2 invenzioni diverse: 2 (amo da pesca) e 3 (corda)
|
||||
// 3 * 2= 6 punti
|
||||
tribe.addCharacter(new CharacterCard(19, 2, Era.I, CharacterType.INVENTOR, 2, 0)); //statuetta
|
||||
tribe.addCharacter(new CharacterCard(53, 2, Era.II, CharacterType.INVENTOR, 2, 0)); //statuetta
|
||||
tribe.addCharacter(new CharacterCard(20, 2, Era.I, CharacterType.INVENTOR, 0, 0)); // canoa
|
||||
|
||||
assertEquals(6, tribe.inventorsEndPoints());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildingBonusPoints() {
|
||||
// Aggiungiamo l'edificio con id 117 che dà 25 punti
|
||||
BuildingCard card25 = new BuildingCard(117, 2, Era.III, 10, 0, Trigger.ENDGAME_BONUS_POINTS, null);
|
||||
tribe.addBuilding(card25);
|
||||
|
||||
// Se la tribù è vuota, dovrebbe dare esattamente 25 punti
|
||||
assertEquals(25, tribe.endPoints(), "L'edificio bonus dovrebbe dare 25 punti");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexScenario() {
|
||||
// Due Artisti (1 coppia = 10 punti)
|
||||
tribe.addCharacter(new CharacterCard(14, 2, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
tribe.addCharacter(new CharacterCard(15, 2, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
|
||||
// Un costruttore che vale 5 punti prestigio base
|
||||
tribe.addCharacter(new CharacterCard(62, 2, Era.II, CharacterType.BUILDER, 1, 5));
|
||||
|
||||
// L'edificio che raddoppia i punti dei costruttori (card id: 107 - ENDGAME_BUILDER_BONUS)
|
||||
BuildingCard doubleBuilderPoints = new BuildingCard(107, 2, Era.II, 6, 4, Trigger.ENDGAME_BUILDER_BONUS, null);
|
||||
tribe.addBuilding(doubleBuilderPoints);
|
||||
|
||||
/* CALCOLO ATTESO:
|
||||
- Artisti: 10 punti
|
||||
- Costruttori base: 5 punti
|
||||
- Bonus buildingAbilitiesEndPoints (buildersEndPoints * 2): 5 * 2 = 10 punti
|
||||
- Buildings: 4 punti
|
||||
TOTALE: 29 punti
|
||||
*/
|
||||
assertEquals(29, tribe.endPoints(), "Il totale dovrebbe essere 29");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComplexScenario2() {
|
||||
// PERSONAGGI
|
||||
|
||||
// 3 Artisti (1 coppia = 10 punti)
|
||||
tribe.addCharacter(new CharacterCard(14, 2, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
tribe.addCharacter(new CharacterCard(15, 2, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
tribe.addCharacter(new CharacterCard(16, 2, Era.I, CharacterType.ARTIST, 0, 0));
|
||||
|
||||
// 2 Costruttori (7 punti base totali)
|
||||
tribe.addCharacter(new CharacterCard(6, 2, Era.I, CharacterType.BUILDER, 1, 3));
|
||||
tribe.addCharacter(new CharacterCard(36, 2, Era.II, CharacterType.BUILDER, 1, 4));
|
||||
|
||||
// 4 Inventori (2 del gruppo 1, 1 del gruppo 2, 1 del gruppo 3 -> 4*3 = 12 punti)
|
||||
tribe.addCharacter(new CharacterCard(48, 2, Era.II, CharacterType.INVENTOR, 2, 0)); // Statuetta (iconValue=2)
|
||||
tribe.addCharacter(new CharacterCard(76, 2, Era.III, CharacterType.INVENTOR, 2, 0)); // Statuetta
|
||||
tribe.addCharacter(new CharacterCard(49, 4, Era.II, CharacterType.INVENTOR, 3, 0)); // Amo da pesca
|
||||
tribe.addCharacter(new CharacterCard(23, 4, Era.I, CharacterType.INVENTOR, 5, 0)); // Corda
|
||||
|
||||
// Rimanenti per fare il set da 6
|
||||
tribe.addCharacter(new CharacterCard(10, 2, Era.I, CharacterType.GATHERER, 3, 0));
|
||||
tribe.addCharacter(new CharacterCard(11, 2, Era.I, CharacterType.GATHERER, 3, 0));
|
||||
tribe.addCharacter(new CharacterCard(1, 2, Era.I, CharacterType.HUNTER, 1, 0));
|
||||
tribe.addCharacter(new CharacterCard(27, 2, Era.I, CharacterType.SHAMAN, 2, 0));
|
||||
|
||||
// EDIFICI
|
||||
|
||||
// id 107 (Bonus Costruttori) - 4 Punti Base Edificio
|
||||
tribe.addBuilding(new BuildingCard(107, 2, Era.II, 6, 4, Trigger.ENDGAME_BUILDER_BONUS, null));
|
||||
|
||||
// id 109 (Set da 6) - 6 Punti Base Edificio
|
||||
tribe.addBuilding(new BuildingCard(109, 2, Era.II, 5, 6, Trigger.ENDGAME_FOR_SIX, null));
|
||||
|
||||
// id 112 (Bonus Sciamani) - 4 Punti Base Edificio
|
||||
tribe.addBuilding(new BuildingCard(112, 2, Era.III, 7, 4, Trigger.ENDGAME_BONUS_CHARACTER, null));
|
||||
|
||||
// id 117 (25 Punti) - 0 Punti Base Edificio
|
||||
tribe.addBuilding(new BuildingCard(117, 2, Era.III, 10, 0, Trigger.ENDGAME_BONUS_POINTS, null));
|
||||
|
||||
|
||||
// VERIFICA
|
||||
// Totale atteso = 92
|
||||
assertEquals(92, tribe.endPoints(), "Il totale dovrebbe essere 92 punti");
|
||||
}
|
||||
}
|
||||
62
src/test/java/Server/TurnTileOldTest.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package Server;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class TurnTileOldTest {
|
||||
TurnTileOld turnTileOld;
|
||||
|
||||
Player player1 = new Player("A", TotemColor.PURPLE);
|
||||
Player player2 = new Player("B", TotemColor.YELLOW);
|
||||
Player player3 = new Player("C", TotemColor.BLUE);
|
||||
Player player4 = new Player("D", TotemColor.GREEN);
|
||||
Player player5 = new Player("E", TotemColor.RED);
|
||||
List<Player> players = new ArrayList<>();
|
||||
@BeforeEach
|
||||
public void setUp(){
|
||||
|
||||
players.add(player1);
|
||||
players.add(player2);
|
||||
players.add(player3);
|
||||
players.add(player4);
|
||||
players.add(player5);
|
||||
turnTileOld = new TurnTileOld(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void startOrder() {
|
||||
assertEquals(5, turnTileOld.startOrder(players).length);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void giveReward() {
|
||||
turnTileOld.startOrder(players);
|
||||
player5.addFood(1);
|
||||
assertEquals(0, turnTileOld.giveReward(player5).getFoodTokens());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void nextPlayer() {
|
||||
|
||||
//test that the method proceeds along the array
|
||||
turnTileOld.startOrder(players);
|
||||
assertEquals(player2, turnTileOld.nextPlayer());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void addPlayer() {
|
||||
|
||||
//verify that the first player changes
|
||||
|
||||
turnTileOld.startOrder(players);
|
||||
assertEquals(player2, turnTileOld.addPlayer(player2));
|
||||
}
|
||||
}
|
||||
64
src/test/java/Server/TurnTileTest.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package Server;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class TurnTileTest {
|
||||
TurnTile turnTile;
|
||||
|
||||
Player player1 = new Player("A", TotemColor.PURPLE);
|
||||
Player player2 = new Player("B", TotemColor.YELLOW);
|
||||
Player player3 = new Player("C", TotemColor.BLUE);
|
||||
Player player4 = new Player("D", TotemColor.GREEN);
|
||||
Player player5 = new Player("E", TotemColor.RED);
|
||||
List<Player> players = new ArrayList<>();
|
||||
@BeforeEach
|
||||
public void setUp(){
|
||||
|
||||
players.add(player1);
|
||||
players.add(player2);
|
||||
players.add(player3);
|
||||
players.add(player4);
|
||||
players.add(player5);
|
||||
turnTile = new TurnTile(5);
|
||||
}
|
||||
/**
|
||||
@Test
|
||||
void startOrder() {
|
||||
assertEquals(5, turnTileOld.startOrder(players).length);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void giveReward() {
|
||||
turnTileOld.startOrder(players);
|
||||
player5.addFood(1);
|
||||
assertEquals(0, turnTileOld.giveReward(player5).getFoodTokens());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void nextPlayer() {
|
||||
|
||||
//test that the method proceeds along the array
|
||||
turnTileOld.startOrder(players);
|
||||
assertEquals(player2, turnTileOld.nextPlayer());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void addPlayer() {
|
||||
|
||||
//verify that the first player changes
|
||||
|
||||
turnTileOld.startOrder(players);
|
||||
assertEquals(player2, turnTileOld.addPlayer(player2));
|
||||
}
|
||||
**/
|
||||
|
||||
}
|
||||
17
src/test/resources/files/only_building_deck.csv
Normal file
@@ -0,0 +1,17 @@
|
||||
B;1;2;I;3;1;SHAMAN_NO_LOSS
|
||||
B;3;4;II;6;2;FOOD_FOR_SIX
|
||||
B;3;5;II;6;2;SUSTAIN_DISCOUNT;INVENTOR
|
||||
B;17;5;II;6;2;SUSTAIN_DISCOUNT;ARTIST
|
||||
B;5;3;III;6;2;SHAMAN_NO_LOSS
|
||||
B;6;3;II;6;2;BONUS_FOOD_ENDTURN
|
||||
B;7;3;II;6;2;FOOD_PER_INVENTORS
|
||||
B;8;3;II;6;2;SHAMAN_BONUS
|
||||
B;9;3;II;6;2;SHAMAN_DOUBLE_POINTS
|
||||
B;10;3;II;6;2;HUNT_BONUS
|
||||
B;11;3;II;6;2;ENDGAME_BUILDER_BONUS
|
||||
B;12;3;II;6;2;PAINTING_FOOD_BONUS
|
||||
B;13;3;II;6;2;ENDGAME_FOR_SIX
|
||||
B;14;3;II;6;2;ENDGAME_BONUS_CHARACTER;BUILDER
|
||||
B;18;3;II;6;2;ENDGAME_BONUS_CHARACTER;SHAMAN
|
||||
B;15;3;II;6;2;EXTRA_DRAW
|
||||
B;16;3;II;6;2;ENDGAME_BONUS_POINTS
|
||||
|
3
src/test/resources/files/only_character_deck.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
C;24;3;I;INVENTOR;7;0
|
||||
C;25;4;I;INVENTOR;4;0
|
||||
C;26;5;II;SHAMAN;2;0
|
||||
|
4
src/test/resources/files/only_event_deck.csv
Normal file
@@ -0,0 +1,4 @@
|
||||
E;1;0;I;SUSTAINMENT;1;0
|
||||
E;2;5;II;HUNT;2;0
|
||||
E;3;3;III;SHAMANIC_RITUAL;2;3
|
||||
E;4;4;FINAL;CAVE_PAINTINGS;2;1
|
||||
|
24
src/test/resources/files/test_deck.csv
Normal file
@@ -0,0 +1,24 @@
|
||||
B;1;2;I;3;1;SHAMAN_NO_LOSS
|
||||
B;3;4;II;6;2;FOOD_FOR_SIX
|
||||
B;3;5;II;6;2;SUSTAIN_DISCOUNT;INVENTOR
|
||||
B;17;5;II;6;2;SUSTAIN_DISCOUNT;ARTIST
|
||||
B;5;3;III;6;2;SHAMAN_NO_LOSS
|
||||
B;6;3;II;6;2;BONUS_FOOD_ENDTURN
|
||||
B;7;3;II;6;2;FOOD_PER_INVENTORS
|
||||
B;8;3;II;6;2;SHAMAN_BONUS
|
||||
B;9;3;II;6;2;SHAMAN_DOUBLE_POINTS
|
||||
B;10;3;II;6;2;HUNT_BONUS
|
||||
B;11;3;II;6;2;ENDGAME_BUILDER_BONUS
|
||||
B;12;3;II;6;2;PAINTING_FOOD_BONUS
|
||||
B;13;3;II;6;2;ENDGAME_FOR_SIX
|
||||
B;14;3;II;6;2;ENDGAME_BONUS_CHARACTER;BUILDER
|
||||
B;18;3;II;6;2;ENDGAME_BONUS_CHARACTER;SHAMAN
|
||||
B;15;3;II;6;2;EXTRA_DRAW
|
||||
B;16;3;II;6;2;ENDGAME_BONUS_POINTS
|
||||
C;24;3;I;INVENTOR;7;0
|
||||
C;25;4;I;INVENTOR;4;0
|
||||
C;26;5;II;SHAMAN;2;0
|
||||
E;21;0;I;SUSTAINMENT;1;0
|
||||
E;22;5;II;HUNT;2;0
|
||||
E;23;3;III;SHAMANIC_RITUAL;2;3
|
||||
E;34;4;FINAL;CAVE_PAINTINGS;2;1
|
||||
|
96
src/test/resources/files/test_gameboard.csv
Normal file
@@ -0,0 +1,96 @@
|
||||
C;1;0;I;HUNTER;1;0
|
||||
C;2;0;I;HUNTER;1;0
|
||||
C;3;0;I;HUNTER;0;0
|
||||
C;4;3;I;HUNTER;0;0
|
||||
C;5;3;I;HUNTER;0;0
|
||||
C;6;0;I;HUNTER;1;3
|
||||
C;7;0;I;HUNTER;2;0
|
||||
C;8;5;I;HUNTER;2;1
|
||||
C;9;0;I;HUNTER;1;2
|
||||
C;10;0;I;HUNTER;3;0
|
||||
C;11;0;I;HUNTER;3;0
|
||||
C;12;3;I;HUNTER;3;0
|
||||
C;13;5;I;HUNTER;3;0
|
||||
C;14;0;I;HUNTER;0;0
|
||||
C;15;0;I;HUNTER;0;0
|
||||
C;16;0;I;HUNTER;0;0
|
||||
C;17;3;I;HUNTER;0;0
|
||||
C;18;4;I;HUNTER;0;0
|
||||
C;19;0;I;HUNTER;8;0
|
||||
C;20;0;I;HUNTER;0;0
|
||||
C;21;0;I;HUNTER;1;0
|
||||
C;22;0;I;HUNTER;9;0
|
||||
C;23;4;I;HUNTER;5;0
|
||||
C;24;4;I;HUNTER;7;0
|
||||
C;25;4;I;HUNTER;4;0
|
||||
C;26;5;I;HUNTER;2;0
|
||||
C;27;0;I;HUNTER;2;0
|
||||
C;28;0;I;HUNTER;1;0
|
||||
C;29;4;I;HUNTER;1;0
|
||||
C;30;0;II;HUNTER;0;0
|
||||
C;31;0;II;HUNTER;0;0
|
||||
C;32;3;II;HUNTER;1;0
|
||||
C;33;0;II;HUNTER;1;0
|
||||
C;34;4;II;HUNTER;1;0
|
||||
C;35;5;II;HUNTER;0;0
|
||||
C;36;0;II;HUNTER;1;4
|
||||
C;37;0;II;HUNTER;2;1
|
||||
C;38;3;II;HUNTER;1;2
|
||||
C;39;0;II;HUNTER;2;3
|
||||
C;40;0;II;HUNTER;3;0
|
||||
C;41;3;II;HUNTER;3;0
|
||||
C;42;4;II;HUNTER;3;0
|
||||
C;43;5;II;HUNTER;3;0
|
||||
C;44;3;II;HUNTER;0;0
|
||||
C;45;0;II;HUNTER;0;0
|
||||
C;46;0;II;HUNTER;0;0
|
||||
C;47;0;II;HUNTER;0;0
|
||||
C;48;0;II;HUNTER;0;0
|
||||
C;49;4;II;HUNTER;0;0
|
||||
C;50;0;II;HUNTER;0;0
|
||||
C;51;0;II;HUNTER;0;0
|
||||
C;52;0;II;HUNTER;0;0
|
||||
C;53;0;II;HUNTER;0;0
|
||||
C;54;0;II;HUNTER;2;0
|
||||
C;55;0;II;HUNTER;2;0
|
||||
C;56;5;II;HUNTER;1;0
|
||||
C;57;5;II;HUNTER;2;0
|
||||
C;58;5;III;HUNTER;1;0
|
||||
C;59;0;III;HUNTER;0;0
|
||||
C;60;0;III;HUNTER;0;0
|
||||
C;61;0;III;HUNTER;1;0
|
||||
C;62;0;III;HUNTER;1;5
|
||||
C;63;0;III;HUNTER;2;3
|
||||
C;64;5;III;HUNTER;1;4
|
||||
C;65;0;III;HUNTER;2;2
|
||||
C;66;5;III;HUNTER;3;0
|
||||
C;67;4;III;HUNTER;3;0
|
||||
C;68;0;III;HUNTER;3;0
|
||||
C;69;5;III;HUNTER;0;0
|
||||
C;70;0;III;HUNTER;0;0
|
||||
C;71;0;III;HUNTER;0;0
|
||||
C;72;0;III;HUNTER;0;0
|
||||
C;73;4;III;HUNTER;0;0
|
||||
C;74;3;III;HUNTER;0;0
|
||||
C;75;3;III;HUNTER;0;0
|
||||
C;76;0;III;HUNTER;0;0
|
||||
C;77;0;III;HUNTER;0;0
|
||||
C;78;0;III;HUNTER;0;0
|
||||
C;79;0;III;HUNTER;0;0
|
||||
C;80;3;III;HUNTER;2;0
|
||||
C;81;0;III;HUNTER;3;0
|
||||
C;82;0;III;HUNTER;2;0
|
||||
C;83;0;III;HUNTER;3;0
|
||||
C;84;4;III;HUNTER;2;0
|
||||
E;85;0;I;HUNT;1;1
|
||||
E;86;0;I;SUSTAINMENT;1;1
|
||||
E;87;0;I;SHAMANIC_RITUAL;5;3
|
||||
E;88;0;I;CAVE_PAINTINGS;2;1
|
||||
E;89;0;II;HUNT;1;2
|
||||
E;90;0;II;SUSTAINMENT;1;2
|
||||
E;91;0;II;SHAMANIC_RITUAL;10;5
|
||||
E;92;0;II;CAVE_PAINTINGS;2;2
|
||||
E;93;0;III;HUNT;1;3
|
||||
E;94;0;III;CAVE_PAINTINGS;2;3
|
||||
E;95;0;FINAL;SUSTAINMENT;1;3
|
||||
E;96;0;FINAL;SHAMANIC_RITUAL;15;7
|
||||
|
84
src/test/resources/files/test_gameboard_characters.csv
Normal file
@@ -0,0 +1,84 @@
|
||||
C;1;0;I;HUNTER;1;0
|
||||
C;2;0;I;HUNTER;1;0
|
||||
C;3;0;I;HUNTER;0;0
|
||||
C;4;3;I;HUNTER;0;0
|
||||
C;5;3;I;HUNTER;0;0
|
||||
C;6;0;I;HUNTER;1;3
|
||||
C;7;0;I;HUNTER;2;0
|
||||
C;8;5;I;HUNTER;2;1
|
||||
C;9;0;I;HUNTER;1;2
|
||||
C;10;0;I;HUNTER;3;0
|
||||
C;11;0;I;HUNTER;3;0
|
||||
C;12;3;I;HUNTER;3;0
|
||||
C;13;5;I;HUNTER;3;0
|
||||
C;14;0;I;HUNTER;0;0
|
||||
C;15;0;I;HUNTER;0;0
|
||||
C;16;0;I;HUNTER;0;0
|
||||
C;17;3;I;HUNTER;0;0
|
||||
C;18;4;I;HUNTER;0;0
|
||||
C;19;0;I;HUNTER;8;0
|
||||
C;20;0;I;HUNTER;0;0
|
||||
C;21;0;I;HUNTER;1;0
|
||||
C;22;0;I;HUNTER;9;0
|
||||
C;23;4;I;HUNTER;5;0
|
||||
C;24;4;I;HUNTER;7;0
|
||||
C;25;4;I;HUNTER;4;0
|
||||
C;26;5;I;HUNTER;2;0
|
||||
C;27;0;I;HUNTER;2;0
|
||||
C;28;0;I;HUNTER;1;0
|
||||
C;29;4;I;HUNTER;1;0
|
||||
C;30;0;II;HUNTER;0;0
|
||||
C;31;0;II;HUNTER;0;0
|
||||
C;32;3;II;HUNTER;1;0
|
||||
C;33;0;II;HUNTER;1;0
|
||||
C;34;4;II;HUNTER;1;0
|
||||
C;35;5;II;HUNTER;0;0
|
||||
C;36;0;II;HUNTER;1;4
|
||||
C;37;0;II;HUNTER;2;1
|
||||
C;38;3;II;HUNTER;1;2
|
||||
C;39;0;II;HUNTER;2;3
|
||||
C;40;0;II;HUNTER;3;0
|
||||
C;41;3;II;HUNTER;3;0
|
||||
C;42;4;II;HUNTER;3;0
|
||||
C;43;5;II;HUNTER;3;0
|
||||
C;44;3;II;HUNTER;0;0
|
||||
C;45;0;II;HUNTER;0;0
|
||||
C;46;0;II;HUNTER;0;0
|
||||
C;47;0;II;HUNTER;0;0
|
||||
C;48;0;II;HUNTER;0;0
|
||||
C;49;4;II;HUNTER;0;0
|
||||
C;50;0;II;HUNTER;0;0
|
||||
C;51;0;II;HUNTER;0;0
|
||||
C;52;0;II;HUNTER;0;0
|
||||
C;53;0;II;HUNTER;0;0
|
||||
C;54;0;II;HUNTER;2;0
|
||||
C;55;0;II;HUNTER;2;0
|
||||
C;56;5;II;HUNTER;1;0
|
||||
C;57;5;II;HUNTER;2;0
|
||||
C;58;5;III;HUNTER;1;0
|
||||
C;59;0;III;HUNTER;0;0
|
||||
C;60;0;III;HUNTER;0;0
|
||||
C;61;0;III;HUNTER;1;0
|
||||
C;62;0;III;HUNTER;1;5
|
||||
C;63;0;III;HUNTER;2;3
|
||||
C;64;5;III;HUNTER;1;4
|
||||
C;65;0;III;HUNTER;2;2
|
||||
C;66;5;III;HUNTER;3;0
|
||||
C;67;4;III;HUNTER;3;0
|
||||
C;68;0;III;HUNTER;3;0
|
||||
C;69;5;III;HUNTER;0;0
|
||||
C;70;0;III;HUNTER;0;0
|
||||
C;71;0;III;HUNTER;0;0
|
||||
C;72;0;III;HUNTER;0;0
|
||||
C;73;4;III;HUNTER;0;0
|
||||
C;74;3;III;HUNTER;0;0
|
||||
C;75;3;III;HUNTER;0;0
|
||||
C;76;0;III;HUNTER;0;0
|
||||
C;77;0;III;HUNTER;0;0
|
||||
C;78;0;III;HUNTER;0;0
|
||||
C;79;0;III;HUNTER;0;0
|
||||
C;80;3;III;HUNTER;2;0
|
||||
C;81;0;III;HUNTER;3;0
|
||||
C;82;0;III;HUNTER;2;0
|
||||
C;83;0;III;HUNTER;3;0
|
||||
C;84;4;III;HUNTER;2;0
|
||||
|
12
src/test/resources/files/test_gameboard_events.csv
Normal file
@@ -0,0 +1,12 @@
|
||||
E;85;0;I;HUNT;1;1
|
||||
E;86;0;I;SUSTAINMENT;1;1
|
||||
E;87;0;I;SHAMANIC_RITUAL;5;3
|
||||
E;88;0;I;CAVE_PAINTINGS;2;1
|
||||
E;89;0;II;HUNT;1;2
|
||||
E;90;0;II;SUSTAINMENT;1;2
|
||||
E;91;0;II;SHAMANIC_RITUAL;10;5
|
||||
E;92;0;II;CAVE_PAINTINGS;2;2
|
||||
E;93;0;III;HUNT;1;3
|
||||
E;94;0;III;CAVE_PAINTINGS;2;3
|
||||
E;95;0;FINAL;SUSTAINMENT;1;3
|
||||
E;96;0;FINAL;SHAMANIC_RITUAL;15;7
|
||||
|