Message types and server (#44)

* message type and handling

* deleted web-content and fixed bug

* edited main page
This commit is contained in:
Valentin Heiserer
2024-04-23 21:54:31 +02:00
committed by GitHub
parent cab2d36f48
commit a0a1cfaa4a
79 changed files with 1737 additions and 637 deletions

View File

@@ -5,14 +5,18 @@ import com.google.gson.JsonObject;
import org.schafkopf.karte.Karte;
import org.schafkopf.karte.KartenFarbe;
/** GameState. */
/**
* GameState.
*/
public class GameState {
public GamePhase getGamePhase() {
return this.gamePhase;
}
/** GamePhase. */
/**
* GamePhase.
*/
public enum GamePhase {
CHOOSE_GAME("Spiel muss gewählt werden"),
@@ -53,7 +57,9 @@ public class GameState {
this.currentPlayer = player;
}
/** GameState. */
/**
* GameState.
*/
public GameState(GamePhase phase, Integer player, Karte card, KartenFarbe color, boolean trumpf) {
this.gamePhase = phase;
this.currentPlayer = player;
@@ -62,19 +68,34 @@ public class GameState {
this.trumpf = trumpf;
}
/** GameState. */
/**
* GameState.
*/
public GameState(GamePhase phase, Integer player, Karte card) {
this.gamePhase = phase;
this.currentPlayer = player;
this.card = card;
}
/** GameState. */
/**
* GameState.
*/
public JsonObject getJson() {
Gson gson = new Gson();
JsonObject jsonObject = new JsonObject();
jsonObject.add("gamestate", gson.toJsonTree(this));
JsonObject gameStateObject = new JsonObject();
return jsonObject;
if (this.currentPlayer != null) {
gameStateObject.addProperty("currentPlayer", this.currentPlayer);
}
if (this.card != null) {
gameStateObject.add("card", gson.toJsonTree(this.card));
}
gameStateObject.addProperty("gamePhase", this.gamePhase.name());
gameStateObject.addProperty("trumpf", this.trumpf);
if (this.color != null) {
gameStateObject.addProperty("color", this.color.name());
}
return gameStateObject;
}
}

View File

@@ -0,0 +1,9 @@
package org.schafkopf;
/**
* Class that represents one Frontend Connection.
*/
public interface MessageListener {
void receiveMessage(String message);
}

View File

@@ -1,6 +1,11 @@
package org.schafkopf;
/** The main entrypoint of the Application. */
import org.schafkopf.SchafkopfMessage.SchafkopfBaseMessage;
/**
* The main entrypoint of the Application.
*/
public interface MessageSender {
void sendMessage(String message);
void sendMessage(SchafkopfBaseMessage message);
}

View File

@@ -1,25 +1,31 @@
package org.schafkopf;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.schafkopf.GameState.GamePhase;
import org.schafkopf.SchafkopfException.NotEnoughPlayersException;
import org.schafkopf.SchafkopfMessage.SchafkopfBaseMessage;
import org.schafkopf.SchafkopfMessage.SchafkopfMessageType;
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.OnlinePlayer;
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. */
/**
* The main class representing the Schafkopf game.
*/
public class Schafkopf {
private final MessageSender messageSender;
/** The game controller. This is the class that implements the game logic. */
/**
* The game controller. This is the class that implements the game logic.
*/
private SpielController spiel = new SauSpielController(0, KartenFarbe.EICHEL);
private final Player[] player;
@@ -32,8 +38,13 @@ public class Schafkopf {
*
* @param messageSender MessageSender
*/
public Schafkopf(Player[] player, MessageSender messageSender) {
public Schafkopf(Player[] player, MessageSender messageSender) throws NotEnoughPlayersException {
this.player = player;
if (player.length < 4) {
throw new NotEnoughPlayersException();
}
this.messageSender = messageSender;
System.out.println("SchaffKopfGame erstellt");
}
@@ -42,23 +53,24 @@ public class Schafkopf {
return player;
}
/** Set GameState to "started" and start Game Thread. */
public void startGame() {
/**
* Set GameState to "started" and start Game Thread.
*/
public void startGame() throws InterruptedException {
if (gameState.getGamePhase() != GamePhase.GAME_STOP) {
System.out.println("Game already started!");
messageSender.sendMessage("Game already started!");
messageSender.sendMessage(new SchafkopfBaseMessage(SchafkopfMessageType.UNKNOWN_ERROR));
} else {
gameState = new GameState(GamePhase.GAME_START);
setAndSendGameState(gameState);
System.out.println("Start Game");
KartenListe austeilen = KartenUtil.initializeSchafKopfCardDeck();
austeilen.shuffle();
for (Player currentPlayer : player) {
if (currentPlayer instanceof BotPlayer botPlayer) {
KartenListe botHand = new KartenListe();
for (int i = 7; i >= 0; i--) {
System.out.println("Austeilen: " + austeilen.size());
System.out.println("Bot Hand: " + i);
botHand.addKarten(austeilen.removeKarten(austeilen.getByIndex(i)));
}
System.out.println("Bot Hand: " + botHand.getJson().toString());
@@ -66,17 +78,35 @@ public class Schafkopf {
}
}
spielThread = new Thread(() -> new Spielablauf(this, spiel));
for (Player currentPlayer : player) {
if (currentPlayer instanceof OnlinePlayer) {
Karte[] karten = new Karte[8];
for (int i = 7; i >= 0; i--) {
karten[i] = austeilen.removeKarten(austeilen.getByIndex(i));
}
Gson gson = new Gson();
JsonObject messageObject = new JsonObject();
messageObject.add("cards", gson.toJsonTree(karten));
spielThread.start();
messageSender.sendMessage(
new SchafkopfBaseMessage(SchafkopfMessageType.ONLINE_PLAYER_HAND, messageObject));
}
}
// spielThread = new Thread(() -> new Spielablauf(this, spiel));
//
// spielThread.start();
new Spielablauf(this, spiel);
}
}
/** Set GameState to "stopped" and interrupt Game Thread. */
/**
* Set GameState to "stopped" and interrupt Game Thread.
*/
public void stopGame() {
if (gameState.getGamePhase() == GamePhase.GAME_STOP) {
System.out.println("no active Game!");
messageSender.sendMessage("no active Game!");
messageSender.sendMessage(new SchafkopfBaseMessage(SchafkopfMessageType.UNKNOWN_ERROR));
} else {
gameState = new GameState(GamePhase.GAME_STOP);
setAndSendGameState(gameState);
@@ -85,68 +115,13 @@ public class Schafkopf {
spielThread.interrupt();
}
/** Set GameType. */
public void setGame(String message) {
System.out.println("Set Game: " + message);
messageSender.sendMessage("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");
}
}
/**
* Class that represents one Frontend Connection.
*/
public void setAndSendGameState(GameState gameState) {
this.gameState = gameState;
this.messageSender.sendMessage(this.gameState.getJson().toString());
this.messageSender.sendMessage(
new SchafkopfBaseMessage(SchafkopfMessageType.GAME_STATE, gameState.getJson()));
}
public GameState getGameState() {

View File

@@ -0,0 +1,37 @@
package org.schafkopf;
/**
* Class that represents one Frontend Connection.
*/
public class SchafkopfException extends Exception {
private SchafkopfException(String message) {
super(message);
}
/**
* Class that represents one Frontend Connection.
*/
public static class NotEnoughPlayersException extends SchafkopfException {
public NotEnoughPlayersException() {
super("Not enough players to start the game");
}
// You can also include additional constructors or methods if needed
}
/**
* Class that represents one Frontend Connection.
*/
public class InvalidMoveException extends SchafkopfException {
// Constructor with a message
public InvalidMoveException(String message) {
super(message);
}
// You can also include additional constructors or methods if needed
}
}

View File

@@ -0,0 +1,141 @@
package org.schafkopf;
import com.google.gson.JsonObject;
/**
* Class that represents one Frontend Connection.
*/
public class SchafkopfMessage {
/**
* Class that represents one Frontend Connection.
*/
public static class SchafkopfBaseMessage {
private JsonObject message;
public SchafkopfBaseMessage(SchafkopfMessageType messageType, String content) {
this.message = buildBaseMessage(messageType, content);
}
public SchafkopfBaseMessage(SchafkopfMessageType messageType, JsonObject content) {
this.message = buildBaseMessage(messageType, content);
}
public SchafkopfBaseMessage(SchafkopfMessageType messageType) {
this.message = buildBaseMessage(messageType);
}
public JsonObject getBaseMessage() {
return message;
}
}
JsonObject message;
public SchafkopfMessage(SchafkopfMessageOrigin origin, SchafkopfBaseMessage baseMessage) {
this.message = buildWrapperMessage(origin, baseMessage.getBaseMessage());
}
/**
* Class that represents one Frontend Connection.
*/
public SchafkopfMessage(SchafkopfMessageOrigin origin, SchafkopfMessageType messageType) {
JsonObject messageContentObject = new JsonObject();
messageContentObject.add("content", buildBaseMessage(messageType));
this.message = buildWrapperMessage(origin, messageContentObject);
}
/**
* Class that represents one Frontend Connection.
*/
private SchafkopfMessage(SchafkopfMessageOrigin origin, SchafkopfMessageType messageType,
JsonObject messageContent) {
JsonObject messageContentObject = new JsonObject();
messageContentObject.add("content", buildBaseMessage(messageType, messageContent));
this.message = buildWrapperMessage(origin, messageContentObject);
}
/**
* Class that represents one Frontend Connection.
*/
public SchafkopfMessage(SchafkopfMessageOrigin origin, SchafkopfMessageType messageType,
String messageContent) {
JsonObject messageContentObject = new JsonObject();
messageContentObject.add("content", buildBaseMessage(messageType, messageContent));
this.message = buildWrapperMessage(origin, messageContentObject);
}
private static JsonObject buildWrapperMessage(SchafkopfMessageOrigin origin, JsonObject message) {
JsonObject messageObject = new JsonObject();
messageObject.addProperty("origin", origin.toString());
messageObject.add("message", message);
return messageObject;
}
private static JsonObject buildBaseMessage(SchafkopfMessageType messageType,
String messageContent) {
JsonObject messageContentObject = new JsonObject();
messageContentObject.addProperty("message_type", messageType.toString());
messageContentObject.addProperty("content", messageContent);
return messageContentObject;
}
private static JsonObject buildBaseMessage(SchafkopfMessageType messageType,
JsonObject messageContent) {
JsonObject messageContentObject = new JsonObject();
messageContentObject.addProperty("message_type", messageType.toString());
messageContentObject.add("content", messageContent);
return messageContentObject;
}
private static JsonObject buildBaseMessage(SchafkopfMessageType messageType) {
JsonObject messageContentObject = new JsonObject();
messageContentObject.addProperty("message_type", messageType.toString());
return messageContentObject;
}
public JsonObject getMessage() {
return message;
}
public String getMessageAsString() {
return message.toString();
}
/**
* Class that represents one Frontend Connection.
*/
public enum SchafkopfMessageType {
UNKNOWN_ERROR,
HEARTBEAT_SYN,
HEARTBEAT_ACK,
GET_CARD_ONLINE_PLAYER,
ONLINE_PLAYER_HAND,
GAME_STATE,
SERVER_CONNECTION_SUCCESSFUL,
REQUEST_SERVER_CONNECTION,
START_GAME,
JOIN_GAME,
PLAYER_CARD
}
/**
* Class that represents one Frontend Connection.
*/
public enum SchafkopfMessageOrigin {
FRONTEND,
BACKEND,
DEDICATED_SERVER
}
}

View File

@@ -8,7 +8,9 @@ import org.schafkopf.spielcontroller.SpielController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** The main class that controlls the game flow. */
/**
* The main class that controlls the game flow.
*/
public class Spielablauf {
private static final Logger logger = LoggerFactory.getLogger(Spielablauf.class);
@@ -22,7 +24,7 @@ public class Spielablauf {
private final Schafkopf schafkopf;
Spielablauf(Schafkopf schafkopf, SpielController spiel) {
Spielablauf(Schafkopf schafkopf, SpielController spiel) throws InterruptedException {
this.schafkopf = schafkopf;
this.spiel = spiel;
this.players = schafkopf.getPlayer();
@@ -30,7 +32,7 @@ public class Spielablauf {
playRound();
}
private void playRound() {
private void playRound() throws InterruptedException {
int startingPlayer = 0;
logger.info("Starte Stiche");
@@ -41,7 +43,7 @@ public class Spielablauf {
schafkopf.stopGame();
}
private int playTrick(int startingPlayer) {
private int playTrick(int startingPlayer) throws InterruptedException {
schafkopf.setAndSendGameState(new GameState(GamePhase.TRICK_START));
for (int i = 0; i < 4; i++) {

View File

@@ -3,12 +3,14 @@ package org.schafkopf.karte;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A Class that represents a list of Cards.
*/
public class KartenListe {
private List<Karte> kartenListe;
public KartenListe() {
@@ -23,6 +25,10 @@ public class KartenListe {
return this.kartenListe;
}
public void shuffle() {
Collections.shuffle(this.kartenListe);
}
/**
* A Class that represents a list of Cards.
*/
@@ -158,6 +164,24 @@ public class KartenListe {
return result;
}
/**
* Class that represents one Frontend Connection.
*/
public Karte getKarten(KartenSymbol symbol, KartenFarbe farbe) {
KartenListe result = new KartenListe();
for (Karte karte : this.kartenListe) {
if (karte.getSymbol().equals(symbol)) {
result.addKarten(karte);
}
}
for (Karte karte : result.kartenListe) {
if (karte.getFarbe().equals(farbe)) {
result.addKarten(karte);
}
}
return result.getByIndex(0);
}
/**
* A Class that represents a list of Cards.
*/

View File

@@ -0,0 +1,46 @@
package org.schafkopf.player;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.schafkopf.MessageSender;
import org.schafkopf.SchafkopfMessage.SchafkopfBaseMessage;
import org.schafkopf.SchafkopfMessage.SchafkopfMessageType;
import org.schafkopf.karte.Karte;
import org.schafkopf.karte.KartenListe;
import org.schafkopf.spielcontroller.SpielController;
/**
* Player that plays in real life.
*/
public class OnlinePlayer extends Player {
private final MessageSender messageSender;
private final BlockingQueue<Karte> receivedCardQueue = new LinkedBlockingQueue<>();
public OnlinePlayer(MessageSender messageSender) {
this.messageSender = messageSender;
}
@Override
public Karte play(SpielController spiel, KartenListe tischKarten, KartenListe gespielteKarten)
throws InterruptedException {
Karte spielKarte = null;
// Send the message to request the card from the frontend
messageSender.sendMessage(
new SchafkopfBaseMessage(SchafkopfMessageType.GET_CARD_ONLINE_PLAYER));
spielKarte = receivedCardQueue.take();
System.out.println("Karte gespielt: " + spielKarte);
return spielKarte;
}
/**
* Class that represents one Frontend Connection.
*/
public void receiveCard(Karte receivedCard) {
System.out.println("Received Card before Queue: " + receivedCard.getName());
receivedCardQueue.add(receivedCard);
}
}

View File

@@ -4,8 +4,12 @@ import org.schafkopf.karte.Karte;
import org.schafkopf.karte.KartenListe;
import org.schafkopf.spielcontroller.SpielController;
/** Class that represents one Player of the game. */
/**
* Class that represents one Player of the game.
*/
public abstract class Player {
public abstract Karte play(
SpielController spiel, KartenListe tischKarten, KartenListe gespielteKarten);
SpielController spiel, KartenListe tischKarten, KartenListe gespielteKarten)
throws InterruptedException;
}