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 index 5b7e5d6..de49850 100644 --- 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 @@ -13,9 +13,17 @@ import java.util.logging.Logger; /** * Fetches and parses game state from server. * - * Protocol notes (based on your logs): - * - Success replies contain lines like PHASE=..., POT=..., PLAYER ... END ... END - * - Error replies contain -ERR, CODE=..., MSG=..., END + * Protocol notes (based on your current server implementation): + * - Success replies contain: PHASE, POT, CURRENT_BET, DEALER, ACTIVE_PLAYER, then blocks: + * - CARD ... END (community cards on root level) + * - PLAYER ... (NAME/CHIPS/BET/STATE + optional CARD blocks for requesting player) ... END + * - Error replies contain: -ERR then CODE=..., MSG=..., END + * + * Important: + * - The server does NOT wrap cards in a "CARDS" container. + * - CARD blocks appear either: + * - at root level -> community cards + * - inside PLAYER -> hole cards for that player (usually only for the requesting user) */ public class GameClient { @@ -51,7 +59,7 @@ public class GameClient { String joined = String.join("\n", lines); - if (joined.contains("-ERR")) { + if (joined.contains("-ERR") || joined.contains("-ERROR")) { String code = extractValue(joined, "CODE"); String msg = extractValue(joined, "MSG"); LOG.info(() -> "GET_GAME_STATE returned -ERR code=" + code + " msg=" + msg); @@ -100,14 +108,12 @@ public class GameClient { Player currentPlayer = null; Card currentCard = null; - boolean inPlayerCards = false; - boolean inCommunityCards = false; - for (String raw : input.split("\n")) { String line = raw.trim(); if (line.isEmpty()) continue; if (line.startsWith("+OK")) continue; + // Global fields if (line.startsWith("PHASE=")) { s.phase = value(line); continue; @@ -136,24 +142,21 @@ public class GameClient { if (line.equals("PLAYER")) { currentPlayer = new Player(); s.players.add(currentPlayer); - inPlayerCards = false; currentCard = null; continue; } if (line.equals("CARDS")) { - inPlayerCards = (currentPlayer != null); - inCommunityCards = (currentPlayer == null); - currentCard = null; continue; } - if (line.startsWith("CARD")) { + if (line.equals("CARD")) { currentCard = new Card("", ""); - if (inPlayerCards && currentPlayer != null) { - currentPlayer.addCard(currentCard); - } else if (inCommunityCards) { - s.communityCards.add(currentCard); + + if (currentPlayer != null) { + currentPlayer.addCard(currentCard); // hole card + } else { + s.communityCards.add(currentCard); // community card } continue; } @@ -162,7 +165,6 @@ public class GameClient { currentCard.setValue(value(line)); continue; } - if (line.startsWith("SUIT=") && currentCard != null) { currentCard.setSuit(value(line)); continue; @@ -173,18 +175,12 @@ public class GameClient { currentCard = null; continue; } - if (inPlayerCards) { - inPlayerCards = false; - continue; - } - if (inCommunityCards) { - inCommunityCards = false; - continue; - } + if (currentPlayer != null) { currentPlayer = null; continue; } + continue; } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameController.java index 7b28b4b..47d0e10 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameController.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/client/ui/gameui/CasinoGameController.java @@ -51,6 +51,9 @@ public class CasinoGameController { private Image dealerImage; private javafx.animation.Timeline timeline; private boolean gameStarted = false; + private java.util.List lastCommunityKeys = java.util.List.of(); + private java.util.List lastMyCardKeys = java.util.List.of(); + private int lastPot = Integer.MIN_VALUE; private static final int TOTAL_SLOTS = 5; private static final int PLAYER_SLOTS = 2; @@ -126,6 +129,22 @@ public class CasinoGameController { // default constructor for FXML } + private String cardKey(Card c) { + if (c == null) return "null"; + String suit = (c.getSuit() == null) ? "" : c.getSuit().toLowerCase(); + String value = (c.getValue() == null) ? "" : c.getValue().toLowerCase(); + return suit + ":" + value; + } + + private java.util.List cardKeys(java.util.List cards, int slots) { + java.util.List keys = new java.util.ArrayList<>(slots); + for (int i = 0; i < slots; i++) { + Card c = (cards != null && i < cards.size()) ? cards.get(i) : null; + keys.add(cardKey(c)); + } + return java.util.List.copyOf(keys); + } + /** * Set the GameService for this controller. This method must be called before starting the UI to * ensure that the controller has access to the game logic and can update the interface @@ -356,15 +375,28 @@ public class CasinoGameController { List players = (s.players != null) ? s.players : List.of(); List community = (s.communityCards != null) ? s.communityCards : List.of(); + List myCards = getMyCards(players); - renderCommunityCards(community); - renderPlayerCards(getMyCards(players)); - renderPot(s.pot); + java.util.List newCommunityKeys = cardKeys(community, TOTAL_SLOTS); + if (!newCommunityKeys.equals(lastCommunityKeys)) { + lastCommunityKeys = newCommunityKeys; + renderCommunityCards(community); + } + + java.util.List newMyCardKeys = cardKeys(myCards, PLAYER_SLOTS); + if (!newMyCardKeys.equals(lastMyCardKeys)) { + lastMyCardKeys = newMyCardKeys; + renderPlayerCards(myCards); + } + + if (s.pot != lastPot) { + lastPot = s.pot; + renderPot(s.pot); + } updatePlayers(players); updateGameInfo(s); highlightDealer(s); - updateTaskbar(s); LOGGER.info("myPlayerId=" + myPlayerId);