From 79bd33ad754124ddd644079748991cd54c38548a Mon Sep 17 00:00:00 2001 From: Julian Kropff Date: Thu, 2 Apr 2026 16:08:24 +0200 Subject: [PATCH] Add: initial client structure for game and network --- .../dbis/cs108/casono/client/game/Card.java | 9 ++ .../cs108/casono/client/game/GameState.java | 23 ++++ .../dbis/cs108/casono/client/game/Player.java | 17 +++ .../casono/client/network/ChatClient.java | 30 ++++- .../casono/client/network/ClientService.java | 45 +++++-- .../casono/client/network/CoreClient.java | 24 +++- .../casono/client/network/GameClient.java | 125 ++++++++++++++++++ .../casono/client/network/LobbyClient.java | 64 +++++++++ 8 files changed, 315 insertions(+), 22 deletions(-) create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/Card.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/GameState.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/Player.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/GameClient.java create mode 100644 src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/LobbyClient.java diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/Card.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/Card.java new file mode 100644 index 0000000..1d2a7f4 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/Card.java @@ -0,0 +1,9 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.game; + +/** + * Represents a playing card with a value and suit. + */ +public class Card { + public String value; + public String suit; +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/GameState.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/GameState.java new file mode 100644 index 0000000..8cd2183 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/GameState.java @@ -0,0 +1,23 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.game; + +import ch.unibas.dmi.dbis.cs108.casono.client.game.Card; +import ch.unibas.dmi.dbis.cs108.casono.client.game.Player; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents the current state of the poker game, including the phase, pot + * size, current bet, dealer position, + * active player, community cards, and player information. + */ +public class GameState { + public String phase; + public int pot; + public int currentBet; + public int dealer; + public int activePlayer; + + public List communityCards = new ArrayList<>(); + public List players = new ArrayList<>(); +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/Player.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/Player.java new file mode 100644 index 0000000..2702d97 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/game/Player.java @@ -0,0 +1,17 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.game; + +import java.util.ArrayList; +import java.util.List; + +/** + * Represents a player in the poker game, including their name, chip count, + * current bet, state (e.g., "active", "folded"), and their hole cards. + */ +public class Player { + public String name; + public int chips; + public int bet; + public String state; + + public List cards = new ArrayList<>(); +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java index b9f30c4..e5a17cb 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ChatClient.java @@ -5,36 +5,52 @@ import ch.unibas.dmi.dbis.cs108.casono.client.chat.Message; import java.util.ArrayList; import java.util.List; +/** + * The ChatClient class is responsible for sending messages to the server and + * retrieving messages from the server. It uses the ClientService to send + * commands and receive responses from the server. + */ public class ChatClient { private ClientService clientService; + /** + * Constructs a ChatClient with the given ClientService for communication. + * + * @param clientService The ClientService instance used to send commands and + * receive responses from the server. + */ public ChatClient(ClientService clientService) { this.clientService = clientService; } /** - * sends a message to the server - * @param message + * Send a Message to the server by converting it to a string format and + * sending a "SEND_MESSAGE" command with the message content as arguments. + * + * @param message The Message object to be sent to the server. */ - public void sendMessage(Message message) { String request = "SEND_MESSAGE " + message.toArgsString(); clientService.processCommand(request); } /** - * Send a Request to get the number of Messages currently in the Queue for the client. - * Then proceeds, if needed, to get the messages by sending + * Retrieve messages from the server by first sending a "GET_MESSAGE_COUNT" + * command to determine how many messages are available and then sending + * "GET_NEXT_MESSAGE" commands in a loop to retrieve each message. The + * retrieved messages are parsed into Message objects and returned as a list. + * + * @return A list of Message objects representing the messages retrieved from + * the server. */ - public List getMessages() { String countStr = clientService.processCommand("GET_MESSAGE_COUNT"); int count = Integer.parseInt(countStr); System.out.println("Got " + count + " messages"); List messages = new ArrayList<>(); for (int i = 0; i < count; i++) { - String message = clientService.processCommand("GET_NEXT_MESSAGE"); + String message = clientService.processCommand("GET_NEXT_MESSAGE"); if (message != null) { Message message1 = Message.toMessage(message); messages.add(message1); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ClientService.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ClientService.java index df64b61..e5785a9 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ClientService.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/ClientService.java @@ -16,8 +16,11 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; /** - * Responsible for the transferring of the data from the Client to the Server and the other way - * around + * The ClientService class is responsible for managing the connection to the + * server, + * sending commands, and receiving responses. It uses a TcpTransport to + * communicate + * with the server and an ExecutorService to handle asynchronous requests. */ public class ClientService { @@ -29,13 +32,13 @@ public class ClientService { public static ArrayList response; private final AtomicInteger idGenerator; private final Logger logger; - - /** - * Creates a new ClientSession with a Socket, a Reader and Writer of the Input- and the - * Outputstream and a pool of threads to send requests and receive responses. + /* + * Constructs a ClientService with the given server IP and port. It establishes + * a socket connection to the server and initializes the TcpTransport and + * ExecutorService for communication. * - * @param ip : ip-adress of the server - * @param port : port of the server + * @param ip The IP address of the server to connect to. + * @param port The port number of the server to connect to. */ public ClientService(String ip, int port) { @@ -55,7 +58,6 @@ public class ClientService { } - /** * Sends the Requests to the server and waits for the response If the response is "+OK" it * proceeds normal If the response "-ERROR" it throws a runtime exception @@ -88,7 +90,13 @@ public class ClientService { } /** - * @param request + * Helper method to send a request to the server using the ExecutorService. It + * submits the request as a Runnable task and waits for its completion. If + * the task is interrupted or encounters an execution exception, it throws a + * RuntimeException with the appropriate cause. + * + * @param request The Runnable task representing the request to be sent to the + * server. */ private void sendRequest(Runnable request) { Future future = executor.submit(request); @@ -102,10 +110,14 @@ public class ClientService { } /** - * Returns a Runtime Exceptions thrown by the sendRequest method + * Helper method to extract the cause of an exception and return it as a + * RuntimeException. If the cause is null, it returns the original exception as + * a RuntimeException. If the cause is already a RuntimeException, it returns + * it directly. Otherwise, it wraps the cause in a new RuntimeException and + * returns it. * - * @param e - an Exception - * @return - a Runtime Exception + * @param e The exception from which to extract the cause. + * @return A RuntimeException representing the cause of the original exception. */ private static RuntimeException getRuntimeException(Exception e) { Throwable reason = e.getCause(); @@ -119,7 +131,12 @@ public class ClientService { return re; } - /** Closes the Socket and shuts down the Threadpool associated with that Socket-Connection. */ + /** + * Closes the socket connection to the server and shuts down the + * ExecutorService. + * It also closes the TcpTransport used for communication. If any IOException + * occurs during this process, it prints the exception to the console. + */ public void closeSocket() { try { executor.shutdown(); diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/CoreClient.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/CoreClient.java index 92902bc..2db2111 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/CoreClient.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/CoreClient.java @@ -1,17 +1,39 @@ package ch.unibas.dmi.dbis.cs108.casono.client.network; +/** + * The CoreClient class provides basic functionalities for communicating with + * the + * server, such as sending a ping command to check connectivity and logging in + * with a username. It uses the ClientService to send commands and receive + * responses from the server. + */ public class CoreClient { private final ClientService clientService; + /** + * Constructs a CoreClient with the given ClientService for communication. + * + * @param clientservice The ClientService instance used to send commands and + * receive responses from the server. + */ public CoreClient(ClientService clientservice) { this.clientService = clientservice; } + /** + * Sends a "PING" command to the server to check connectivity. The server + * should respond with a "PONG" message if the connection is successful. + */ public void ping() { clientService.processCommand("PING"); } + /** + * Logs in to the server with the given username by sending a "LOGIN" command. + * + * @param user The username to log in with. + */ public void login(String user) { clientService.processCommand("LOGIN USERNAME=" + user); } -} \ No newline at end of file +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/GameClient.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/GameClient.java new file mode 100644 index 0000000..0ae8225 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/GameClient.java @@ -0,0 +1,125 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.network; + +import ch.unibas.dmi.dbis.cs108.casono.client.game.Card; +import ch.unibas.dmi.dbis.cs108.casono.client.game.GameState; +import ch.unibas.dmi.dbis.cs108.casono.client.game.Player; + +import java.util.ArrayList; +import java.util.List; + +/** + * The GameClient class is responsible for communicating with the server to + * retrieve the current game state. It sends a command to the server and + * parses the response into a structured GameState object. + */ +public class GameClient { + + private final ClientService client; + + /** + * Constructs a GameClient with the given ClientService for communication. + * + * @param client The ClientService instance used to send commands and receive + * responses from the server. + */ + public GameClient(ClientService client) { + this.client = client; + } + + /** + * Retrieves the current game state from the server by sending a command and + * parsing the response. + * + * @return A GameState object representing the current state of the game. + */ + public GameState getGameState() { + String response = client.processCommand("GET_GAME_STATE"); + return parseGameState(response); + } + + /** + * Parses the raw response from the server into a structured GameState object. + * + * @param input The raw response string from the server. + * @return A GameState object representing the current state of the game. + */ + private GameState parseGameState(String input) { + + GameState state = new GameState(); + + String[] lines = input.split("\n"); + + Player currentPlayer = null; + Card currentCard = null; + + for (String rawLine : lines) { + + String line = rawLine.trim(); + + if (line.startsWith("+OK") || line.equals("END")) { + continue; + } + + if (line.startsWith("PHASE=")) { + state.phase = line.split("=")[1]; + } + + else if (line.startsWith("POT=")) { + state.pot = Integer.parseInt(line.split("=")[1]); + } + + else if (line.startsWith("CURRENT_BET=")) { + state.currentBet = Integer.parseInt(line.split("=")[1]); + } + + else if (line.startsWith("DEALER=")) { + state.dealer = Integer.parseInt(line.split("=")[1]); + } + + else if (line.startsWith("ACTIVE_PLAYER=")) { + state.activePlayer = Integer.parseInt(line.split("=")[1]); + } + + else if (line.startsWith("PLAYER")) { + currentPlayer = new Player(); + state.players.add(currentPlayer); + } + + else if (line.startsWith("NAME=") && currentPlayer != null) { + currentPlayer.name = line.split("=")[1]; + } + + else if (line.startsWith("CHIPS=") && currentPlayer != null) { + currentPlayer.chips = Integer.parseInt(line.split("=")[1]); + } + + else if (line.startsWith("BET=") && currentPlayer != null) { + currentPlayer.bet = Integer.parseInt(line.split("=")[1]); + } + + else if (line.startsWith("STATE=") && currentPlayer != null) { + currentPlayer.state = line.split("=")[1]; + } + + else if (line.startsWith("CARD")) { + currentCard = new Card(); + + if (currentPlayer != null) { + currentPlayer.cards.add(currentCard); + } else { + state.communityCards.add(currentCard); + } + } + + else if (line.startsWith("VALUE=") && currentCard != null) { + currentCard.value = line.split("=")[1]; + } + + else if (line.startsWith("SUIT=") && currentCard != null) { + currentCard.suit = line.split("=")[1]; + } + } + + return state; + } +} diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/LobbyClient.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/LobbyClient.java new file mode 100644 index 0000000..996f767 --- /dev/null +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/network/LobbyClient.java @@ -0,0 +1,64 @@ +package ch.unibas.dmi.dbis.cs108.casono.client.network; + +/** + * The LobbyClient class is responsible for communicating with the server to + * manage game lobbies. It provides methods to create a lobby, join a lobby, + * and fetch the current status of a lobby by sending appropriate commands to + * the server and processing the responses. + */ +public class LobbyClient { + private final ClientService client; + + /** + * Constructs a LobbyClient with the given ClientService for communication. + * + * @param client The ClientService instance used to send commands and receive + * responses from the server. + */ + public LobbyClient(ClientService client) { + this.client = client; + } + + /** + * Fetch the current status of the lobby with the given id from the server. + * + * @param lobbyId The id of the lobby to fetch the status for. + * @return A string representing the current status of the lobby, as returned + * by the server. + */ + public String fetchLobbyStatusString(int lobbyId) { + return client.processCommand("GET_LOBBY_STATUS ID=" + lobbyId); + } + + /** + * Request the server to create a new lobby and return the id of the newly + * created lobby. + * + * @return The id of the newly created lobby, as returned by the server. + */ + public int createLobby() { + String response = client.processCommand("CREATE_LOBBY"); + return Integer.parseInt(response); + } + + /** + * Request the server to return the id of the lobby that the client is + * currently in. + * + * @return The id of the lobby that the client is currently in, as returned by + * the server. + */ + public int getLobbyId() { + String response = client.processCommand("GET_LOBBY_ID"); + return Integer.parseInt(response); + } + + /** + * Request the server to join the lobby with the given id. + * + * @param lobbyId The id of the lobby to join. + */ + public void joinLobby(int lobbyId) { + client.processCommand("JOIN_LOBBY ID=" + lobbyId); + } +}