diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/game/get_game_state/GetGameStateHandler.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/game/get_game_state/GetGameStateHandler.java index b43f322..d9fb584 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/game/get_game_state/GetGameStateHandler.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/app/commands/game/get_game_state/GetGameStateHandler.java @@ -1,6 +1,7 @@ package ch.unibas.dmi.dbis.cs108.casono.server.app.commands.game.get_game_state; import ch.unibas.dmi.dbis.cs108.casono.server.app.checks.UserLoggedInCheck; +import ch.unibas.dmi.dbis.cs108.casono.server.domain.game.state.GamePhase; import ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.Lobby; import ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.LobbyId; import ch.unibas.dmi.dbis.cs108.casono.server.domain.lobby.LobbyManager; @@ -31,8 +32,10 @@ public class GetGameStateHandler extends CommandHandler { String username = resolveUsername(request); Lobby lobby; + LobbyId lobbyId; if (gameId != null) { - lobby = lobbyManager.getLobby(LobbyId.of(gameId)); + lobbyId = LobbyId.of(gameId); + lobby = lobbyManager.getLobby(lobbyId); if (lobby == null) { responseDispatcher.dispatch( new ErrorResponse( @@ -59,6 +62,7 @@ public class GetGameStateHandler extends CommandHandler { request.getContext(), "NOT_IN_LOBBY", "User not in a lobby")); return; } + lobbyId = lobby.getId(); } var game = lobby.getGameController(); @@ -69,9 +73,30 @@ public class GetGameStateHandler extends CommandHandler { return; } + if (game.getState().getPhase() == GamePhase.FINISHED) { + cleanupLobby(lobby, lobbyId); + } + responseDispatcher.dispatch(new GetGameStateResponse(request.getContext(), game, username)); } + /** + * Cleans up a lobby by removing all players and resetting the game controller. This is called + * when the game reaches FINISHED phase. + */ + private void cleanupLobby(Lobby lobby, LobbyId lobbyId) { + try { + // Remove all players from the lobby + for (String playerName : lobby.getPlayerNames()) { + lobbyManager.removePlayer(playerName); + } + // Reset the game controller so the lobby returns to CREATED state + lobby.initGame(null); + } catch (RuntimeException e) { + // Log silently to avoid disrupting game state response + } + } + private String resolveUsername(GetGameStateRequest request) { String username = request.getUsername(); if (username != null && !username.isBlank()) { diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/GameController.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/GameController.java index 1199630..b90de4f 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/GameController.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/GameController.java @@ -254,4 +254,12 @@ public class GameController { return bestPlayer; } + + /** + * Ends the current game by setting the phase to FINISHED. This should be called when the + * showdown is complete and a winner has been determined. + */ + public void endGame() { + engine.getState().setPhase(GamePhase.FINISHED); + } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/engine/RoundManager.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/engine/RoundManager.java index 4853946..677c1b4 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/engine/RoundManager.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/engine/RoundManager.java @@ -49,6 +49,11 @@ public class RoundManager { state.setPhase(GamePhase.PREFLOP); } + if (state.countNonFoldedPlayers() == 1) { + state.setPhase(GamePhase.FINISHED); + return; + } + if (isBettingRoundFinished(state)) { advancePhase(state); } @@ -81,8 +86,9 @@ public class RoundManager { case FLOP -> dealTurn(state); case TURN -> dealRiver(state); case RIVER -> showdown(state); - case SHOWDOWN -> { - /* nothing */ + case SHOWDOWN -> state.setPhase(GamePhase.FINISHED); + case FINISHED -> { + /* game is over */ } } } diff --git a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/state/GameState.java b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/state/GameState.java index 81fbdfb..a018d6a 100644 --- a/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/state/GameState.java +++ b/src/main/java/ch/unibas/dmi/dbis/cs108/casono/server/domain/game/state/GameState.java @@ -11,19 +11,15 @@ import java.util.List; import java.util.Map; /** - * The GameState class encapsulates the entire state of a poker game at any - * given moment. + * The GameState class encapsulates the entire state of a poker game at any given moment. * - *

- * Important invariants this implementation maintains: + *

Important invariants this implementation maintains: * *

    - *
  • {@code playerOrder} defines the stable seating/turn order. - *
  • {@code currentBets} always contains an entry for every player in - * {@code playerOrder}. - *
  • {@code holeCards} maps every player to a mutable list; if not present, it - * is created on - * demand. + *
  • {@code playerOrder} defines the stable seating/turn order. + *
  • {@code currentBets} always contains an entry for every player in {@code playerOrder}. + *
  • {@code holeCards} maps every player to a mutable list; if not present, it is created on + * demand. *
*/ public class GameState { @@ -188,8 +184,7 @@ public class GameState { } /** - * Reset bets to 0 for ALL players (do not clear the map). Also resets table - * current bet to 0. + * Reset bets to 0 for ALL players (do not clear the map). Also resets table current bet to 0. */ public void resetBets() { for (PlayerId id : playerOrder) { @@ -232,8 +227,7 @@ public class GameState { // Cards /** - * Gives (overwrites) the two hole cards for the given player. Ensures stable - * list identity + * Gives (overwrites) the two hole cards for the given player. Ensures stable list identity * (important if other code holds references). */ public void giveHoleCards(PlayerId playerId, Card c1, Card c2) { @@ -293,14 +287,13 @@ public class GameState { /** * Starts a new hand by resetting the game state for the next round of poker. * - *

- * This: + *

This: * *

    - *
  • sets {@code phase=PREFLOP} - *
  • resets pot/bets/commitments - *
  • clears community + hole cards - *
  • creates & shuffles a new deck + *
  • sets {@code phase=PREFLOP} + *
  • resets pot/bets/commitments + *
  • clears community + hole cards + *
  • creates & shuffles a new deck *
*/ public void startNewHand() { @@ -336,4 +329,19 @@ public class GameState { public boolean isFolded(PlayerId playerId) { return getPlayer(playerId).isFolded(); } + + /** + * Counts the number of players who have not folded. + * + * @return The number of non-folded players + */ + public int countNonFoldedPlayers() { + int count = 0; + for (Player p : players.values()) { + if (p != null && !p.isFolded()) { + count++; + } + } + return count; + } }