package org.fhnw.aigs.RockPaperScissors.server;
import java.util.ArrayList;
import org.fhnw.aigs.RockPaperScissors.commons.GameState;
import org.fhnw.aigs.RockPaperScissors.commons.RockPaperScissorsSelectionMessage;
import org.fhnw.aigs.RockPaperScissors.commons.RockPaperScissorsParticipantsMessage;
import org.fhnw.aigs.RockPaperScissors.commons.RockPaperScissorsResultMessage;
import org.fhnw.aigs.RockPaperScissors.commons.RockPaperScissorsSymbol;
import org.fhnw.aigs.commons.Game;
import org.fhnw.aigs.commons.Player;
import org.fhnw.aigs.commons.communication.GameEndsMessage;
import org.fhnw.aigs.commons.communication.Message;
/**
* Server-side game logic: turn results are computed and sent to the clients
*/
public class GameLogic extends Game {
public static final String GAMENAME = "RockPaperScissors"; // Must match the value in client.Main
public static final String VERSION = "v1.1"; // Server-logic version
public static final int MINNUMBEROFPLAYERS = 2; // Number of players required for a game
public static final int NUMBEROFTURNS = 3; // Game is over after this many turns
private ArrayList<RockPaperScissorsTurn> turnPlayers; // List of all player-turns
private int turnNumber; // Current turn number
private boolean lastTurn; // Whether this is the last turn
/**
* Empty constructor (required); work handled by the superclass
*/
public GameLogic() {
super(GameLogic.GAMENAME, GameLogic.VERSION, GameLogic.MINNUMBEROFPLAYERS);
}
/**
* Initialize the game
*/
@Override
public void initialize() {
turnPlayers = new ArrayList<>();
RockPaperScissorsTurn turn = null;
// Create turn-object for each player
for (int i = 0; i < players.size(); i++) {
turn = new RockPaperScissorsTurn(players.get(i));
turnPlayers.add(turn);
}
turnNumber = 1;
lastTurn = false;
// For this particular game, the order of players is irrelevant; all players must play before the results are reveals.
// However, the AIGS-Framework requires that we specify a player to start.
setCurrentPlayer(getRandomPlayer());
// Start the game
startGame();
// Inform all players that the game has started
RockPaperScissorsParticipantsMessage identification = new RockPaperScissorsParticipantsMessage(turnPlayers.get(0).getPlayer(), turnPlayers.get(1).getPlayer());
sendMessageToAllPlayers(identification);
}
/**
* Process messages from the clients.
* @param msg Message from client; messages types are defined in the commons package
* @param player Player who sent the message
*/
@Override
public void processGameLogic(Message msg, Player player) {
if (msg instanceof RockPaperScissorsSelectionMessage) {
if (turnNumber == NUMBEROFTURNS)
lastTurn = true;
RockPaperScissorsSelectionMessage castMsg = (RockPaperScissorsSelectionMessage) msg;
// Locate the turn-object for this player, and set the symbol from the message
for (int i = 0; i < turnPlayers.size(); i++) {
if (turnPlayers.get(i).getPlayerID() == player.getId()) {
turnPlayers.get(i).setTurnSymbol(castMsg.getSymbol());
turnPlayers.get(i).setTurnFinished(true);
break;
}
}
// Checking for a winner is handled in checkForWinningCondition
}
}
/**
* This method is called after every player move, to see if the round is over
*/
@Override
public void checkForWinningCondition() {
if (allPlayersFinished() == true) {
// If all players have made their moves, determine the round winner (-1 = draw)
int winnerIndex = calculateTurnWinner();
// Send player-specific message to all players
RockPaperScissorsResultMessage result = null;
String messageText = "";
RockPaperScissorsTurn me = null;
RockPaperScissorsTurn opponent = null;
for (int i = 0; i < turnPlayers.size(); i++) {
me = turnPlayers.get(i);
opponent = turnPlayers.get(me.getOpponentIndex());
if (winnerIndex == -1) { // if a draw
messageText = "Two times " + GameLogic.printSymbol(me.getTurnSymbol()) + ". Draw!";
} else if (i == winnerIndex) { // this player won
messageText = GameLogic.printSymbol(me.getTurnSymbol()) + " beats " + GameLogic.printSymbol(opponent.getTurnSymbol()) + ". " + me.getPlayerName() + " wins!";
} else { // opponent won
messageText = GameLogic.printSymbol(opponent.getTurnSymbol()) + " beats " + GameLogic.printSymbol(me.getTurnSymbol()) + ". " + opponent.getPlayerName() + " wins!";
}
result = new RockPaperScissorsResultMessage(me.getTurnState(), lastTurn, me.getTurnSymbol(), opponent.getTurnSymbol(), opponent.getPlayerName(), me.getPoints(), opponent.getPoints(),
turnNumber, messageText);
sendMessageToPlayer(result, me.getPlayer()); // Send message to player
}
// Reset the turn objects for the next round
for (int i = 0; i < turnPlayers.size(); i++) {
turnPlayers.get(i).nextTurn();
}
turnNumber++;
if (lastTurn) {
RockPaperScissorsTurn winner = calculateGameWinner();
GameEndsMessage endMessage = null;
if (winner == null) { // If a draw over all rounds
endMessage = new GameEndsMessage("Draw!");
} else {
endMessage = new GameEndsMessage(winner.getPlayerName() + " won with " + Integer.toString(winner.getPoints()) + " rounds.");
}
sendMessageToAllPlayers(endMessage);
}
}
}
/**
* Have all players sent their moves?
* @return true if all players have submitted their moves, else false
*/
private boolean allPlayersFinished() {
boolean finished = true;
for (int i = 0; i < turnPlayers.size(); i++) {
if (!turnPlayers.get(i).hasTurnFinished()) {
finished = false; // Player found, who has not moved
break;
}
}
return finished;
}
/**
* Determine who has won the round, and return the corresponding index from the ArrayList. Currently supports only two players
* @return Index of the player who has won
*/
private int calculateTurnWinner() {
int winnerIndex = -1; // -1 means a drawn game
for (int i = 0; i < turnPlayers.size(); i++) {
for (int j = i + 1; j < turnPlayers.size(); j++) {
if (turnPlayers.get(i).getTurnSymbol() == turnPlayers.get(j).getTurnSymbol()) { // drawn round
turnPlayers.get(i).setTurnState(GameState.Draw);
turnPlayers.get(j).setTurnState(GameState.Draw);
} else if (turnPlayers.get(i).getTurnSymbol() == RockPaperScissorsSymbol.Paper && turnPlayers.get(j).getTurnSymbol() == RockPaperScissorsSymbol.Rock) {
turnPlayers.get(i).setTurnState(GameState.Win, 1);
turnPlayers.get(j).setTurnState(GameState.Lose);
} else if (turnPlayers.get(i).getTurnSymbol() == RockPaperScissorsSymbol.Paper && turnPlayers.get(j).getTurnSymbol() == RockPaperScissorsSymbol.Scissors) {
turnPlayers.get(i).setTurnState(GameState.Lose);
turnPlayers.get(j).setTurnState(GameState.Win, 1);
} else if (turnPlayers.get(i).getTurnSymbol() == RockPaperScissorsSymbol.Rock && turnPlayers.get(j).getTurnSymbol() == RockPaperScissorsSymbol.Paper) {
turnPlayers.get(i).setTurnState(GameState.Lose);
turnPlayers.get(j).setTurnState(GameState.Win, 1);
} else if (turnPlayers.get(i).getTurnSymbol() == RockPaperScissorsSymbol.Rock && turnPlayers.get(j).getTurnSymbol() == RockPaperScissorsSymbol.Scissors) {
turnPlayers.get(i).setTurnState(GameState.Win, 1);
turnPlayers.get(j).setTurnState(GameState.Lose);
} else if (turnPlayers.get(i).getTurnSymbol() == RockPaperScissorsSymbol.Scissors && turnPlayers.get(j).getTurnSymbol() == RockPaperScissorsSymbol.Rock) {
turnPlayers.get(i).setTurnState(GameState.Lose);
turnPlayers.get(j).setTurnState(GameState.Win, 1);
} else if (turnPlayers.get(i).getTurnSymbol() == RockPaperScissorsSymbol.Scissors && turnPlayers.get(j).getTurnSymbol() == RockPaperScissorsSymbol.Paper) {
turnPlayers.get(i).setTurnState(GameState.Win, 1);
turnPlayers.get(j).setTurnState(GameState.Lose);
}
turnPlayers.get(i).setOpponentIndex(j);
turnPlayers.get(j).setOpponentIndex(i);
}
}
// Look for winner. If there is no winner, then the index will remain -1
for (int i = 0; i < turnPlayers.size(); i++) {
if (turnPlayers.get(i).getTurnState() == GameState.Win) {
winnerIndex = i;
break;
}
}
return winnerIndex;
}
/**
* Return the turn-object of the overall game winner, or null if the game is drawn.
* @return RockPaperScissorsTurn-Objekt of the winner, or null if game is drawn
*/
private RockPaperScissorsTurn calculateGameWinner() {
int winnerIndex = 0; // Assume first player has won
int maxPoints = turnPlayers.get(0).getPoints(); // points of the first player
boolean draw = true; // Assume drawn will be true
// Search through players, beginning with second player, looking for higher points
for (int i = 1; i < turnPlayers.size(); i++) {
if (turnPlayers.get(i).getPoints() > maxPoints) {
// found higher point total: new winner
winnerIndex = i;
maxPoints = turnPlayers.get(i).getPoints();
draw = false;
} else if (turnPlayers.get(i).getPoints() < maxPoints) {
// lower points, so game is not drawn
draw = false;
}
}
if (draw) {
return null;
} else {
return turnPlayers.get(winnerIndex);
}
}
/**
* Return a string for the given symbol
* @param symbol Symbol (rock, paper, scissors)
* @return String value of the enumerated value
*/
public static String printSymbol(RockPaperScissorsSymbol symbol) {
if (symbol == RockPaperScissorsSymbol.Paper)
return "Paper";
else if (symbol == RockPaperScissorsSymbol.Rock)
return "Rock";
else if (symbol == RockPaperScissorsSymbol.Scissors)
return "Scissors";
else
return "None";
}
}