package pp.mdga.server; import pp.mdga.game.Color; import pp.mdga.game.Node; import pp.mdga.game.Piece; import pp.mdga.game.PieceState; import pp.mdga.game.PlayerData; import pp.mdga.message.client.*; import pp.mdga.message.server.EndOfTurn; import pp.mdga.message.server.PossibleCard; import pp.mdga.message.server.RankingResponce; import pp.mdga.message.server.ServerMessage; import java.lang.System.Logger; import java.util.ArrayList; import java.util.List; /** * Abstract class representing a state in the server's state machine. * Implements the Observer pattern to observe changes in the game state. */ public abstract class ServerState implements Observer { /** * Logger for logging messages within the application. */ protected static final Logger LOGGER = System.getLogger(ServerState.class.getName()); /** * The parent state of the current state. */ protected ServerState parent; /** * The game logic associated with the server state. */ protected ServerGameLogic logic; /** * Constructs a new ServerState with the specified parent state and game logic. * * @param parent the parent state of the current state * @param logic the game logic associated with the server state */ protected ServerState(ServerState parent, ServerGameLogic logic) { this.parent = parent; this.logic = logic; } /** * This method is called when the state is entered. */ public void entry() { /* do nothing */ } /** * This method is called when the state is exited. */ public void exit() { /* do nothing */ } /** * This method is called when an animation ends. * * @param msg the animation end message */ public void receivedAnimationEnd(AnimationEnd msg, int from) { /* do nothing */ } /** * This method is called when a TSK is deselected. * * @param msg the deselect TSK message */ public void receivedDeselectTSK(DeselectTSK msg, int from) { /* do nothing */ } /** * This method is called when a NoPowerCard message is received. * * @param msg the NoPowerCard message */ public void receivedNoPowerCard(NoPowerCard msg, int from) { /* do nothing */ } /** * This method is called when a LobbyNotReady message is received. * * @param msg the LobbyNotReady message */ public void receivedNotReady(LobbyNotReady msg, int from) { /* do nothing */ } /** * This method is called when a LobbyReady message is received. * * @param msg the LobbyReady message */ public void receivedReady(LobbyReady msg, int from) { /* do nothing */ } /** * This method is called when a RequestDice message is received. * * @param msg the RequestDice message */ public void receivedRequestDice(RequestDice msg, int from) { /* do nothing */ } /** * This method is called when a RequestMove message is received. * * @param msg the RequestMove message */ public void receivedRequestMove(RequestMove msg, int from) { /* do nothing */ } /** * This method is called when a SelectCard message is received. * * @param msg the SelectCard message */ public void receivedSelectCard(SelectCard msg, int from) { /* do nothing */ } /** * This method is called when a SelectTSK message is received. * * @param msg the SelectTSK message */ public void receivedSelectTSK(SelectTSK msg, int from) { /* do nothing */ } /** * This method is called when a SelectedPieces message is received. * * @param msg the SelectedPieces message */ public void receivedSelectedPieces(SelectedPieces msg, int from) { /* do nothing */ } /** * This method is called when a StartGame message is received. * * @param msg the StartGame message */ public void receivedStartGame(ClientStartGame msg, int from) { /* do nothing */ } /** * This method is called when an EndOfTurn message is sent. * * @param msg the EndOfTurn message */ public void sentEndOfTurn(EndOfTurn msg, int from) { /* do nothing */ } /** * This method is called when a PossibleCard message is sent. * * @param msg the PossibleCard message */ public void sentPossibleCard(PossibleCard msg, int from) { /* do nothing */ } /** * This method is called when a RankingResponce message is sent. * * @param msg the RankingResponce message */ public void sentRankingResponse(RankingResponce msg, int from) { /* do nothing */ } /** * This method transitions to a new state. * * @param state the new state to transition to * @throws IllegalStateException if called outside a state machine */ public void gotoState(ServerState state) { throw new IllegalStateException("not in a statemachine"); } /** * Returns the parent state of the current state. * * @return the parent state */ public ServerState getParent() { return parent; } /** * This method is called when the observed object is changed. * It is part of the Observer pattern implementation. */ public void update() { /* do nothing */ } /** * This method is used to calculate the steps a piece can move * * @return the steps a piece can move */ private int calculateSteps() { return logic.getGame().getDiceEyes() * logic.getGame().getDiceModifier(); } /** * This method is used to test if u can move a piece * * @param piece the piece to be moved * @return true if the piece can be moved, false otherwise */ protected boolean tryMove(Piece piece) { int steps = calculateSteps(); if (piece.getState() == PieceState.HOME) { return tryHomeMove(piece, steps); } else { int homeMoves = getHomeMoves(piece, steps); if (homeMoves > 0) { return tryHomeMove(piece, homeMoves); } else { return tryInfieldMove(piece, steps); } } } /** * This method is used to determine if a piece would move into the home area. * * @param piece the piece to be moved * @param steps the steps the piece would move * @return the number of steps the piece would move into the home area */ protected int getHomeMoves(Piece piece, int steps) { int figureIndex = logic.getGame().getBoard().getInfieldIndexOfPiece(piece); Color col = piece.getColor(); int startIndex = logic.getGame().getBoard().getPlayerData().get(col).getStartNodeIndex(); int moveIndex = startIndex + steps; if (moveIndex > logic.getGame().getBoard().getInfield().length) { moveIndex %= logic.getGame().getBoard().getInfield().length; if (moveIndex >= startIndex) { return moveIndex - startIndex + 1; } } else if (figureIndex < startIndex && moveIndex >= startIndex) { return moveIndex - startIndex + 1; } return 0; } /** * This method is used to determine if a piece can move in the infield * * @param piece the piece to be moved * @param steps the steps the piece would move * @return true if the piece can move in the infield, false otherwise */ protected boolean tryInfieldMove(Piece piece, int steps) { int figureIndex = logic.getGame().getBoard().getInfieldIndexOfPiece(piece); int moveIndex = (figureIndex + steps) % logic.getGame().getBoard().getInfield().length; Piece occupant = logic.getGame().getBoard().getInfield()[moveIndex].getOccupant(); if (occupant != null) { return occupant.getColor() != piece.getColor(); } return true; } /** * This method is used to determine if a piece can move inside the home area * * @param piece the piece to be moved * @param steps the steps the piece would move * @return true if the piece can move into the home area, false otherwise */ protected boolean tryHomeMove(Piece piece, int steps) { Color col = piece.getColor(); PlayerData playerData = logic.getGame().getBoard().getPlayerData().get(col); Node[] homeNodes = playerData.getHomeNodes(); int index; if (playerData.homeIncludes(piece)) { index = playerData.getIndexInHome(piece); } else { index = 0; } if (index + steps >= homeNodes.length) { return false; } else { for (int i = index; i <= index + steps; i++) { if (homeNodes[i].getOccupant() != null) { return false; } } return true; } } /** * This method is used to get the pieces that can be moved * * @param color the color of the pieces * @return the pieces that can be moved */ protected List getMoveablePieces(Color color) { ArrayList moveablePieces = new ArrayList<>(); ArrayList pieces = new ArrayList<>(); for (Piece piece : logic.getGame().getBoard().getPlayerData().get(color).getPieces()) { if (piece.getState() == PieceState.ACTIVE || piece.getState() == PieceState.HOME) { pieces.add(piece); } } for (Piece piece : pieces) { if (tryMove(piece)) { moveablePieces.add(piece); } } return moveablePieces; } /** * Broadcasts an update message to all players. * * @param updateMessage the update message to be sent */ protected void broadcastUpdate(ServerMessage updateMessage) { for (var entry : logic.getGame().getPlayers().entrySet()) { logic.send(entry.getValue(), updateMessage); } } /** * Returns a string representation of the object. * * @return the simple name of the class */ @Override public String toString() { return getClass().getSimpleName(); } }