diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
new file mode 100644
index 0000000..16a322c
--- /dev/null
+++ b/.github/workflows/maven.yml
@@ -0,0 +1,21 @@
+name: Java CI with Maven
+
+on:
+ pull_request:
+ branches: [ "master" ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Set up JDK 21
+ uses: actions/setup-java@v3
+ with:
+ java-version: '21'
+ distribution: 'temurin'
+ cache: maven
+ - name: Build with Maven
+ run: mvn -B package --file pom.xml
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SpielController.drawio b/SpielController.drawio
index b8cac88..6b16fed 100644
--- a/SpielController.drawio
+++ b/SpielController.drawio
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/intellij-java-google-style.xml b/intellij-java-google-style.xml
new file mode 100644
index 0000000..6b8b9ef
--- /dev/null
+++ b/intellij-java-google-style.xml
@@ -0,0 +1,598 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:.*Style
+
+ http://schemas.android.com/apk/res/android
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:layout_width
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_height
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_weight
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_margin
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_marginTop
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_marginBottom
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_marginStart
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_marginEnd
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_marginLeft
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_marginRight
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:layout_.*
+
+ http://schemas.android.com/apk/res/android
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:padding
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:paddingTop
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:paddingBottom
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:paddingStart
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:paddingEnd
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:paddingLeft
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:paddingRight
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*
+ http://schemas.android.com/apk/res/android
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+ http://schemas.android.com/apk/res-auto
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+ http://schemas.android.com/tools
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/pn532/pn532-sdk/1.0.2/pn532-sdk-1.0.2.pom b/lib/pn532/pn532-sdk/1.0.2/pn532-sdk-1.0.2.pom
index b37e64a..0390562 100644
--- a/lib/pn532/pn532-sdk/1.0.2/pn532-sdk-1.0.2.pom
+++ b/lib/pn532/pn532-sdk/1.0.2/pn532-sdk-1.0.2.pom
@@ -1,9 +1,11 @@
-
- 4.0.0
- pn532
+
pn532-sdk
- 1.0.2
POM was created from install:install-file
+ pn532
+ 4.0.0
+ 1.0.2
diff --git a/lib/pn532/pn532-sdk/maven-metadata-local.xml b/lib/pn532/pn532-sdk/maven-metadata-local.xml
index b178090..0faba88 100644
--- a/lib/pn532/pn532-sdk/maven-metadata-local.xml
+++ b/lib/pn532/pn532-sdk/maven-metadata-local.xml
@@ -1,12 +1,12 @@
- pn532
pn532-sdk
+ pn532
+ 20231116111447
1.0.2
1.0.2
- 20231116111447
diff --git a/pom.xml b/pom.xml
index f290ae7..32b39bd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,165 +1,167 @@
-
- 4.0.0
+
+ schafkopf-backend-java
- org.example
- schafkopf-backend-java
- 1.0-SNAPSHOT
+
+ schafkopf-backend-build
-
- 21
- 21
- UTF-8
-
- 1.7.32
- 2.4.0
- 3.5.1
+
+
+ maven-checkstyle-plugin
+
+
+
+ google_checks.xml
+ true
+ true
+ warning
+
+
+ check
+
+ validate
+ validate
+
+
+ org.apache.maven.plugins
+ 3.3.1
+
+
+ maven-jar-plugin
+
+
+
+ org.schafkopf.BackendServer
+
+
+
+ 3.3.0
+
-
-
- schafkopf-backend-build
-
-
- org.apache.maven.plugins
- maven-checkstyle-plugin
- 3.3.1
-
-
- validate
- validate
-
- google_checks.xml
- true
- true
- warning
-
-
- check
-
-
-
-
-
- maven-jar-plugin
- 3.3.0
-
-
-
- org.example.BackendServer
-
-
-
-
+
+ maven-compiler-plugin
+
+ true
+ true
+ false
+
+ 3.11.0
+
-
- maven-compiler-plugin
- 3.11.0
-
- true
- true
- false
-
-
+
+ maven-shade-plugin
+
+
+
+
+
+
+
+
+ shade
+
+ package
+
+
+ org.apache.maven.plugins
+ 3.5.1
+
+
+
+
+
+ slf4j-api
+ org.slf4j
+ ${slf4j.version}
+
+
+ slf4j-simple
+ org.slf4j
+ ${slf4j.version}
+
+
+
+ websocket-jetty-api
+ org.eclipse.jetty.websocket
+ 11.0.15
+
+
+
+ websocket-jetty-server
+ org.eclipse.jetty.websocket
+ 11.0.15
+
+
+ jetty-servlets
+ org.eclipse.jetty
+ 11.0.15
+
+
+
+ websocket-jetty-client
+ org.eclipse.jetty.websocket
+ 11.0.15
+
+
+ gson
+ com.google.code.gson
+ 2.10.1
+
+
+ dotenv-java
+ io.github.cdimascio
+ 3.0.0
+
-
- org.apache.maven.plugins
- maven-shade-plugin
- 3.5.1
-
-
-
-
-
-
-
- package
-
- shade
-
-
-
-
-
-
-
-
- in-project
- In Project Repo
- file://${project.basedir}/lib
-
-
+
+
+ pi4j-core
+ com.pi4j
+ ${pi4j.version}
+
-
-
- org.slf4j
- slf4j-api
- ${slf4j.version}
-
-
- org.slf4j
- slf4j-simple
- ${slf4j.version}
-
-
-
- org.eclipse.jetty.websocket
- websocket-jetty-api
- 11.0.15
-
-
-
- org.eclipse.jetty.websocket
- websocket-jetty-server
- 11.0.15
-
-
- org.eclipse.jetty
- jetty-servlets
- 11.0.15
-
-
-
- org.eclipse.jetty.websocket
- websocket-jetty-client
- 11.0.15
-
-
- com.google.code.gson
- gson
- 2.10.1
-
-
- io.github.cdimascio
- dotenv-java
- 3.0.0
-
-
-
-
- com.pi4j
- pi4j-core
- ${pi4j.version}
-
-
-
-
- com.pi4j
- pi4j-plugin-raspberrypi
- ${pi4j.version}
-
-
- com.pi4j
- pi4j-plugin-pigpio
- ${pi4j.version}
-
+
+
+ pi4j-plugin-raspberrypi
+ com.pi4j
+ ${pi4j.version}
+
+
+ pi4j-plugin-pigpio
+ com.pi4j
+ ${pi4j.version}
+
-
- pn532
- pn532-sdk
- 1.0.2
-
-
+
+ pn532-sdk
+ pn532
+ 1.0.2
+
+
+ org.example
+
+ 4.0.0
+
+ 3.5.1
+ 21
+ 21
+
+ 2.4.0
+ UTF-8
+ 1.7.32
+
+
+
+
+ in-project
+ In Project Repo
+ file://${project.basedir}/lib
+
+
+
+ 1.0-SNAPSHOT
\ No newline at end of file
diff --git a/src/main/java/org/example/BackendServer.java b/src/main/java/org/example/BackendServer.java
deleted file mode 100644
index ef68297..0000000
--- a/src/main/java/org/example/BackendServer.java
+++ /dev/null
@@ -1,164 +0,0 @@
-package org.example;
-
-import java.net.InetSocketAddress;
-import java.net.URI;
-import java.time.Duration;
-import java.util.EnumSet;
-
-import jakarta.servlet.DispatcherType;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-
-import org.eclipse.jetty.servlet.FilterHolder;
-import org.eclipse.jetty.servlets.CrossOriginFilter;
-import io.github.cdimascio.dotenv.Dotenv;
-
-public class BackendServer
-{
- private List frontendEndpoints = new ArrayList<>();
- public static void main(String[] args) throws Exception
- {
- BackendServer server = new BackendServer();
- server.setPort(8080);
- server.start();
- server.join();
- }
-
- private final Server server;
- private final ServerConnector connector;
-
- private final Schafkopf schafkopfGame;
- private final KartenLeser nfcLeser;
- private CountDownLatch nfcLatch = new CountDownLatch(1);
-
- private Boolean readingMode = false;
- private String uidString = "";
-
- public BackendServer()
- {
- Dotenv dotenv = Dotenv.configure().directory("./").load();
- server = new Server();
- InetSocketAddress address = new InetSocketAddress(dotenv.get("VITE_APP_WEBSOCKET_IP"), 8080);
- connector = new ServerConnector(server);
- connector.setHost(address.getHostName());
- connector.setPort(address.getPort());
- server.addConnector(connector);
-
- schafkopfGame = new Schafkopf(this);
- nfcLeser = new KartenLeser(this);
-
- // Setup the basic application "context" for this application at "/"
- // This is also known as the handler tree (in jetty speak)
- ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
- context.setContextPath("/");
- server.setHandler(context);
-
- // Configure CORS settings
- configureCORS(context);
-
- // Configure specific websocket behavior
- JettyWebSocketServletContainerInitializer.configure(context, (servletContext, wsContainer) ->
- {
- // Configure default max size
- wsContainer.setMaxTextMessageSize(65535);
- wsContainer.setIdleTimeout(Duration.ofDays(300000));
- // Add websockets
- wsContainer.addMapping("/schafkopf-events/*", new FrontendEndpointCreator(this));
-
- });
- }
-
- private void configureCORS(ServletContextHandler context) {
- // Enable CORS for all paths
- FilterHolder cors = context.addFilter(CrossOriginFilter.class, "/*", null);
-
- // Configure allowed origins, headers, and methods
- cors.setInitParameter("allowedOrigins", "http://192.168.178.126:5173");
- cors.setInitParameter("allowedHeaders", "X-Requested-With,Content-Type,Accept,Origin");
- cors.setInitParameter("allowedMethods", "GET,POST,PUT,DELETE,OPTIONS");
-
- // Add filter mappings
- EnumSet types = EnumSet.of(DispatcherType.REQUEST);
- context.addFilter(cors, "*", types);
- }
-
- public void setPort(int port)
- {
- connector.setPort(port);
- }
-
- public void start() throws Exception
- {
- server.start();
- }
-
- public URI getURI()
- {
- return server.getURI();
- }
-
- public void stop() throws Exception
- {
- server.stop();
- }
-
- public void join() throws InterruptedException
- {
- server.join();
- }
-
- public void addFrontendEndpoint(FrontendEndpoint endpoint) {
- frontendEndpoints.add(endpoint);
- }
-
- public void removeFrontendEndpoint(FrontendEndpoint endpoint) {
- frontendEndpoints.remove(endpoint);
- }
-
- public void sendMessageToAllFrontendEndpoints(String message) {
- for (FrontendEndpoint endpoint : frontendEndpoints) {
- endpoint.sendMessage(message);
- }
- }
-
- public void startSchafkopfGame() {
- schafkopfGame.startGame();
- }
-
- public void stopSchafkopfGame() {
- schafkopfGame.stopGame();
- }
-
- public void showTrumpf() {
- schafkopfGame.showTrumpf();
- }
-
- public void showFarbe() {
- schafkopfGame.showFarbe();
- }
- public void nfcGelesen(String uidString) {
- if(this.uidString.equals(uidString)){
- return;
- }
- if(!this.readingMode){
- return;
- }
-
- this.uidString = uidString;
- nfcLatch.countDown();
- }
-
- public String waitForCardScan() throws InterruptedException {
- this.readingMode = true;
- nfcLatch.await();
- this.readingMode = false;
- nfcLatch = new CountDownLatch(1);
- return this.uidString;
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/example/FrontendEndpoint.java b/src/main/java/org/example/FrontendEndpoint.java
deleted file mode 100644
index ec7b08a..0000000
--- a/src/main/java/org/example/FrontendEndpoint.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.example;
-
-import com.google.gson.Gson;
-import org.eclipse.jetty.websocket.api.Session;
-import org.eclipse.jetty.websocket.api.WebSocketAdapter;
-
-import java.io.IOException;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CountDownLatch;
-
-public class FrontendEndpoint extends WebSocketAdapter {
- private final CountDownLatch closureLatch = new CountDownLatch(1);
- private BackendServer backendServer;
- public FrontendEndpoint(BackendServer backendServer) {
- this.backendServer = backendServer;
- System.out.println("new FrontendEndpoint");
- }
-
- @Override
- public void onWebSocketConnect(Session session) {
- super.onWebSocketConnect(session);
- String clientIp = session.getRemoteAddress().toString();
- System.out.println("Endpoint connected from ip: " + clientIp);
-
- backendServer.addFrontendEndpoint(this);
- }
-
- @Override
- public void onWebSocketText(String message) {
- super.onWebSocketText(message);
- System.out.println("Received TEXT message:" + message);
-
- if (message.contains("startsimulation")) {
- backendServer.startSchafkopfGame();
- }
-
- if (message.contains("stopsimulation")) {
- backendServer.stopSchafkopfGame();
- }
-
- if(message.contains("showtrumpf")) {
- backendServer.showTrumpf();
- }
-
- if(message.contains("showfarben")) {
- backendServer.showFarbe();
- }
- }
-
- @Override
- public void onWebSocketClose(int statusCode, String reason) {
- super.onWebSocketClose(statusCode, reason);
-
- backendServer.removeFrontendEndpoint(this);
-
- System.out.println("Socket Closed: [" + statusCode + "] " + reason);
- closureLatch.countDown();
- }
-
- @Override
- public void onWebSocketError(Throwable cause) {
- super.onWebSocketError(cause);
- cause.printStackTrace(System.err);
- }
-
- public void sendMessage(String message) {
- try {
- getRemote().sendString(message);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/example/FrontendEndpointCreator.java b/src/main/java/org/example/FrontendEndpointCreator.java
deleted file mode 100644
index f1c27b6..0000000
--- a/src/main/java/org/example/FrontendEndpointCreator.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.example;
-import org.eclipse.jetty.websocket.server.JettyServerUpgradeRequest;
-import org.eclipse.jetty.websocket.server.JettyServerUpgradeResponse;
-import org.eclipse.jetty.websocket.server.JettyWebSocketCreator;
-
-public class FrontendEndpointCreator implements JettyWebSocketCreator
-{
- private BackendServer backendServer;
- public FrontendEndpointCreator(BackendServer backendServer) {
- this.backendServer = backendServer;
- }
-
- @Override
- public Object createWebSocket(JettyServerUpgradeRequest jettyServerUpgradeRequest, JettyServerUpgradeResponse jettyServerUpgradeResponse)
- {
- return new FrontendEndpoint(this.backendServer);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/example/Karte.java b/src/main/java/org/example/Karte.java
deleted file mode 100644
index c89ea69..0000000
--- a/src/main/java/org/example/Karte.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.example;
-
-public class Karte {
- private String id;
- private String name;
- private String farbe;
- private String symbol;
- private int punkte;
- Karte(String id, String name, String farbe, String symbol, int punkte){
- this.id = id;
- this.name = name;
- this.farbe = farbe;
- this.symbol = symbol;
- this.punkte = punkte;
- }
-
- public String getId(){
- return this.id;
- }
-
- public String getName(){
- return this.name;
- }
-
- public String getFarbe(){
- return this.farbe;
- }
-
- public String getSymbol() {
- return this.symbol;
- }
-}
diff --git a/src/main/java/org/example/KartenLeser.java b/src/main/java/org/example/KartenLeser.java
deleted file mode 100644
index 3e13729..0000000
--- a/src/main/java/org/example/KartenLeser.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.example;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.pi4j.Pi4J;
-import com.pi4j.io.i2c.I2C;
-import mk.hsilomedus.pn532.*;
-import mk.hsilomedus.pn532.Pn532SamThread.Pn532SamThreadListener;
-
-public final class KartenLeser {
-
- private static BackendServer server;
-
- public KartenLeser(BackendServer server){
- this.server = server;
-
- new Thread(() -> {
-
- new KartenListener().run();
-
- }).start();
- }
-
-
-
- public static final void main(String[] args) throws IOException {
-
- }
-
- private static class KartenListener implements Pn532SamThreadListener {
-
- @SuppressWarnings("rawtypes")
- Pn532SamThread i2cThread = new Pn532SamThread<>(this, new Pn532I2c());
-
-
- public void run() {
- Pn532ContextHelper.initialize();
- i2cThread.start();
- }
-
- public void close() {
- closeThread(i2cThread);
- Pn532ContextHelper.shutdown();
- }
-
- @Override
- public void receiveMessage(String message) {
- System.out.println(message);
- }
-
- @Override
- public void uidReceived(String displayName, byte[] uid) {
- server.nfcGelesen(Pn532SamThreadListener.getUidString(uid) );
- }
-
- @SuppressWarnings("rawtypes")
- private void closeThread(Pn532SamThread thread) {
- if (thread != null && thread.isAlive()) {
- thread.close();
-
- try {
- thread.join();
- } catch (InterruptedException e) {
- System.out.println("Error closing thread: " + e.getMessage());
- Thread.currentThread().interrupt();
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/example/KartenUtil.java b/src/main/java/org/example/KartenUtil.java
deleted file mode 100644
index ebebed8..0000000
--- a/src/main/java/org/example/KartenUtil.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package org.example;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class KartenUtil {
-
- public static List getKartenByFarbe(List karten, String farbe) {
- List result = new ArrayList<>();
- for (Karte karte : karten) {
- if (karte.getFarbe().equalsIgnoreCase(farbe)) {
- result.add(karte);
- }
- }
- return result;
- }
-
- public static List getKartenBySymbol(List karten, String symbol) {
- List result = new ArrayList<>();
- for (Karte karte : karten) {
- if (karte.getSymbol().equalsIgnoreCase(symbol)) {
- result.add(karte);
- }
- }
- return result;
- }
-
- public static List initializeSchafKopfCardDeck() {
- String[] farben = {"schell", "herz", "blatt", "eichel"};
- String[] symbole = {"6", "7", "8", "9", "u", "o", "k", "x", "a"};
-
- int totalCards = farben.length * symbole.length;
- List deck = new ArrayList<>();
-
- for (String farbe : farben) {
- for (String symbol : symbole) {
- String cardId = farbe + "_" + symbol;
- String cardName = getCardName(farbe, symbol);
- int wert = switch (symbol) {
- case "6", "9", "8", "7" -> 0;
- case "k" -> 4;
- case "x" -> 10;
- case "a" -> 11;
- case "u" -> 2;
- case "o" -> 3;
- default -> -1;
- };
- deck.add(new Karte(cardId, cardName, farbe, symbol, wert));
- }
- }
- deck.removeAll(KartenUtil.getKartenBySymbol(deck, "6"));
- return deck;
- }
-
- private static String getCardName(String farbe, String symbol) {
- String cardName = switch (farbe) {
- case "schell" -> "Schell";
- case "herz" -> "Herz";
- case "blatt" -> "Blatt";
- case "eichel" -> "Eichel";
- default -> "";
- };
- String prefix = switch (symbol) {
- case "6" -> "6";
- case "7" -> "7";
- case "8" -> "8";
- case "9" -> "9";
- case "k" -> "König";
- case "x" -> "10";
- case "a" -> "Ass";
- case "u" -> "Unter";
- case "o" -> "Ober";
- default -> "";
- };
- cardName += " " + prefix;
- return cardName;
- }
-
- public static String getIdOfUid(String uid){
- switch (uid){
- case "04A56BB4780000":
- return "eichel_7";
- case "04A46BB4780000":
- return "eichel_8";
- case "04A26BB4780000":
- return "eichel_9";
- case "04A16BB4780000":
- return "eichel_x";
- case "049E6BB4780000":
- return "eichel_k";
- case "04A86BB4780000":
- return "eichel_a";
- case "04A06BB4780000":
- return "eichel_u";
- case "049F6BB4780000":
- return "eichel_o";
-
- case "04F26BB4780000":
- return "blatt_7";
- case "04A76BB4780000":
- return "blatt_8";
- case "049B6BB4780000":
- return "blatt_9";
- case "04996BB4780000":
- return "blatt_x";
- case "041CD2C2126F81":
- return "blatt_k";
- case "04A96BB4780000":
- return "blatt_a";
- case "049A6BB4780000":
- return "blatt_u";
- case "049D6BB4780000":
- return "blatt_o";
-
- case "04936BB4780000":
- return "schell_7";
- case "04F697C2126F80":
- return "schell_8";
- case "04946BB4780000":
- return "schell_9";
- case "04956BB4780000":
- return "schell_x";
- case "04986BB4780000":
- return "schell_k";
- case "04AA6BB4780000":
- return "schell_a";
- case "04966BB4780000":
- return "schell_u";
- case "04976BB4780000":
- return "schell_o";
-
- case "04F36BB4780000":
- return "herz_7";
- case "04B06BB4780000":
- return "herz_8";
- case "04AF6BB4780000":
- return "herz_9";
- case "04AE6BB4780000":
- return "herz_x";
- case "04AB6BB4780000":
- return "herz_k";
- case "049C6BB4780000":
- return "herz_a";
- case "04AD6BB4780000":
- return "herz_u";
- case "04AC6BB4780000":
- return "herz_o";
- }
- return null;
- }
-
- public static Karte getKarteById(String id){
- List kartenList = initializeSchafKopfCardDeck();
- for (Karte karte : kartenList) {
- if (karte.getId().equalsIgnoreCase(id)) {
- return karte;
- }
- }
- return null;
- }
-
- public static void removeCards(List allCards, List cardsToRemove) {
- allCards.removeAll(cardsToRemove);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/org/example/Schafkopf.java b/src/main/java/org/example/Schafkopf.java
deleted file mode 100644
index e45da80..0000000
--- a/src/main/java/org/example/Schafkopf.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package org.example;
-
-import com.google.gson.Gson;
-import org.example.spielController.GeierSpielController;
-import org.example.spielController.SoloSpielController;
-import org.example.spielController.SpielController;
-import org.example.spielController.WenzSpielController;
-
-public class Schafkopf {
- private final Karte[] kartenDeck;
- private final SpielController spielController = new GeierSpielController( "schell");
- private final BackendServer server;
- private boolean gameState = false;
-
- Schafkopf(BackendServer server) {
- this.server = server;
- System.out.println("SchaffKopfGame erstellt");
- this.kartenDeck = initializeCardDeck();
- }
-
- private static String getCardName(String farbe, String symbol) {
- String cardName = switch (farbe) {
- case "schell" -> "Schell";
- case "herz" -> "Herz";
- case "blatt" -> "Blatt";
- case "eichel" -> "Eichel";
- default -> "";
- };
- String prefix = switch (symbol) {
- case "6" -> "6";
- case "7" -> "7";
- case "8" -> "8";
- case "9" -> "9";
- case "k" -> "König";
- case "x" -> "10";
- case "a" -> "Ass";
- case "u" -> "Unter";
- case "o" -> "Ober";
- default -> "";
- };
- cardName += " " + prefix;
- return cardName;
- }
-
- public Karte[] initializeCardDeck() {
- String[] farben = {"schell", "herz", "blatt", "eichel"};
- String[] symbole = {"6", "7", "8", "9", "k", "x", "a", "u", "o"};
-
- int totalCards = farben.length * symbole.length;
- Karte[] Deck = new Karte[totalCards];
-
- int index = 0;
-
- for (String farbe : farben) {
- for (String symbol : symbole) {
- String cardId = farbe + "_" + symbol;
- String cardName = getCardName(farbe, symbol);
- int wert = switch (symbol) {
- case "6", "9", "8", "7" -> 0;
- case "k" -> 4;
- case "x" -> 10;
- case "a" -> 11;
- case "u" -> 2;
- case "o" -> 3;
- default -> -1;
- };
- Deck[index] = new Karte(cardId, cardName, farbe, symbol, wert);
- index++;
- }
- }
- return Deck;
- }
-
- public void showTrumpf() {
-
- Gson gson = new Gson();
- for (Karte karte : spielController.getTrumpfKarten()) {
- String karteJson = gson.toJson(karte);
- server.sendMessageToAllFrontendEndpoints(karteJson);
- }
- }
-
- public void showFarbe() {
- Gson gson = new Gson();
- for (Karte karte : spielController.getFarbKarten()) {
- String karteJson = gson.toJson(karte);
- server.sendMessageToAllFrontendEndpoints(karteJson);
- }
- }
-
- public void startGame() {
- if (gameState) {
- System.out.println("Game already started!");
- server.sendMessageToAllFrontendEndpoints("Game already started!");
- } else {
- gameState = true;
- System.out.println("Start Game");
- server.sendMessageToAllFrontendEndpoints("Start Game");
- }
- }
-
- public void stopGame() {
- if (!gameState) {
- System.out.println("no active Game!");
- server.sendMessageToAllFrontendEndpoints("no active Game!");
- } else {
- gameState = false;
- System.out.println("Stop Game");
- server.sendMessageToAllFrontendEndpoints("Stop Game");
- }
-
- }
-}
diff --git a/src/main/java/org/example/spielController/GeierSpielController.java b/src/main/java/org/example/spielController/GeierSpielController.java
deleted file mode 100644
index 9cce335..0000000
--- a/src/main/java/org/example/spielController/GeierSpielController.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.example.spielController;
-
-import org.example.Karte;
-import org.example.KartenUtil;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class GeierSpielController extends SpielController {
- public GeierSpielController(String farbe) {
- List kartenList = KartenUtil.initializeSchafKopfCardDeck();
- List oberKarten = KartenUtil.getKartenBySymbol(kartenList, "o");
- List farbTrumpfKarten = KartenUtil.getKartenByFarbe(kartenList, farbe);
- farbTrumpfKarten.removeAll(KartenUtil.getKartenBySymbol(kartenList, "o"));
- farbTrumpfKarten.addAll(oberKarten);
- kartenList.removeAll(farbTrumpfKarten);
-
- this.trumpfKarten = new ArrayList<>(farbTrumpfKarten);
- this.farbKarten = new ArrayList<>(kartenList);
- }
-
- public GeierSpielController() {
- List kartenList = KartenUtil.initializeSchafKopfCardDeck();
- List oberKarten = KartenUtil.getKartenBySymbol(kartenList, "o");
-
- kartenList.removeAll(oberKarten);
-
- this.trumpfKarten = new ArrayList<>(oberKarten);
- this.farbKarten = new ArrayList<>(kartenList);
- }
-}
diff --git a/src/main/java/org/example/spielController/SauSpielController.java b/src/main/java/org/example/spielController/SauSpielController.java
deleted file mode 100644
index a63a43a..0000000
--- a/src/main/java/org/example/spielController/SauSpielController.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.example.spielController;
-import org.example.Karte;
-import org.example.KartenUtil;
-
-import java.util.List;
-import java.util.ArrayList;
-
-public class SauSpielController extends SpielController{
-
- public SauSpielController(){
- List kartenList = KartenUtil.initializeSchafKopfCardDeck();
- List herzKarten = KartenUtil.getKartenByFarbe(kartenList, "herz");
- herzKarten.removeAll(KartenUtil.getKartenBySymbol(kartenList, "u"));
- herzKarten.removeAll(KartenUtil.getKartenBySymbol(kartenList, "o"));
-
- herzKarten.addAll(KartenUtil.getKartenBySymbol(kartenList, "u"));
- herzKarten.addAll(KartenUtil.getKartenBySymbol(kartenList, "o"));
-
- kartenList.removeAll(herzKarten);
-
- this.trumpfKarten = new ArrayList<>(herzKarten);
- this.farbKarten = new ArrayList<>(kartenList);
- }
-}
diff --git a/src/main/java/org/example/spielController/SoloSpielController.java b/src/main/java/org/example/spielController/SoloSpielController.java
deleted file mode 100644
index c98a4bf..0000000
--- a/src/main/java/org/example/spielController/SoloSpielController.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.example.spielController;
-
-import org.example.Karte;
-import org.example.KartenUtil;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SoloSpielController extends SpielController {
- public SoloSpielController(String farbe) {
- List kartenList = KartenUtil.initializeSchafKopfCardDeck();
- List unterKarten = KartenUtil.getKartenBySymbol(kartenList, "u");
-
- List farbTrumpfKarten = KartenUtil.getKartenByFarbe(kartenList, farbe);
- farbTrumpfKarten.removeAll(KartenUtil.getKartenBySymbol(kartenList, "u"));
- farbTrumpfKarten.removeAll(KartenUtil.getKartenBySymbol(kartenList, "o"));
- farbTrumpfKarten.addAll(KartenUtil.getKartenBySymbol(kartenList, "u"));
- farbTrumpfKarten.addAll(KartenUtil.getKartenBySymbol(kartenList, "o"));
-
-
-
-
-
-
- kartenList.removeAll(farbTrumpfKarten);
-
- this.trumpfKarten = new ArrayList<>(farbTrumpfKarten);
- this.farbKarten = new ArrayList<>(kartenList);
- }
-}
diff --git a/src/main/java/org/example/spielController/SpielController.java b/src/main/java/org/example/spielController/SpielController.java
deleted file mode 100644
index 263f745..0000000
--- a/src/main/java/org/example/spielController/SpielController.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.example.spielController;
-
-import org.example.Karte;
-
-import java.util.List;
-
-public abstract class SpielController {
- protected List trumpfKarten;
- protected List farbKarten;
-
-
-
- public List getTrumpfKarten() {
- return trumpfKarten;
- }
-
- public List getFarbKarten() {
- return farbKarten;
- }
-}
diff --git a/src/main/java/org/example/spielController/WenzSpielController.java b/src/main/java/org/example/spielController/WenzSpielController.java
deleted file mode 100644
index 73989e9..0000000
--- a/src/main/java/org/example/spielController/WenzSpielController.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.example.spielController;
-
-import org.example.Karte;
-import org.example.KartenUtil;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class WenzSpielController extends SpielController {
- public WenzSpielController(String farbe) {
- List kartenList = KartenUtil.initializeSchafKopfCardDeck();
- List unterKarten = KartenUtil.getKartenBySymbol(kartenList, "u");
- List farbTrumpfKarten = KartenUtil.getKartenByFarbe(kartenList, farbe);
- farbTrumpfKarten.removeAll(KartenUtil.getKartenBySymbol(kartenList, "u"));
- farbTrumpfKarten.addAll(unterKarten);
- kartenList.removeAll(farbTrumpfKarten);
-
- this.trumpfKarten = new ArrayList<>(farbTrumpfKarten);
- this.farbKarten = new ArrayList<>(kartenList);
- }
-
- public WenzSpielController() {
- List kartenList = KartenUtil.initializeSchafKopfCardDeck();
- List unterKarten = KartenUtil.getKartenBySymbol(kartenList, "u");
-
- kartenList.removeAll(unterKarten);
-
- this.trumpfKarten = new ArrayList<>(unterKarten);
- this.farbKarten = new ArrayList<>(kartenList);
- }
-}
diff --git a/src/main/java/org/schafkopf/BackendServer.java b/src/main/java/org/schafkopf/BackendServer.java
new file mode 100644
index 0000000..2b3e217
--- /dev/null
+++ b/src/main/java/org/schafkopf/BackendServer.java
@@ -0,0 +1,183 @@
+package org.schafkopf;
+
+import com.google.gson.JsonObject;
+import io.github.cdimascio.dotenv.Dotenv;
+import jakarta.servlet.DispatcherType;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlets.CrossOriginFilter;
+import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
+
+/** Main Class that represents the Backend Server. */
+public class BackendServer {
+ private final Server server;
+ private final ServerConnector connector;
+ private final Schafkopf schafkopfGame;
+ private final KartenLeser nfcLeser;
+ private final List frontendEndpoints = new ArrayList<>();
+ private CountDownLatch nfcLatch = new CountDownLatch(1);
+ private Boolean readingMode = false;
+ private String uidString = "";
+
+ /** Creates an Instance of the Backend Server. */
+ public BackendServer() {
+ Dotenv dotenv = Dotenv.configure().directory("./").load();
+ server = new Server();
+ InetSocketAddress address = new InetSocketAddress(dotenv.get("VITE_APP_WEBSOCKET_IP"), 8080);
+ connector = new ServerConnector(server);
+ connector.setHost(address.getHostName());
+ connector.setPort(address.getPort());
+ server.addConnector(connector);
+
+ schafkopfGame = new Schafkopf(this);
+ nfcLeser = new KartenLeser(this);
+
+ // Setup the basic application "context" for this application at "/"
+ // This is also known as the handler tree (in jetty speak)
+ ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
+ context.setContextPath("/");
+ server.setHandler(context);
+
+ // Configure CORS settings
+ configureCors(context);
+
+ // Configure specific websocket behavior
+ JettyWebSocketServletContainerInitializer.configure(
+ context,
+ (servletContext, wsContainer) -> {
+ // Configure default max size
+ wsContainer.setMaxTextMessageSize(65535);
+ wsContainer.setIdleTimeout(Duration.ofDays(300000));
+ // Add websockets
+ wsContainer.addMapping("/schafkopf-events/*", new FrontendEndpointCreator(this));
+ });
+ }
+
+ /** The main entrypoint of the Application. */
+ public static void main(String[] args) throws Exception {
+ BackendServer server = new BackendServer();
+ server.setPort(8080);
+ server.start();
+ server.join();
+ }
+
+ private void configureCors(ServletContextHandler context) {
+ // Enable CORS for all paths
+ FilterHolder cors = context.addFilter(CrossOriginFilter.class, "/*", null);
+
+ // Configure allowed origins, headers, and methods
+ cors.setInitParameter("allowedOrigins", "*");
+ cors.setInitParameter("allowedHeaders", "X-Requested-With,Content-Type,Accept,Origin");
+ cors.setInitParameter("allowedMethods", "GET,POST,PUT,DELETE,OPTIONS");
+
+ // Add filter mappings
+ EnumSet types = EnumSet.of(DispatcherType.REQUEST);
+ context.addFilter(cors, "*", types);
+ }
+
+ public void setPort(int port) {
+ connector.setPort(port);
+ }
+
+ public void start() throws Exception {
+ server.start();
+ }
+
+ public URI getUri() {
+ return server.getURI();
+ }
+
+ public void stop() throws Exception {
+ server.stop();
+ }
+
+ public void join() throws InterruptedException {
+ server.join();
+ }
+
+ public void addFrontendEndpoint(FrontendEndpoint endpoint) {
+ frontendEndpoints.add(endpoint);
+ }
+
+ public void removeFrontendEndpoint(FrontendEndpoint endpoint) {
+ frontendEndpoints.remove(endpoint);
+ }
+
+ /**
+ * Sends Message to all Frontend Instances.
+ *
+ * @param message Message to send (String).
+ */
+ public void sendMessageToAllFrontendEndpoints(String message) {
+ for (FrontendEndpoint endpoint : frontendEndpoints) {
+ endpoint.sendMessage(message);
+ }
+ }
+
+ /**
+ * Sends Message to all Frontend Instances.
+ *
+ * @param message Message to send (JsonObject).
+ */
+ public void sendMessageToAllFrontendEndpoints(JsonObject message) {
+ for (FrontendEndpoint endpoint : frontendEndpoints) {
+ endpoint.sendMessage(message.toString());
+ }
+ }
+
+ public void startSchafkopfGame() {
+ schafkopfGame.startGame();
+ }
+
+ public void stopSchafkopfGame() {
+ schafkopfGame.stopGame();
+ }
+
+ public void showTrumpf() {
+ schafkopfGame.showTrumpf();
+ }
+
+ public void showFarbe() {
+ schafkopfGame.showFarbe();
+ }
+
+ public void setGame(String message) {
+ schafkopfGame.setGame(message);
+ }
+
+ /**
+ * checks uid of scanned card and do nothing if Server is not in reading mode.
+ *
+ * @param uidString uid to check.
+ */
+ public void nfcGelesen(String uidString) {
+ if (this.uidString.equals(uidString)) {
+ return;
+ }
+ if (!this.readingMode) {
+ return;
+ }
+
+ this.uidString = uidString;
+ nfcLatch.countDown();
+ }
+
+ /** method to call to wait for NFC input. */
+ public String waitForCardScan() throws InterruptedException {
+ this.readingMode = true;
+ nfcLatch.await();
+ Thread.sleep(20);
+ this.readingMode = false;
+ nfcLatch = new CountDownLatch(1);
+ return this.uidString;
+ }
+}
diff --git a/src/main/java/org/schafkopf/FrontendEndpoint.java b/src/main/java/org/schafkopf/FrontendEndpoint.java
new file mode 100644
index 0000000..03eaf96
--- /dev/null
+++ b/src/main/java/org/schafkopf/FrontendEndpoint.java
@@ -0,0 +1,77 @@
+package org.schafkopf;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketAdapter;
+
+/** Class that represents one Frontend Connection. */
+public class FrontendEndpoint extends WebSocketAdapter {
+ private final CountDownLatch closureLatch = new CountDownLatch(1);
+ private BackendServer backendServer;
+
+ public FrontendEndpoint(BackendServer backendServer) {
+ this.backendServer = backendServer;
+ System.out.println("new FrontendEndpoint");
+ }
+
+ @Override
+ public void onWebSocketConnect(Session session) {
+ super.onWebSocketConnect(session);
+ String clientIp = session.getRemoteAddress().toString();
+ System.out.println("Endpoint connected from ip: " + clientIp);
+
+ backendServer.addFrontendEndpoint(this);
+ }
+
+ @Override
+ public void onWebSocketText(String message) {
+ super.onWebSocketText(message);
+ System.out.println("Received TEXT message:" + message);
+
+ if (message.contains("startsimulation")) {
+ backendServer.startSchafkopfGame();
+ }
+
+ if (message.contains("stopsimulation")) {
+ backendServer.stopSchafkopfGame();
+ }
+
+ if (message.contains("showtrumpf")) {
+ backendServer.showTrumpf();
+ }
+
+ if (message.contains("showfarben")) {
+ backendServer.showFarbe();
+ }
+
+ if (message.contains("setgame")) {
+ backendServer.setGame(message);
+ }
+ }
+
+ @Override
+ public void onWebSocketClose(int statusCode, String reason) {
+ super.onWebSocketClose(statusCode, reason);
+
+ backendServer.removeFrontendEndpoint(this);
+
+ System.out.println("Socket Closed: [" + statusCode + "] " + reason);
+ closureLatch.countDown();
+ }
+
+ @Override
+ public void onWebSocketError(Throwable cause) {
+ super.onWebSocketError(cause);
+ cause.printStackTrace(System.err);
+ }
+
+ /** send a Message to the connected FrontEnd. */
+ public void sendMessage(String message) {
+ try {
+ getRemote().sendString(message);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/org/schafkopf/FrontendEndpointCreator.java b/src/main/java/org/schafkopf/FrontendEndpointCreator.java
new file mode 100644
index 0000000..d5538ce
--- /dev/null
+++ b/src/main/java/org/schafkopf/FrontendEndpointCreator.java
@@ -0,0 +1,23 @@
+package org.schafkopf;
+
+import org.eclipse.jetty.websocket.server.JettyServerUpgradeRequest;
+import org.eclipse.jetty.websocket.server.JettyServerUpgradeResponse;
+import org.eclipse.jetty.websocket.server.JettyWebSocketCreator;
+
+/**
+ * Creater to make new Instances of the FrontendConnection.
+ */
+public class FrontendEndpointCreator implements JettyWebSocketCreator {
+ private BackendServer backendServer;
+
+ public FrontendEndpointCreator(BackendServer backendServer) {
+ this.backendServer = backendServer;
+ }
+
+ @Override
+ public Object createWebSocket(
+ JettyServerUpgradeRequest jettyServerUpgradeRequest,
+ JettyServerUpgradeResponse jettyServerUpgradeResponse) {
+ return new FrontendEndpoint(this.backendServer);
+ }
+}
diff --git a/src/main/java/org/schafkopf/KartenLeser.java b/src/main/java/org/schafkopf/KartenLeser.java
new file mode 100644
index 0000000..3de38ff
--- /dev/null
+++ b/src/main/java/org/schafkopf/KartenLeser.java
@@ -0,0 +1,73 @@
+package org.schafkopf;
+
+import com.pi4j.io.i2c.I2C;
+import java.io.IOException;
+import mk.hsilomedus.pn532.Pn532ContextHelper;
+import mk.hsilomedus.pn532.Pn532I2c;
+import mk.hsilomedus.pn532.Pn532SamThread;
+import mk.hsilomedus.pn532.Pn532SamThread.Pn532SamThreadListener;
+
+/**
+ * Class that represents the NFC Reader.
+ */
+public final class KartenLeser {
+
+ private static BackendServer server;
+
+ /**
+ * Creates an Instance of the KartenLeser.
+ *
+ * @param server Backend Server to call methods on.
+ */
+ public KartenLeser(BackendServer server) {
+ this.server = server;
+
+ new Thread(
+ () -> {
+ new KartenListener().run();
+ })
+ .start();
+ }
+
+ public static final void main(String[] args) throws IOException {}
+
+ private static class KartenListener implements Pn532SamThreadListener {
+
+ @SuppressWarnings("rawtypes")
+ Pn532SamThread i2cThread = new Pn532SamThread<>(this, new Pn532I2c());
+
+ public void run() {
+ Pn532ContextHelper.initialize();
+ i2cThread.start();
+ }
+
+ public void close() {
+ closeThread(i2cThread);
+ Pn532ContextHelper.shutdown();
+ }
+
+ @Override
+ public void receiveMessage(String message) {
+ System.out.println(message);
+ }
+
+ @Override
+ public void uidReceived(String displayName, byte[] uid) {
+ server.nfcGelesen(Pn532SamThreadListener.getUidString(uid));
+ }
+
+ @SuppressWarnings("rawtypes")
+ private void closeThread(Pn532SamThread thread) {
+ if (thread != null && thread.isAlive()) {
+ thread.close();
+
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ System.out.println("Error closing thread: " + e.getMessage());
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/schafkopf/Schafkopf.java b/src/main/java/org/schafkopf/Schafkopf.java
new file mode 100644
index 0000000..8026e32
--- /dev/null
+++ b/src/main/java/org/schafkopf/Schafkopf.java
@@ -0,0 +1,194 @@
+package org.schafkopf;
+
+import org.schafkopf.karte.Karte;
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenUtil;
+import org.schafkopf.player.BotPlayer;
+import org.schafkopf.player.LocalPlayer;
+import org.schafkopf.player.Player;
+import org.schafkopf.spielcontroller.FarbGeierController;
+import org.schafkopf.spielcontroller.FarbSoloController;
+import org.schafkopf.spielcontroller.FarbWenzController;
+import org.schafkopf.spielcontroller.GeierController;
+import org.schafkopf.spielcontroller.SauSpielController;
+import org.schafkopf.spielcontroller.SpielController;
+import org.schafkopf.spielcontroller.WenzController;
+
+/** The main class representing the Schafkopf game. */
+public class Schafkopf {
+ private final BackendServer server;
+
+ /** The game controller. This is the class that implements the game logic. */
+ private SpielController spiel = new SauSpielController(0, KartenFarbe.EICHEL);
+
+ private final Player[] player = {
+ new BotPlayer(), new LocalPlayer(this), new LocalPlayer(this), new LocalPlayer(this)
+ };
+
+ private boolean gameState = false;
+ private Thread spielThread;
+
+ public Player[] getPlayer() {
+ return player;
+ }
+
+ /**
+ * Constructor for the Schafkopf class.
+ *
+ * @param server The backend server associated with the game.
+ */
+ Schafkopf(BackendServer server) {
+ this.server = server;
+ System.out.println("SchaffKopfGame erstellt");
+ }
+
+ /** Sends all Trumpf Karten of the current GameType to the Frontend. */
+ public void showTrumpf() {
+ server.sendMessageToAllFrontendEndpoints(spiel.getTrumpfKarten().getJson());
+ }
+
+ /** Sends all Farb Karten of the current GameType to the Frontend. */
+ public void showFarbe() {
+ server.sendMessageToAllFrontendEndpoints(spiel.getFarbKarten().getJson());
+ }
+
+ /** Waits for a Card and returns a Karte Object. */
+ public Karte wartetAufKarte() {
+ String uid = null;
+ System.out.println("Starte Warten auf Karte");
+ try {
+ uid = server.waitForCardScan();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+
+ Karte karte = KartenUtil.getIdOfUid(uid);
+
+ if (karte == null) {
+ System.out.println("Ungültige Karte");
+ return wartetAufKarte();
+ }
+ server.sendMessageToAllFrontendEndpoints(karte.getJson());
+ System.out.println("Karte gescannt: " + karte.getName());
+ System.out.println("Beende Warten auf Karte");
+ return karte;
+ }
+
+ /** Set GameState to "started" and start Game Thread. */
+ public void startGame() {
+ if (gameState) {
+ System.out.println("Game already started!");
+ server.sendMessageToAllFrontendEndpoints("Game already started!");
+ } else {
+ gameState = true;
+ System.out.println("Start Game");
+
+ // KartenListe botHand = KartenUtil.zieheZufallsHand(8);
+ KartenListe botHand = new KartenListe();
+ botHand.addKarten(Karte.EICHEL_7);
+ botHand.addKarten(Karte.EICHEL_8);
+ botHand.addKarten(Karte.EICHEL_9);
+ botHand.addKarten(Karte.EICHEL_K);
+
+ botHand.addKarten(Karte.EICHEL_X);
+ botHand.addKarten(Karte.EICHEL_A);
+ botHand.addKarten(Karte.EICHEL_U);
+ botHand.addKarten(Karte.EICHEL_O);
+ for (Player currentPlayer : player) {
+ if (currentPlayer instanceof BotPlayer botPlayer) {
+ // Perform actions specific to BotPlayer
+ botPlayer.setCards(botHand); // Replace with the actual method you want to call
+ }
+ }
+
+ server.sendMessageToAllFrontendEndpoints("Start Game");
+ server.sendMessageToAllFrontendEndpoints(botHand.getJson());
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ spielThread = new Thread(() -> new Spielablauf(this, spiel));
+
+ spielThread.start();
+ }
+ }
+
+ /** Set GameState to "stopped" and interrupt Game Thread. */
+ public void stopGame() {
+ if (!gameState) {
+ System.out.println("no active Game!");
+ server.sendMessageToAllFrontendEndpoints("no active Game!");
+ } else {
+ gameState = false;
+ System.out.println("Stop Game");
+ server.sendMessageToAllFrontendEndpoints("Stop Game");
+ }
+
+ spielThread.interrupt();
+ }
+
+ /** Set GameType. */
+ public void setGame(String message) {
+ System.out.println("Set Game: " + message);
+ server.sendMessageToAllFrontendEndpoints("Set Game: " + message);
+ switch (message) {
+ case "setgame:herzsolo":
+ this.spiel = new FarbSoloController(0, KartenFarbe.HERZ);
+ break;
+ case "setgame:blattsolo":
+ this.spiel = new FarbSoloController(0, KartenFarbe.BLATT);
+ break;
+ case "setgame:eichelsolo":
+ this.spiel = new FarbSoloController(0, KartenFarbe.EICHEL);
+ break;
+ case "setgame:schellsolo":
+ this.spiel = new FarbSoloController(0, KartenFarbe.SCHELL);
+ break;
+
+ case "setgame:wenz":
+ this.spiel = new WenzController(0);
+ break;
+ case "setgame:geier":
+ this.spiel = new GeierController(0);
+ break;
+
+ case "setgame:eichelwenz":
+ this.spiel = new FarbWenzController(0, KartenFarbe.EICHEL);
+ break;
+ case "setgame:herzwenz":
+ this.spiel = new FarbWenzController(0, KartenFarbe.HERZ);
+ break;
+ case "setgame:blattwenz":
+ this.spiel = new FarbWenzController(0, KartenFarbe.BLATT);
+ break;
+ case "setgame:schellwenz":
+ this.spiel = new FarbWenzController(0, KartenFarbe.SCHELL);
+ break;
+
+ case "setgame:eichelgeier":
+ this.spiel = new FarbGeierController(0, KartenFarbe.EICHEL);
+ break;
+ case "setgame:herzgeier":
+ this.spiel = new FarbGeierController(0, KartenFarbe.HERZ);
+ break;
+ case "setgame:blattgeier":
+ this.spiel = new FarbGeierController(0, KartenFarbe.BLATT);
+ break;
+ case "setgame:schellgeier":
+ this.spiel = new FarbGeierController(0, KartenFarbe.SCHELL);
+ break;
+
+ case "setgame:sauspiel":
+ this.spiel = new SauSpielController(0, KartenFarbe.EICHEL);
+ break;
+ default:
+ System.out.println("Ungültiges Spiel");
+ }
+ }
+
+ public BackendServer getServer() {
+ return this.server;
+ }
+}
diff --git a/src/main/java/org/schafkopf/Spielablauf.java b/src/main/java/org/schafkopf/Spielablauf.java
new file mode 100644
index 0000000..677c653
--- /dev/null
+++ b/src/main/java/org/schafkopf/Spielablauf.java
@@ -0,0 +1,75 @@
+package org.schafkopf;
+
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.player.Player;
+import org.schafkopf.spielcontroller.SpielController;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** The main class that controlls the game flow. */
+public class Spielablauf {
+
+ private static final Logger logger = LoggerFactory.getLogger(Spielablauf.class);
+ private final KartenListe gespielteKarten;
+
+ private final KartenListe tischKarten = new KartenListe();
+
+ private final SpielController spiel;
+
+ private final Player[] players;
+
+ private final Schafkopf schafkopf;
+
+ private int gemachteStiche;
+
+ Spielablauf(Schafkopf schafkopf, SpielController spiel) {
+ this.schafkopf = schafkopf;
+ this.spiel = spiel;
+ this.players = schafkopf.getPlayer();
+ gespielteKarten = new KartenListe();
+ gemachteStiche = 0;
+ try {
+ einStich();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Method to Handle flow of one Game. */
+ public void einStich() throws InterruptedException {
+ logger.info("Starte Stiche");
+ int rauskommer = 0;
+ while (gemachteStiche < 8) {
+ schafkopf.getServer().sendMessageToAllFrontendEndpoints(gespielteKarten.getJson());
+ logger.info("Stich: {}", gemachteStiche);
+ for (int i = 0; i < 4; i++) {
+ schafkopf.getServer().sendMessageToAllFrontendEndpoints(tischKarten.getJson());
+ int nextPlayer = (i + rauskommer) % 4;
+
+ logger.info("Spieler ist dran: {}", nextPlayer);
+
+ tischKarten.addKarten(players[nextPlayer].play(spiel, tischKarten));
+ schafkopf.getServer().sendMessageToAllFrontendEndpoints(tischKarten.getJson());
+ }
+ schafkopf.getServer().sendMessageToAllFrontendEndpoints(tischKarten.getJson());
+ int stichSpieler = SpielController.welcheKarteSticht(tischKarten);
+
+
+
+ Thread.sleep(2000);
+ logger.info("Stiche ende");
+
+ rauskommer = (rauskommer + stichSpieler) % 4;
+ logger.warn("Karte sticht: {}", rauskommer);
+ //rauskommer = 0;
+
+ gespielteKarten.addKarten(tischKarten);
+
+ tischKarten.clear();
+
+ gemachteStiche++;
+ }
+ schafkopf.getServer().sendMessageToAllFrontendEndpoints(gespielteKarten.getJson());
+ schafkopf.stopGame();
+ }
+}
diff --git a/src/main/java/org/schafkopf/karte/Karte.java b/src/main/java/org/schafkopf/karte/Karte.java
new file mode 100644
index 0000000..ef93bdf
--- /dev/null
+++ b/src/main/java/org/schafkopf/karte/Karte.java
@@ -0,0 +1,85 @@
+package org.schafkopf.karte;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+/** enum to represent all cards in the game. */
+public enum Karte {
+ EICHEL_7(KartenFarbe.EICHEL, KartenSymbol.SEVEN),
+ EICHEL_8(KartenFarbe.EICHEL, KartenSymbol.EIGHT),
+ EICHEL_9(KartenFarbe.EICHEL, KartenSymbol.NINE),
+ EICHEL_X(KartenFarbe.EICHEL, KartenSymbol.TEN),
+ EICHEL_K(KartenFarbe.EICHEL, KartenSymbol.KOENIG),
+ EICHEL_A(KartenFarbe.EICHEL, KartenSymbol.ASS),
+ EICHEL_U(KartenFarbe.EICHEL, KartenSymbol.UNTER),
+ EICHEL_O(KartenFarbe.EICHEL, KartenSymbol.OBER),
+ BLATT_7(KartenFarbe.BLATT, KartenSymbol.SEVEN),
+ BLATT_8(KartenFarbe.BLATT, KartenSymbol.EIGHT),
+ BLATT_9(KartenFarbe.BLATT, KartenSymbol.NINE),
+ BLATT_X(KartenFarbe.BLATT, KartenSymbol.TEN),
+ BLATT_K(KartenFarbe.BLATT, KartenSymbol.KOENIG),
+ BLATT_A(KartenFarbe.BLATT, KartenSymbol.ASS),
+ BLATT_U(KartenFarbe.BLATT, KartenSymbol.UNTER),
+ BLATT_O(KartenFarbe.BLATT, KartenSymbol.OBER),
+ SCHELL_7(KartenFarbe.SCHELL, KartenSymbol.SEVEN),
+ SCHELL_8(KartenFarbe.SCHELL, KartenSymbol.EIGHT),
+ SCHELL_9(KartenFarbe.SCHELL, KartenSymbol.NINE),
+ SCHELL_X(KartenFarbe.SCHELL, KartenSymbol.TEN),
+ SCHELL_K(KartenFarbe.SCHELL, KartenSymbol.KOENIG),
+ SCHELL_A(KartenFarbe.SCHELL, KartenSymbol.ASS),
+ SCHELL_U(KartenFarbe.SCHELL, KartenSymbol.UNTER),
+ SCHELL_O(KartenFarbe.SCHELL, KartenSymbol.OBER),
+ HERZ_7(KartenFarbe.HERZ, KartenSymbol.SEVEN),
+ HERZ_8(KartenFarbe.HERZ, KartenSymbol.EIGHT),
+ HERZ_9(KartenFarbe.HERZ, KartenSymbol.NINE),
+ HERZ_X(KartenFarbe.HERZ, KartenSymbol.TEN),
+ HERZ_K(KartenFarbe.HERZ, KartenSymbol.KOENIG),
+ HERZ_A(KartenFarbe.HERZ, KartenSymbol.ASS),
+ HERZ_U(KartenFarbe.HERZ, KartenSymbol.UNTER),
+ HERZ_O(KartenFarbe.HERZ, KartenSymbol.OBER);
+
+ private final String id;
+ private final KartenFarbe farbe;
+ private final KartenSymbol symbol;
+
+ private final String displayName;
+
+ private final int punkte;
+
+ Karte(KartenFarbe farbe, KartenSymbol symbol) {
+ this.farbe = farbe;
+ this.symbol = symbol;
+ this.id = this.name().toLowerCase();
+ this.displayName = farbe.getDisplayName() + " " + symbol.getDisplayName();
+ this.punkte = symbol.getValue();
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public String getName() {
+ return this.displayName;
+ }
+
+ public KartenFarbe getFarbe() {
+ return this.farbe;
+ }
+
+ public KartenSymbol getSymbol() {
+ return this.symbol;
+ }
+
+ public int getPunkte() {
+ return this.punkte;
+ }
+
+ /** get the Card as a Json Object. */
+ public JsonObject getJson() {
+ Gson gson = new Gson();
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.add("card", gson.toJsonTree(this));
+
+ return jsonObject;
+ }
+}
diff --git a/src/main/java/org/schafkopf/karte/KartenFarbe.java b/src/main/java/org/schafkopf/karte/KartenFarbe.java
new file mode 100644
index 0000000..cfd7e84
--- /dev/null
+++ b/src/main/java/org/schafkopf/karte/KartenFarbe.java
@@ -0,0 +1,21 @@
+package org.schafkopf.karte;
+
+/**
+ * Enum for all possible Card Colors.
+ */
+public enum KartenFarbe {
+ EICHEL("Eichel"),
+ BLATT("Blatt"),
+ HERZ("Herz"),
+ SCHELL("Schell");
+
+ private final String displayName;
+
+ KartenFarbe(String displayName) {
+ this.displayName = displayName;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+}
diff --git a/src/main/java/org/schafkopf/karte/KartenListe.java b/src/main/java/org/schafkopf/karte/KartenListe.java
new file mode 100644
index 0000000..ba5008d
--- /dev/null
+++ b/src/main/java/org/schafkopf/karte/KartenListe.java
@@ -0,0 +1,203 @@
+package org.schafkopf.karte;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A Class that represents a list of Cards.
+ */
+public class KartenListe {
+ private List kartenListe;
+
+ public KartenListe() {
+ this.kartenListe = new ArrayList<>();
+ }
+
+ public KartenListe(KartenListe liste) {
+ this.kartenListe = new ArrayList<>(liste.getKartenListe());
+ }
+
+ public List getKartenListe() {
+ return this.kartenListe;
+ }
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public void addKarten(Karte karte) {
+ if (!this.containsKarte(karte)) {
+ this.kartenListe.add(karte);
+ return;
+ }
+ throw new RuntimeException("Karte bereits vorhanden: " + karte.getName());
+ }
+
+ // methoden zum hinzufügen von karten
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public void addKarten(KartenListe karten) {
+ for (Karte karte : karten.getKartenListe()) {
+ this.addKarten(karte);
+ }
+ }
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public KartenListe removeKarten(KartenListe karten) {
+ KartenListe result = new KartenListe();
+ for (Karte karteWeg : karten.getKartenListe()) {
+ for (Karte karte : this.kartenListe) {
+ if (karte.getId().equals(karteWeg.getId())) {
+ result.addKarten(karte);
+ break;
+ }
+ }
+ }
+ this.kartenListe.removeAll(result.getKartenListe());
+ return result;
+ }
+
+ // methoden zum entfernen von karten
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public KartenListe removeKarten(KartenFarbe farbe) {
+ KartenListe result = new KartenListe();
+ for (Karte karte : this.kartenListe) {
+ if (karte.getFarbe().equals(farbe)) {
+ result.addKarten(karte);
+ }
+ }
+ this.kartenListe.removeAll(result.getKartenListe());
+ return result;
+ }
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public KartenListe removeKarten(KartenSymbol symbol) {
+ KartenListe result = new KartenListe();
+ for (Karte karte : this.kartenListe) {
+ if (karte.getSymbol().equals(symbol)) {
+ result.addKarten(karte);
+ }
+ }
+ this.kartenListe.removeAll(result.getKartenListe());
+ return result;
+ }
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public Karte removeKarten(Karte karteToRemove) {
+ for (Karte karte : this.kartenListe) {
+ if (karte.getId().equals(karteToRemove.getId())) {
+ this.kartenListe.remove(karte);
+ return karte;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public Karte removeKarten(String idToRemove) {
+ for (Karte karte : this.kartenListe) {
+ if (karte.getId().equals(idToRemove)) {
+ this.kartenListe.remove(karte);
+ return karte;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ private boolean containsKarte(Karte karte) {
+ for (Karte karteInListe : this.kartenListe) {
+ if (karteInListe.getId().equals(karte.getId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // get Karten
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public KartenListe getKarten(KartenFarbe farbe) {
+ KartenListe result = new KartenListe();
+ for (Karte karte : this.kartenListe) {
+ if (karte.getFarbe().equals(farbe)) {
+ result.addKarten(karte);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public KartenListe getKarten(KartenSymbol symbol) {
+ KartenListe result = new KartenListe();
+ for (Karte karte : this.kartenListe) {
+ if (karte.getSymbol().equals(symbol)) {
+ result.addKarten(karte);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public JsonObject getJson() {
+ Gson gson = new Gson();
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.add("cards", gson.toJsonTree(this.kartenListe));
+
+ return jsonObject;
+ }
+
+ public boolean isEmpty() {
+ return this.kartenListe.isEmpty();
+ }
+
+ public Karte getLast() {
+ return this.kartenListe.getLast();
+ }
+
+ public Karte getByIndex(int index) {
+ return this.kartenListe.get(index);
+ }
+
+ public int size() {
+ return this.kartenListe.size();
+ }
+
+ /**
+ * A Class that represents a list of Cards.
+ */
+ public int indexOf(Karte karte) {
+ for (Karte karteInListe : this.kartenListe) {
+ if (karteInListe.getId().equals(karte.getId())) {
+ return this.kartenListe.indexOf(karteInListe);
+ }
+ }
+ return -1;
+ }
+
+ public void clear() {
+ this.kartenListe.clear();
+ }
+}
diff --git a/src/main/java/org/schafkopf/karte/KartenSymbol.java b/src/main/java/org/schafkopf/karte/KartenSymbol.java
new file mode 100644
index 0000000..b8e2c91
--- /dev/null
+++ b/src/main/java/org/schafkopf/karte/KartenSymbol.java
@@ -0,0 +1,38 @@
+package org.schafkopf.karte;
+
+/**
+ * Enum for all possible Card Symbols.
+ */
+public enum KartenSymbol {
+ SIX("6", "6", 0),
+ SEVEN("7", "7", 0),
+ EIGHT("8", "8", 0),
+ NINE("9", "9", 0),
+ UNTER("u", "Unter", 2),
+ OBER("o", "Ober", 3),
+ KOENIG("k", "König", 4),
+ TEN("x", "10", 10),
+ ASS("a", "Ass", 11);
+
+ private final String displayName;
+ private final String id;
+ private final int value;
+
+ KartenSymbol(String id, String displayName, int value) {
+ this.displayName = displayName;
+ this.value = value;
+ this.id = id;
+ }
+
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public String getId() {
+ return id;
+ }
+}
diff --git a/src/main/java/org/schafkopf/karte/KartenUtil.java b/src/main/java/org/schafkopf/karte/KartenUtil.java
new file mode 100644
index 0000000..b92080d
--- /dev/null
+++ b/src/main/java/org/schafkopf/karte/KartenUtil.java
@@ -0,0 +1,82 @@
+package org.schafkopf.karte;
+
+import java.util.Random;
+
+/** Class that brings usefully functions for Card/s. */
+public class KartenUtil {
+
+ /** initialize a normal Card Deck. It will be in the standard order. */
+ public static KartenListe initializeSchafKopfCardDeck() {
+ KartenListe deck = new KartenListe();
+
+ for (Karte karte : Karte.values()) {
+ deck.addKarten(karte);
+ }
+
+ deck.removeKarten(KartenSymbol.SIX);
+ return deck;
+ }
+
+ /**
+ * Create a List of Random Cards.
+ *
+ * @param anzahl count of random cards.
+ */
+ public static KartenListe zieheZufallsHand(int anzahl) {
+ KartenListe karten = initializeSchafKopfCardDeck();
+ KartenListe gezogeneKarten = new KartenListe();
+ Random random = new Random();
+
+ // Ziehe zufällige Karten
+ for (int i = 0; i < anzahl; i++) {
+ int zufallsIndex = random.nextInt(karten.size());
+ Karte gezogeneKarte = karten.getByIndex(zufallsIndex);
+ gezogeneKarten.addKarten(gezogeneKarte);
+ karten.removeKarten(gezogeneKarte);
+ }
+ return gezogeneKarten;
+ }
+
+ /**
+ * converts Uid from a NFC Card to a card ID.
+ *
+ * @param uid uId to get the Card ID from.
+ */
+ public static Karte getIdOfUid(String uid) {
+ return switch (uid) {
+ case "04A56BB4780000" -> Karte.EICHEL_7;
+ case "04A46BB4780000" -> Karte.EICHEL_8;
+ case "04A26BB4780000" -> Karte.EICHEL_9;
+ case "04A16BB4780000" -> Karte.EICHEL_X;
+ case "049E6BB4780000" -> Karte.EICHEL_K;
+ case "04A86BB4780000" -> Karte.EICHEL_A;
+ case "04A06BB4780000" -> Karte.EICHEL_U;
+ case "049F6BB4780000" -> Karte.EICHEL_O;
+ case "04F26BB4780000" -> Karte.BLATT_7;
+ case "04A76BB4780000" -> Karte.BLATT_8;
+ case "049B6BB4780000" -> Karte.BLATT_9;
+ case "04996BB4780000" -> Karte.BLATT_X;
+ case "041CD2C2126F81" -> Karte.BLATT_K;
+ case "04A96BB4780000" -> Karte.BLATT_A;
+ case "049A6BB4780000" -> Karte.BLATT_U;
+ case "049D6BB4780000" -> Karte.BLATT_O;
+ case "04936BB4780000" -> Karte.SCHELL_7;
+ case "04F697C2126F80" -> Karte.SCHELL_8;
+ case "04946BB4780000" -> Karte.SCHELL_9;
+ case "04956BB4780000" -> Karte.SCHELL_X;
+ case "04986BB4780000" -> Karte.SCHELL_K;
+ case "04AA6BB4780000" -> Karte.SCHELL_A;
+ case "04966BB4780000" -> Karte.SCHELL_U;
+ case "04976BB4780000" -> Karte.SCHELL_O;
+ case "04F36BB4780000" -> Karte.HERZ_7;
+ case "04B06BB4780000" -> Karte.HERZ_8;
+ case "04AF6BB4780000" -> Karte.HERZ_9;
+ case "04AE6BB4780000" -> Karte.HERZ_X;
+ case "04AB6BB4780000" -> Karte.HERZ_K;
+ case "049C6BB4780000" -> Karte.HERZ_A;
+ case "04AD6BB4780000" -> Karte.HERZ_U;
+ case "04AC6BB4780000" -> Karte.HERZ_O;
+ default -> null;
+ };
+ }
+}
diff --git a/src/main/java/org/schafkopf/player/BotPlayer.java b/src/main/java/org/schafkopf/player/BotPlayer.java
new file mode 100644
index 0000000..72e4b04
--- /dev/null
+++ b/src/main/java/org/schafkopf/player/BotPlayer.java
@@ -0,0 +1,47 @@
+package org.schafkopf.player;
+
+import org.schafkopf.karte.Karte;
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenSymbol;
+import org.schafkopf.karte.KartenUtil;
+import org.schafkopf.spielcontroller.SauSpielController;
+import org.schafkopf.spielcontroller.SpielController;
+
+/**
+ * Player that represents the Bot.
+ */
+public class BotPlayer extends Player {
+
+ private KartenListe eigeneKarten;
+ private KartenListe unbekannteKarten = KartenUtil.initializeSchafKopfCardDeck();
+
+ public BotPlayer() {
+ // TODO document why this constructor is empty
+ }
+
+ @Override
+ public Karte play(SpielController spiel, KartenListe tischKarten) {
+
+ Karte cardIndex = eigeneKarten.getByIndex(spiel.welcheKarteSpielIch(0,
+ eigeneKarten,
+ eigeneKarten,
+ tischKarten));
+
+ eigeneKarten.removeKarten(cardIndex);
+
+ System.out.println("Eigene Karte legen");
+ return cardIndex;
+ }
+
+ /**
+ * Set the Cards of the Player.
+ */
+ public void setCards(KartenListe cards) {
+ System.out.println("Eigene Karte setzen");
+ this.eigeneKarten = cards;
+ this.unbekannteKarten = KartenUtil.initializeSchafKopfCardDeck();
+ this.unbekannteKarten.removeKarten(eigeneKarten);
+ System.out.println("Eigene Karte fertig");
+ }
+}
diff --git a/src/main/java/org/schafkopf/player/LocalPlayer.java b/src/main/java/org/schafkopf/player/LocalPlayer.java
new file mode 100644
index 0000000..446da73
--- /dev/null
+++ b/src/main/java/org/schafkopf/player/LocalPlayer.java
@@ -0,0 +1,25 @@
+package org.schafkopf.player;
+
+import org.schafkopf.Schafkopf;
+import org.schafkopf.karte.Karte;
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenSymbol;
+import org.schafkopf.spielcontroller.SpielController;
+
+/**
+ * Player that plays in real life.
+ */
+public class LocalPlayer extends Player {
+
+ private final Schafkopf schafkopf;
+
+ public LocalPlayer(Schafkopf schafkopf) {
+ this.schafkopf = schafkopf;
+ }
+
+ @Override
+ public Karte play(SpielController spiel, KartenListe tischKarten) {
+ return schafkopf.wartetAufKarte();
+ }
+}
diff --git a/src/main/java/org/schafkopf/player/Player.java b/src/main/java/org/schafkopf/player/Player.java
new file mode 100644
index 0000000..50f69e7
--- /dev/null
+++ b/src/main/java/org/schafkopf/player/Player.java
@@ -0,0 +1,12 @@
+package org.schafkopf.player;
+
+import org.schafkopf.karte.Karte;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.spielcontroller.SpielController;
+
+/**
+ * Class that represents one Player of the game.
+ */
+public abstract class Player {
+ public abstract Karte play(SpielController spiel, KartenListe tischKarten);
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/FarbGeierController.java b/src/main/java/org/schafkopf/spielcontroller/FarbGeierController.java
new file mode 100644
index 0000000..2c410a4
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/FarbGeierController.java
@@ -0,0 +1,35 @@
+package org.schafkopf.spielcontroller;
+
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenSymbol;
+import org.schafkopf.karte.KartenUtil;
+
+/**
+ * SpielController that implements Logic of a Farb Geier.
+ */
+public class FarbGeierController extends SoloController {
+ /**
+ * Create instance of SpielController.
+ *
+ * @param farbe Trumpffarbe of the Farb Geier.
+ */
+ public FarbGeierController(int activePlayer, KartenFarbe farbe) {
+ super(activePlayer);
+ KartenListe kartenList = KartenUtil.initializeSchafKopfCardDeck();
+ KartenListe oberKarten = kartenList.getKarten(KartenSymbol.OBER);
+ KartenListe farbTrumpfKarten = kartenList.getKarten(farbe);
+ farbTrumpfKarten.removeKarten(KartenSymbol.OBER);
+ farbTrumpfKarten.addKarten(oberKarten);
+ kartenList.removeKarten(farbTrumpfKarten);
+
+ this.trumpfKarten = new KartenListe(farbTrumpfKarten);
+ this.farbKarten = new KartenListe(kartenList);
+ }
+
+ public int welcheKarteSpielIch(int meinePosition,
+ KartenListe gespielteKarten, KartenListe meineHand, KartenListe tischKarten) {
+ return 0;
+ }
+
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/FarbSoloController.java b/src/main/java/org/schafkopf/spielcontroller/FarbSoloController.java
new file mode 100644
index 0000000..690ec62
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/FarbSoloController.java
@@ -0,0 +1,39 @@
+package org.schafkopf.spielcontroller;
+
+import org.schafkopf.karte.Karte;
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenSymbol;
+import org.schafkopf.karte.KartenUtil;
+
+/**
+ * SpielController that implements Logic of a Farb Solo.
+ */
+public class FarbSoloController extends SoloController {
+ /**
+ * Create instance of SpielController.
+ *
+ * @param farbe Trumpffarbe of the Farb Solo.
+ */
+ public FarbSoloController(int activePlayer, KartenFarbe farbe) {
+ super(activePlayer);
+ KartenListe kartenList = KartenUtil.initializeSchafKopfCardDeck();
+ KartenListe unterKarten = kartenList.getKarten(KartenSymbol.UNTER);
+
+ KartenListe farbTrumpfKarten = kartenList.getKarten(farbe);
+ farbTrumpfKarten.removeKarten(KartenSymbol.UNTER);
+ farbTrumpfKarten.removeKarten(KartenSymbol.OBER);
+ farbTrumpfKarten.addKarten(kartenList.getKarten(KartenSymbol.UNTER));
+ farbTrumpfKarten.addKarten(kartenList.getKarten(KartenSymbol.OBER));
+
+ kartenList.removeKarten(farbTrumpfKarten);
+
+ this.trumpfKarten = new KartenListe(farbTrumpfKarten);
+ this.farbKarten = new KartenListe(kartenList);
+ }
+
+ public int welcheKarteSpielIch(int meinePosition,
+ KartenListe gespielteKarten, KartenListe meineHand, KartenListe tischKarten) {
+ return 0;
+ }
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/FarbWenzController.java b/src/main/java/org/schafkopf/spielcontroller/FarbWenzController.java
new file mode 100644
index 0000000..0ff4c8c
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/FarbWenzController.java
@@ -0,0 +1,35 @@
+package org.schafkopf.spielcontroller;
+
+import org.schafkopf.karte.Karte;
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenSymbol;
+import org.schafkopf.karte.KartenUtil;
+
+/**
+ * SpielController that implements Logic of a Farb Wenz.
+ */
+public class FarbWenzController extends SoloController {
+ /**
+ * Create instance of SpielController.
+ *
+ * @param farbe Trumpffarbe of the Farb Wenz.
+ */
+ public FarbWenzController(int activePlayer, KartenFarbe farbe) {
+ super(activePlayer);
+ KartenListe kartenList = KartenUtil.initializeSchafKopfCardDeck();
+ KartenListe unterKarten = kartenList.getKarten(KartenSymbol.UNTER);
+ KartenListe farbTrumpfKarten = kartenList.getKarten(farbe);
+ farbTrumpfKarten.removeKarten(KartenSymbol.UNTER);
+ farbTrumpfKarten.addKarten(unterKarten);
+ kartenList.removeKarten(farbTrumpfKarten);
+
+ this.trumpfKarten = new KartenListe(farbTrumpfKarten);
+ this.farbKarten = new KartenListe(kartenList);
+ }
+
+ public int welcheKarteSpielIch(int meinePosition,
+ KartenListe gespielteKarten, KartenListe meineHand, KartenListe tischKarten) {
+ return 0;
+ }
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/GeierController.java b/src/main/java/org/schafkopf/spielcontroller/GeierController.java
new file mode 100644
index 0000000..ee59025
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/GeierController.java
@@ -0,0 +1,25 @@
+package org.schafkopf.spielcontroller;
+
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenSymbol;
+import org.schafkopf.karte.KartenUtil;
+
+/**
+ * SpielController that implements Logic of a Geier Game.
+ */
+public class GeierController extends GeierWenzController {
+ /**
+ * Create instance of Geier Game.
+ */
+ public GeierController(int activePlayer) {
+ super(activePlayer);
+ KartenListe kartenList = KartenUtil.initializeSchafKopfCardDeck();
+ KartenListe oberKarten = kartenList.getKarten(KartenSymbol.OBER);
+
+ kartenList.removeKarten(oberKarten);
+
+ this.trumpfKarten = new KartenListe(oberKarten);
+ this.farbKarten = new KartenListe(kartenList);
+ }
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/GeierWenzController.java b/src/main/java/org/schafkopf/spielcontroller/GeierWenzController.java
new file mode 100644
index 0000000..6a4586b
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/GeierWenzController.java
@@ -0,0 +1,21 @@
+package org.schafkopf.spielcontroller;
+
+import java.util.List;
+import org.schafkopf.karte.Karte;
+import org.schafkopf.karte.KartenListe;
+
+/**
+ * SpielController that implements Logic of a Geier/Wenz Game.
+ */
+public class GeierWenzController extends SoloController {
+
+ public GeierWenzController(int activePlayer) {
+ super(activePlayer);
+ }
+
+ @Override
+ public int welcheKarteSpielIch(int meinePosition, KartenListe gespielteKarten,
+ KartenListe meineHand, KartenListe tischKarten) {
+ return 0;
+ }
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/SauSpielController.java b/src/main/java/org/schafkopf/spielcontroller/SauSpielController.java
new file mode 100644
index 0000000..20eb24e
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/SauSpielController.java
@@ -0,0 +1,66 @@
+package org.schafkopf.spielcontroller;
+
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+
+/**
+ * SpielController that implements Logic of a Sau Spiel Game.
+ */
+public class SauSpielController extends StandardController {
+
+ KartenFarbe suchFarbe;
+ boolean istSpieler;
+
+ /**
+ * Class that represents one Card of the game.
+ */
+ public SauSpielController(int activePlayer, KartenFarbe farbe) {
+ super(activePlayer);
+ this.suchFarbe = suchFarbe;
+ this.istSpieler = istSpieler;
+ }
+
+ /**
+ * choose witch Card should be played with the right Game logic.
+ */
+ public int welcheKarteSpielIch(int meinePosition,
+ KartenListe gespielteKarten, KartenListe meineHand, KartenListe tischKarten) {
+ System.out.println("Ich spiele eine Karte Sauspiel");
+
+ int spielerNummer = tischKarten.size();
+
+ if (istSpieler && tischKarten.getLast().getFarbe().equals(suchFarbe)) {
+ return farbeZugeben(meineHand, suchFarbe, 2);
+ }
+
+ switch (spielerNummer) {
+ case 0:
+ if (istSpieler) {
+ return meineHand.size() - 1;
+ } else {
+ return 0;
+ }
+ case 1:
+ if (istSpieler) {
+ return farbeZugeben(meineHand, tischKarten.getLast().getFarbe(), 2);
+ } else {
+ return farbeZugeben(meineHand, tischKarten.getLast().getFarbe(), 0);
+ }
+ case 2:
+ if (istSpieler) {
+ return farbeZugeben(meineHand, tischKarten.getLast().getFarbe(), 2);
+ } else {
+ return farbeZugeben(meineHand, tischKarten.getLast().getFarbe(), 0);
+ }
+ case 3:
+ if (istSpieler) {
+ return farbeZugeben(meineHand, tischKarten.getLast().getFarbe(), 2);
+ } else {
+ return farbeZugeben(meineHand, tischKarten.getLast().getFarbe(), 0);
+ }
+ default:
+ System.out.println("Ungültige SpielerNummer");
+ }
+ return 0;
+ }
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/SoloController.java b/src/main/java/org/schafkopf/spielcontroller/SoloController.java
new file mode 100644
index 0000000..11ad24d
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/SoloController.java
@@ -0,0 +1,18 @@
+package org.schafkopf.spielcontroller;
+
+import org.schafkopf.karte.KartenListe;
+
+/**
+ * abstract Class that represents Logic of a Solo like Game.
+ */
+public abstract class SoloController extends SpielController {
+
+ SoloController(int activePlayer) {
+ super(activePlayer);
+ }
+
+ public int welcheKarteSpielIch(
+ KartenListe gespielteKarten, KartenListe meineHand, KartenListe tischKarten) {
+ return 0;
+ }
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/SpielController.java b/src/main/java/org/schafkopf/spielcontroller/SpielController.java
new file mode 100644
index 0000000..24c6ed1
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/SpielController.java
@@ -0,0 +1,116 @@
+package org.schafkopf.spielcontroller;
+
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenUtil;
+
+/** Base Class of Game Controllers. */
+public abstract class SpielController {
+ protected static KartenListe trumpfKarten;
+ protected static KartenListe farbKarten;
+
+ protected static int activePlayer;
+
+ public SpielController(int activePlayer) {
+ this.activePlayer = activePlayer;
+ }
+
+ /**
+ * Create instance of SpielController.
+ *
+ * @param meineHand Cards one Player holds.
+ * @param farbe color the Player has to play.
+ * @param mode Mode the player chooses a Card if multiple are available.
+ */
+ public static int farbeZugeben(KartenListe meineHand, KartenFarbe farbe, int mode) {
+ KartenListe farbKarten = meineHand.getKarten(farbe);
+ farbKarten.removeKarten(trumpfKarten);
+ if (farbKarten.size() == 1) {
+ return meineHand.indexOf(farbKarten.getByIndex(0));
+ }
+ if (farbKarten.size() > 1) {
+ switch (mode) {
+ case 0:
+ return 0;
+ case 1:
+ return meineHand.indexOf(farbKarten.getLast());
+ case 2:
+ return meineHand.indexOf(farbKarten.getLast());
+ default:
+ return 0;
+ }
+ }
+ if (farbKarten.isEmpty()) {
+ switch (mode) {
+ case 0:
+ return 0;
+ case 1:
+ return 0;
+ case 2:
+ return meineHand.size() - 1;
+ default:
+ return 0;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * sorts Cards, so they are in the right order for the active game.
+ *
+ * @param karten Trumpffarbe of the Farb Geier.
+ */
+ public static void sortiereKarten(KartenListe karten) {
+ KartenListe kartenReihenfolge = new KartenListe(farbKarten);
+ kartenReihenfolge.addKarten(trumpfKarten);
+
+ KartenListe kartenListe = KartenUtil.initializeSchafKopfCardDeck();
+
+ kartenListe.removeKarten(karten);
+ kartenReihenfolge.removeKarten(kartenListe);
+
+ karten.clear();
+ karten.addKarten(kartenReihenfolge);
+ }
+
+ /**
+ * checks, which card has the highest strength and will win one Stich.
+ *
+ * @param karten Cards to check.
+ */
+ public static int welcheKarteSticht(KartenListe karten) {
+ KartenListe kartenNew = new KartenListe(karten);
+ sortiereKarten(kartenNew);
+ KartenListe farbTischKarten = kartenNew.removeKarten(trumpfKarten);
+ System.out.println("trumpfKarten:");
+ System.out.println(trumpfKarten.getJson());
+
+ if (!farbTischKarten.isEmpty()) {
+ System.out.println("trumpfkarten:");
+ System.out.println(farbTischKarten.getJson());
+ return karten.indexOf(farbTischKarten.getLast());
+ } else {
+ KartenFarbe firstColor = karten.getByIndex(0).getFarbe();
+ KartenListe firstColorCards = kartenNew.removeKarten(firstColor);
+
+ System.out.println("firstcolor:");
+ System.out.println(firstColorCards.getJson());
+
+ return karten.indexOf(firstColorCards.getLast());
+ }
+ }
+
+ public abstract int welcheKarteSpielIch(
+ int meinePosition,
+ KartenListe gespielteKarten,
+ KartenListe meineHand,
+ KartenListe tischKarten);
+
+ public KartenListe getTrumpfKarten() {
+ return trumpfKarten;
+ }
+
+ public KartenListe getFarbKarten() {
+ return farbKarten;
+ }
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/StandardController.java b/src/main/java/org/schafkopf/spielcontroller/StandardController.java
new file mode 100644
index 0000000..2358008
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/StandardController.java
@@ -0,0 +1,31 @@
+package org.schafkopf.spielcontroller;
+
+import org.schafkopf.karte.KartenFarbe;
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenSymbol;
+import org.schafkopf.karte.KartenUtil;
+
+/**
+ * SpielController that has the standard Card Deck for Sauspiel, Bettel und Co.
+ */
+public abstract class StandardController extends SpielController {
+
+ StandardController(int activePlayer) {
+ super(activePlayer);
+ KartenListe kartenList = KartenUtil.initializeSchafKopfCardDeck();
+ KartenListe herzKarten = kartenList.getKarten(KartenFarbe.HERZ);
+ herzKarten.removeKarten(KartenSymbol.UNTER);
+ herzKarten.removeKarten(KartenSymbol.OBER);
+
+ herzKarten.addKarten(kartenList.getKarten(KartenSymbol.UNTER));
+ herzKarten.addKarten(kartenList.getKarten(KartenSymbol.OBER));
+
+ kartenList.removeKarten(herzKarten);
+
+ this.trumpfKarten = new KartenListe(herzKarten);
+ this.farbKarten = new KartenListe(kartenList);
+ }
+
+ public abstract int welcheKarteSpielIch(int meinePosition,
+ KartenListe gespielteKarten, KartenListe meineHand, KartenListe tischKarten);
+}
diff --git a/src/main/java/org/schafkopf/spielcontroller/WenzController.java b/src/main/java/org/schafkopf/spielcontroller/WenzController.java
new file mode 100644
index 0000000..70cff99
--- /dev/null
+++ b/src/main/java/org/schafkopf/spielcontroller/WenzController.java
@@ -0,0 +1,25 @@
+package org.schafkopf.spielcontroller;
+
+import org.schafkopf.karte.KartenListe;
+import org.schafkopf.karte.KartenSymbol;
+import org.schafkopf.karte.KartenUtil;
+
+/**
+ * SpielController that implements Logic of a Wenz Game.
+ */
+public class WenzController extends GeierWenzController {
+ /**
+ * Create instance of Wenz Game.
+ */
+ public WenzController(int activePlayer) {
+ super(activePlayer);
+ this.activePlayer = activePlayer;
+ KartenListe kartenList = KartenUtil.initializeSchafKopfCardDeck();
+ KartenListe unterKarten = kartenList.getKarten(KartenSymbol.UNTER);
+
+ kartenList.removeKarten(unterKarten);
+
+ this.trumpfKarten = new KartenListe(unterKarten);
+ this.farbKarten = new KartenListe(kartenList);
+ }
+}