325 lines
10 KiB
Java
325 lines
10 KiB
Java
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<Piece> getMoveablePieces(Color color) {
|
|
ArrayList<Piece> moveablePieces = new ArrayList<>();
|
|
ArrayList<Piece> 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();
|
|
}
|
|
}
|