Merge remote-tracking branch 'origin/main' into GUI

This commit is contained in:
2026-05-03 17:48:24 +02:00
66 changed files with 1744 additions and 498 deletions
@@ -5,28 +5,67 @@ import it.polimi.ingsw.gc14.Network.RMI.Client.RMIClient;
import it.polimi.ingsw.gc14.Network.TCP.Client.TCPClient;
import it.polimi.ingsw.gc14.View.TUI.TUI;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* Entry point for the TUI-based game client.
* Handles the initial setup by asking the user for a username, the desired number of players,
* and the preferred network protocol (RMI or TCP).
* Once connected to the server, it continuously reads and dispatches user input to the controller.
*/
public class ClientLauncherTUI {
//TODO Javadoc
List<String> admissibleChar=new ArrayList<>();
/**
* The TUI view associated with this client.
*/
TUI view;
/**
* Starts the TUI client.
* Prompts the user for a username, the desired number of players, and the network protocol.
* Attempts to connect to the server using either RMI or TCP depending on the selection.
* If the connection is successful, enters a loop to continuously read and process user input.
*
* @throws InterruptedException if the thread is interrupted while waiting.
*/
public void main() throws InterruptedException {
TUI view=new TUI(null);
view = new TUI(null);
admissibleChar.add("0");
admissibleChar.add("1");
admissibleChar.add("2");
admissibleChar.add("3");
admissibleChar.add("4");
admissibleChar.add("5");
admissibleChar.add("6");
admissibleChar.add("7");
admissibleChar.add("8");
admissibleChar.add("9");
admissibleChar.add("A");
admissibleChar.add("B");
admissibleChar.add("C");
admissibleChar.add("a");
admissibleChar.add("b");
admissibleChar.add("c");
ClientController controller = new ClientController(view);
Scanner scanner = new Scanner(System.in);
System.out.println("Selezionare nome utente: ");
System.out.println("Insert username: ");
String username = scanner.next();
System.out.println("Selezionare numero di giocatori desiderato: ");
view.setUsername(username);
System.out.println("Insert preferred number of players: ");
int proposedNumPlayers = scanner.nextInt();
System.out.println("Selezionare RMI[0] o TCP[1]: ");
System.out.println("Select RMI[0] o TCP[1]: ");
int networkType = scanner.nextInt();
System.out.println("Insert server IP: ");
String IP = scanner.next();
// RMI
if (networkType == 0) {
// Connect
RMIClient client = new RMIClient(controller, "localhost", 1099);
RMIClient client = new RMIClient(controller, IP, 1099);
if (client.connect(username, proposedNumPlayers)) {
System.out.println("Succesfully connected to RMI server\n\n");
} else {
@@ -34,20 +73,13 @@ public class ClientLauncherTUI {
return;
}
controller.setClient(client);
// Play
//while(controller.localController.getModel()==null){
// scanner.nextInt();
//}
while(true) {
while (true) {
getInput(scanner, controller, username);
}
// TCP
// TCP
} else if (networkType == 1) {
// Connect
TCPClient client = new TCPClient(controller, "localhost", 8080);
TCPClient client = new TCPClient(controller, IP, 8080);
if (client.connect(username, proposedNumPlayers)) {
System.out.println("Succesfully connected to TCP server\n\n");
} else {
@@ -55,31 +87,75 @@ public class ClientLauncherTUI {
return;
}
controller.setClient(client);
// Play
while(true) {
while (true) {
getInput(scanner, controller, username);
}
}
scanner.close();
}
/**
* Reads a single action from the user and dispatches it to the controller.
* The action is identified by a string code. Most actions also require a position index
* (e.g. the index of the card to draw from a list), which is read as a second input.
* Actions that do not require a position (7, 8, 9, A, B, C) skip the position prompt.
* <p>
* Available actions:
* <ul>
* <li>{@code 0} - Choose a slot by index.</li>
* <li>{@code 1} - Draw an upper building card by index.</li>
* <li>{@code 2} - Draw an upper tribe card by index.</li>
* <li>{@code 3} - Draw a lower building card by index.</li>
* <li>{@code 4} - Draw a lower tribe card by index.</li>
* <li>{@code 5} - Pick an optional tribe card by index.</li>
* <li>{@code 6} - Pick an optional building card by index.</li>
* <li>{@code 7} - Skip the optional card choice.</li>
* <li>{@code 8} - Skip the upper draw.</li>
* <li>{@code 9} - Skip the lower draw.</li>
* <li>{@code A} - Render the full game view.</li>
* <li>{@code B} - Render the board view.</li>
* <li>{@code C} - Render the player view.</li>
* </ul>
*
* @param scanner the scanner used to read user input.
* @param controller the client controller to which actions are dispatched.
* @param username the username of the current player.
*/
private void getInput(Scanner scanner, ClientController controller, String username) {
int action = scanner.nextInt();
int pos = scanner.nextInt();
String action = scanner.next();
int pos = -1;
switch(action) {
case 1 -> controller.drawLowerBuildingCard(username, pos);
case 2 -> controller.drawLowerTribeCard(username, pos);
case 3 -> controller.drawUpperBuildingCard(username, pos);
case 4 -> controller.drawUpperTribeCard(username, pos);
case 5 -> controller.pickOptionalBuildingCard(username, pos);
case 6 -> controller.slotChoice(username, pos);
if(admissibleChar.contains(username))
{
if (!action.equals("7") && !action.equals("8") && !action.equals("9") && !action.equals("A") && !action.equals("B") && !action.equals("C")) {
try {
System.out.println("Insert the required position:");
pos = scanner.nextInt();
} catch (Exception e) {
System.out.println("ERROR: Invalid input(expected number)");
}
}
switch (action) {
case "0" -> controller.slotChoice(username, pos);
case "1" -> controller.drawUpperTribeCard(username, pos);
case "2" -> controller.drawUpperBuildingCard(username, pos);
case "3" -> controller.drawLowerTribeCard(username, pos);
case "4" -> controller.drawLowerBuildingCard(username, pos);
case "5" -> controller.pickOptionalTribeCard(username, pos);
case "6" -> controller.pickOptionalBuildingCard(username, pos);
case "7" -> controller.noOptionalCard(username);
case "8" -> controller.skipUpper(username);
case "9" -> controller.skipLower(username);
case "A", "a" -> view.fullRender();
case "B", "b" -> view.renderBoard();
case "C", "c" -> view.renderPlayer();
default -> {}
}
}
else
{
System.out.println("ERROR: Invalid input(action not valid)");
}
return;
}
}
@@ -1,116 +1,164 @@
package it.polimi.ingsw.gc14.Controller;
import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.Model.Player;
import it.polimi.ingsw.gc14.Network.IClient;
import it.polimi.ingsw.gc14.Network.NetworkEvents.*;
import it.polimi.ingsw.gc14.Network.Observer;
import it.polimi.ingsw.gc14.View.IView;
//TODO Javadoc
/**
* Controller class that holds all the components of the client, such as view, network client and Game Controller.
* It provides methods to set the client components and to execute requested actions.
*/
public class ClientController {
/** Game Controller of the client */
public GameController localController;
//TODO Javadoc
public IView view=null;
/** View of the client */
public IView view;
/** Network client (either TCP or RMI) */
private IClient client;
/**
* Constructs the ClientController.
* Initializes all attributes.
* @param view the client view (either TUI or GUI)
*/
public ClientController(IView view) {
this.view = view;
this.localController = new GameController();
this.client = null;
}
/**
* Sets the network client.
* @param client the client to set (either TCP or RMI)
*/
public void setClient(IClient client) {
this.client = client;
}
/**
* Sets the model in the GameController and updates the view.
* @param model the model to set
*/
public void setModel(Game model) {
localController.setModel(model);
view.update(localController.getModel());
}
/**
* Displays an error message in the view.
* @param message the error message to display
*/
public void onError(String message) {
view.showError(message);
}
/**
* Attempts to draw an upper tribe card for the specified player from the specified position.
*
* @param playerUsername the username of the player performing the action.
* @param pos the position of the upper tribe card to draw.
* @return {@code true} if the action succeeds, {@code false} if the player does not exist
* or if the draw operation fails.
* Requests to draw a tribe card from the upper list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawUpperTribeCard(String playerUsername,int pos) {
public void drawUpperTribeCard(String playerUsername, int pos) {
client.doEvent(new DrawUpperTribeCard(playerUsername,pos));
}
/**
* Attempts to draw a lower tribe card for the specified player from the specified position.
*
* @param playerUsername the username of the player performing the action.
* @param pos the position of the lower tribe card to draw.
* @return {@code true} if the action succeeds, {@code false} if the player does not exist
* or if the draw operation fails.
* Requests to draw a tribe card from the lower list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawLowerTribeCard(String playerUsername,int pos) {
client.doEvent(new DrawLowerTribeCard(playerUsername,pos));
}
/**
* Attempts to draw an upper building card for the specified player from the specified position.
*
* @param playerUsername the username of the player performing the action.
* @param pos the position of the upper building card to draw.
* @return {@code true} if the action succeeds, {@code false} if the player does not exist
* or if the draw operation fails.
* Requests to draw a building card from the upper list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawUpperBuildingCard(String playerUsername,int pos) {
client.doEvent(new DrawUpperBuildingCard(playerUsername,pos));
}
/**
* Attempts to draw a lower building card for the specified player from the specified position.
*
* @param playerUsername the username of the player performing the action.
* @param pos the position of the lower building card to draw.
* @return {@code true} if the action succeeds, {@code false} if the player does not exist
* or if the draw operation fails.
* Requests to draw a building card from the lower list.
* Creates a NetworkEvent and sends it through the network client.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void drawLowerBuildingCard(String playerUsername,int pos) {
client.doEvent(new DrawLowerBuildingCard(playerUsername,pos));
}
/**
* Attempts to pick an optional tribe card for the specified player from the specified position.
*
* @param playerUsername the username of the player performing the action.
* @param pos the position of the optional tribe card to pick.
* @return {@code true} if the action succeeds, {@code false} if the player does not exist
* or if the pick operation fails.
* Requests to skip drawing from the upper list.
* This action is available only when the upper list is empty or the player cannot draw any card.
* @param playerUsername the name of the player performing the action
*/
public void skipUpper(String playerUsername) {
client.doEvent(new SkipUpper(playerUsername));
}
/**
* Requests to skip drawing from the lower list.
* This action is available only when the lower list is empty or the player cannot draw any card.
* @param playerUsername the name of the player performing the action
*/
public void skipLower(String playerUsername) { client.doEvent(new SkipLower(playerUsername));}
/**
* Used to draw a tribe card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void pickOptionalTribeCard(String playerUsername,int pos) {
client.doEvent(new PickOptionalTribeCard(playerUsername,pos));
}
/**
* Attempts to pick an optional building card for the specified player from the specified position.
*
* @param playerUsername the username of the player performing the action.
* @param pos the position of the optional building card to pick.
* @return {@code true} if the action succeeds, {@code false} if the player does not exist
* or if the pick operation fails.
* Used to draw a building card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
* @param pos the index of the card to draw
*/
public void pickOptionalBuildingCard(String playerUsername,int pos) {
client.doEvent(new PickOptionalBuildingCard(playerUsername,pos));
}
/**
* Attempts to perform the slot choice action for the specified player at the specified position.
*
* @param playerUsername the username of the player performing the action.
* @param pos the position of the chosen slot.
* @return {@code true} if the action succeeds, {@code false} if the player does not exist
* or if the slot choice operation fails.
* Used to skip the action of drawing a card from the upper list.
* Available only if the player owns the building 12.
* @param playerUsername the name of the player performing the action
*/
public void noOptionalCard(String playerUsername) {
client.doEvent(new NoOptionalCard(playerUsername));
}
/**
* Used to perform the slot choice action for the specified player at the specified position.
* @param playerUsername the name of the player performing the action
* @param pos the index of the selected slot
*/
public void slotChoice(String playerUsername,int pos) {
client.doEvent(new SlotChoice(playerUsername,pos));
@@ -1,6 +1,7 @@
package it.polimi.ingsw.gc14.Controller;
import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
import it.polimi.ingsw.gc14.Model.Player;
/**
@@ -118,6 +119,20 @@ public class GameController {
return model.DrawLowerBuildingCardByIndex(model.getPlayerByUsername(playerUsername), pos);
}
public boolean SkipUpperDrawing(String playerUsername) {
Player player= model.getPlayerByUsername(playerUsername);
if(player==null)
return false;
return model.SkipUpperDrawing(model.getPlayerByUsername(playerUsername));
}
public boolean SkipLowerDrawing(String playerUsername) {
Player player= model.getPlayerByUsername(playerUsername);
if(player==null)
return false;
return model.SkipLowerDrawing(model.getPlayerByUsername(playerUsername));
}
/**
* Attempts to pick an optional tribe card for the specified player from the specified position.
*
@@ -147,6 +162,18 @@ public class GameController {
return false;
return model.PickOptionalBuildingCard(model.getPlayerByUsername(playerUsername), pos);
}
/**
* Refuse to pick an optional building card for the specified player.
* @param playerUsername the username of the player performing the action.
* @return {@code true} if the action succeeds, {@code false} if the player does not exist
* or if the pick operation fails.
*/
public boolean noOptionalCard(String playerUsername) {
Player player= model.getPlayerByUsername(playerUsername);
if(player==null)
return false;
return model.NoOptionalCard(model.getPlayerByUsername(playerUsername));
}
/**
* Attempts to perform the slot choice action for the specified player at the specified position.
@@ -1,22 +1,42 @@
package it.polimi.ingsw.gc14;
import java.util.ArrayList;
//TODO Javadoc
/**
* An {@link ArrayList} with a configurable size limit and an associated action.
* When the number of elements reaches or exceeds the limit, the specified action is automatically triggered.
*
* @param <T> the type of elements held in this list.
*/
public class LimitedList<T> extends ArrayList<T> {
//TODO Javadoc
/**
* The maximum number of elements allowed in the list before the action is triggered.
*/
private int limit;
//TODO Javadoc
/**
* The action to execute when the list size reaches or exceeds the limit.
*/
private Runnable action;
//TODO Javadoc
/**
* Creates a new {@code LimitedList} with the specified limit and action.
*
* @param limit the maximum number of elements before the action is triggered.
* @param action the action to execute when the limit is reached.
*/
public LimitedList(int limit, Runnable action) {
this.limit = limit;
this.action = action;
}
//TODO Javadoc
/**
* Adds the specified element to the list.
* If the list size reaches or exceeds the limit after the insertion, the configured action is triggered.
*
* @param element the element to add.
* @return {@code true} if the element was successfully added.
*/
@Override
public boolean add(T element) {
boolean result = super.add(element);
@@ -26,16 +46,30 @@ public class LimitedList<T> extends ArrayList<T> {
return result;
}
//TODO Javadoc
/**
* Sets a new size limit for this list.
*
* @param num the new limit.
*/
public void setLimit(int num) {
this.limit=num;
this.limit = num;
}
//TODO Javadoc
public int getLimit(){return limit;}
/**
* Returns the current size limit of this list.
*
* @return the current limit.
*/
public int getLimit() {
return limit;
}
//TODO Javadoc
/**
* Sets a new action to execute when the list size reaches or exceeds the limit.
*
* @param action the new action to set.
*/
public void setAction(Runnable action) {
this.action=action;
this.action = action;
}
}
@@ -1,5 +1,5 @@
package it.polimi.ingsw.gc14.Model.Cards.Building;
public enum EffectType {
FINAL, CARD_SET,INVENTOR_PAIR, ON_EVENT , ON_END_TURN, ON_ROUND_END
FINAL, CARD_SET, INVENTOR_PAIR, ON_EVENT, ON_END_TURN, ON_ROUND_END
}
@@ -42,7 +42,7 @@ public class Building8 extends BuildingCard {
if(!player.buildingCards.contains(this))
throw new IllegalArgumentException();
for (Builder builder : player.builders) {
player.addPrestige(builder.getPrestigeValue() * 2);
player.addPrestige(builder.getPrestigeValue());
}
}
@@ -159,8 +159,16 @@ public class BuildingCard extends PlayableCard implements Cloneable , BuildingEf
* @return {@code true} if the building card is successfully bought,
* {@code false} otherwise.
*/
// sum reduction value builder=> sconto
public boolean buy(Player player) {
if( bought || !player.removeFood(getPrice()))
int discount = 0;
discount = player.builders.stream().mapToInt(x -> x.getReductionValue()).sum();
if(discount > this.price){
discount = this.price;
}
if(bought || !player.removeFood(this.price - discount))
return false;
player.buildingCards.add(this);
bought=true;
@@ -1,5 +1,5 @@
package it.polimi.ingsw.gc14.Model.Cards.TribeCards;
public enum CharacterType {
INVENTOR,BUILDER, GATHERER,ARTIST,SHAMAN,HUNTER
INVENTOR, BUILDER, GATHERER, ARTIST, SHAMAN, HUNTER
}
@@ -98,6 +98,9 @@ public class Hunter extends Character {
@Override
public void insert(Player player) {
player.hunters.add(this);
if(this.getIcon()){
player.addFood(player.hunters.size());
}
}
}
@@ -62,7 +62,7 @@ public abstract class EventCard extends TribeCard {
*/
@Override
public String toString() {
return super.toString()+" "+type.toString();
return super.toString()+"(Event)"+type.toString();
}
/**
@@ -77,7 +77,7 @@ public abstract class EventCard extends TribeCard {
*/
@Override
public String toStringBoard() {
return super.toString()+" "+type.toString();
return super.toString()+"(Event)"+type.toString();
}
/**
@@ -43,7 +43,7 @@ public class Sustenance extends EventCard {
* If the resulting Food debt is positive, the player must pay it with available Food.
* If the player does not have enough Food, all remaining Food is removed and the player
* loses Prestige equal to the unpaid Food debt multiplied by {@code PrestigeDebt}.
* This event is intended to be executed last among event effects.
* <b>This event is intended to be executed last among event effects.</b>
*
* @param playerList the list of players affected by the event.
* @throws NullPointerException if {@code playerList} or one of its required elements is {@code null}.
@@ -15,10 +15,19 @@ import java.io.*;
import java.lang.reflect.Type;
import java.util.*;
//TODO javadoc
/**
* Utility class responsible for loading and creating decks of cards and slots for the game.
* Cards are loaded from JSON resource files and instantiated according to their type and parameters.
*/
public class DecksCreator {
//TODO javadoc
/**
* Loads the tribe card deck for the specified era from the corresponding JSON resource file.
*
* @param era the era number (1, 2, or 3).
* @return a list of {@link TribeCard} objects for the specified era.
* @throws IllegalArgumentException if {@code era} is not 1, 2, or 3.
*/
public static List<TribeCard> loadTribeDeckByEra(int era) throws IllegalArgumentException
{
return switch (era) {
@@ -29,7 +38,13 @@ public class DecksCreator {
};
}
//TODO javadoc
/**
* Loads a tribe card deck from the specified JSON resource file path.
*
* @param resourcePath the path to the JSON resource file.
* @return a list of {@link TribeCard} objects defined in the resource file.
* @throws RuntimeException if the resource file is not found or an error occurs while reading it.
*/
public static List<TribeCard> loadTribeDeck(String resourcePath) {
Gson gson = new Gson();
Type listType = new com.google.gson.reflect.TypeToken<List<TribeCardDefinition>>(){}.getType();
@@ -51,14 +66,26 @@ public class DecksCreator {
}
}
//TODO javadoc
public static List<BuildingCard> loadBuildingDeckByEra(int era) throws IllegalArgumentException
/**
* Loads the building card deck for the specified era, filtering cards from the global building deck.
*
* @param era the era number (1, 2, or 3).
* @return a list of {@link BuildingCard} objects belonging to the specified era.
* @throws IllegalArgumentException if {@code era} is not 1, 2, or 3.
*/
public static List<BuildingCard> loadBuildingDeckByEra(int era) throws IllegalArgumentException
{
if(era<=0 || era>3) throw new IllegalArgumentException();
return loadBuildingDeck("/Cards/buildingCards.json").stream().filter(x->x.getEra()==era).toList();
}
//TODO javadoc
/**
* Loads the full building card deck from the specified JSON resource file path.
*
* @param resourcePath the path to the JSON resource file.
* @return a list of {@link BuildingCard} objects defined in the resource file.
* @throws RuntimeException if the resource file is not found or an error occurs while reading it.
*/
public static List<BuildingCard> loadBuildingDeck(String resourcePath) {
Gson gson = new Gson();
Type listType = new com.google.gson.reflect.TypeToken<List<BuildingCardDefinition>>(){}.getType();
@@ -80,7 +107,12 @@ public class DecksCreator {
}
}
//TODO javadoc
/**
* Creates and returns the list of slots used as the game board.
* Slots are labeled with the letters A through G.
*
* @return a list of {@link Slot} objects representing the game board.
*/
public static List<Slot> loadSlotDeck()
{
List<Slot> slots = new ArrayList<>();
@@ -90,7 +122,15 @@ public class DecksCreator {
return slots;
}
//TODO javadoc
/**
* Instantiates a {@link TribeCard} from the given definition.
* Depending on whether the card is an event or a character, the appropriate subclass is created
* using the type and parameters specified in the definition.
*
* @param def the {@link TribeCardDefinition} containing the card's type, era, and parameters.
* @return the instantiated {@link TribeCard}.
* @throws IllegalArgumentException if the card type is unknown or the parameters are invalid.
*/
private static TribeCard createCard(TribeCardDefinition def) {
int era = def.era;
@@ -138,7 +178,14 @@ public class DecksCreator {
};
}
//TODO javadoc
/**
* Instantiates a {@link BuildingCard} from the given definition.
* The appropriate subclass is selected based on the effect ID specified in the definition.
* If no specific subclass matches the effect ID, a base {@link BuildingCard} is created.
*
* @param def the {@link BuildingCardDefinition} containing the card's effect ID, era, price, prestige value, and parameters.
* @return the instantiated {@link BuildingCard}.
*/
private static BuildingCard createCard(BuildingCardDefinition def) {
return switch (def.effectId) {
case 0 -> new Building0(def.era, def.price, def.prestigeValue);
@@ -153,7 +200,11 @@ public class DecksCreator {
}
//TODO javadoc
/**
* Internal data class representing the raw definition of a tribe card as loaded from a JSON file.
* Contains the card type, era, whether it is armed, whether it is an event card,
* and a list of additional parameters.
*/
private static class TribeCardDefinition {
String type;
int era;
@@ -162,7 +213,10 @@ public class DecksCreator {
List<Object> params; // Object per gestire boolean e int misti
}
//TODO javadoc
/**
* Internal data class representing the raw definition of a building card as loaded from a JSON file.
* Contains the effect ID, era, price, prestige value, and a list of additional parameters.
*/
private static class BuildingCardDefinition {
int effectId;
int era;
@@ -4,6 +4,9 @@ import it.polimi.ingsw.gc14.Model.Cards.Building.EffectType;
import it.polimi.ingsw.gc14.Model.Cards.BuildingCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Character;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.CharacterType;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Builder;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Inventor;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.EventCard;
import it.polimi.ingsw.gc14.Model.Cards.TribeCards.EventType;
import it.polimi.ingsw.gc14.Model.GamePackage.Board;
@@ -17,7 +20,8 @@ import it.polimi.ingsw.gc14.Model.GamePackage.GameStages;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
import it.polimi.ingsw.gc14.Network.Observer;
import java.util.stream.Stream;
import it.polimi.ingsw.gc14.View.TUI.AsciiTable;
import it.polimi.ingsw.gc14.View.TUI.BorderStyle;
@@ -28,18 +32,6 @@ import it.polimi.ingsw.gc14.View.TUI.BorderStyle;
*/
public class Game implements Serializable {
private transient List<Observer> observers = new ArrayList<>(); // transient! non serializzare
public void addObserver(Observer observer) {
observers.add(observer);
}
private void notifyObservers() {
for (Observer o : observers) {
o.update(this);
}
}
/**
* Returns the list of players participating in the game.
* @return
@@ -49,7 +41,8 @@ public class Game implements Serializable {
}
/**
* The current number of players.
* Returns the current number of players participating in the game.
* @return the current number of players.
*/
public int getCurrentPlayerNumber() {
return playersList.size();
@@ -239,6 +232,16 @@ public class Game implements Serializable {
orderLogicCard=new Order5(playersList);
break;
}
for(Player player : playersList)
{
switch(orderLogicCard.getPosition(player.getUserName()))
{
case 0: player.addFood(2); break;
case 1,2: player.addFood(3); break;
case 3,4: player.addFood(4); break;
}
}
currentState.PlayerUpdate(orderLogicCard.pull(),null);
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
}
@@ -271,6 +274,10 @@ public class Game implements Serializable {
{
return false;
}
if(slotPlayerEntry.getKey().getSlotId()=='A')
{
player.addFood(3);
}
slotMap.put(slotPlayerEntry.getKey(),player);
nextPlayerSetup();
return true;
@@ -295,7 +302,7 @@ public class Game implements Serializable {
public boolean DrawUpperTribeCardByIndex(Player player,int cardIndex) {
if( cardIndex<0 || cardIndex >=board.upperListTribe.size())
return false;
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -318,6 +325,68 @@ public class Game implements Serializable {
return true;
}
/**
* Skips the upper card draw for the specified player when no drawable cards are available.
* The operation succeeds only if the current game stage is {@code RESOLVING_ACTIONS},
* the specified player is the current player, at least one upper draw is still available,
* and there are no drawable upper tribe cards (i.e. all remaining upper tribe cards are event cards)
* and no upper building cards that the player can afford.
* If successful, the upper draw counter is decremented.
* If both upper and lower draws become zero (or no cards remain drawable), the next player setup is triggered.
*
* @param player the player skipping the upper draw.
* @return {@code true} if the skip succeeds, {@code false} otherwise.
*/
public boolean SkipUpperDrawing(Player player) {
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
if(!player.equals(currentState.getCurrentPlayer()))
{
return false;
}
if(currentState.getNUpper() <1)
return false;
if(hasDrawableUp())
return false;
currentState.UpperDrawn();
if((currentState.getNLower() ==0 ||( !hasDrawableDown() && getLowerListBuilding().isEmpty())) && ((currentState.getNUpper() ==0)||(getUpperListBuilding().isEmpty())))
nextPlayerSetup();
return true;
}
/**
* Skips the lower card draw for the specified player when no drawable cards are available.
* The operation succeeds only if the current game stage is {@code RESOLVING_ACTIONS},
* the specified player is the current player, at least one lower draw is still available,
* and there are no drawable lower tribe cards (i.e. all remaining lower tribe cards are event cards)
* and no lower building cards that the player can afford.
* If successful, the lower draw counter is decremented.
* If both upper and lower draws become zero (or no cards remain drawable), the next player setup is triggered.
*
* @param player the player skipping the lower draw.
* @return {@code true} if the skip succeeds, {@code false} otherwise.
*/
public boolean SkipLowerDrawing(Player player) {
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
if(!player.equals(currentState.getCurrentPlayer()))
{
return false;
}
if(currentState.getNLower() <1)
return false;
if(hasDrawableDown())
return false;
currentState.LowerDrawn();
if((currentState.getNLower() ==0 ||( getLowerListBuilding().isEmpty())) && ((currentState.getNUpper() ==0)||(!hasDrawableUp()&&getUpperListBuilding().isEmpty())))
nextPlayerSetup();
return true;
}
/**
* Attempts to draw the lower tribe card at the specified index for the specified player.
* The operation succeeds only if the index is valid, the game stage is {@code RESOLVING_ACTIONS},
@@ -334,7 +403,7 @@ public class Game implements Serializable {
public boolean DrawLowerTribeCardByIndex(Player player, int cardIndex) {
if( cardIndex<0 || cardIndex >=board.lowerListTribe.size())
return false;
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -375,7 +444,7 @@ public class Game implements Serializable {
public boolean DrawUpperBuildingCardByIndex(Player player,int cardIndex) {
if( cardIndex<0 || cardIndex >=board.upperListBuilding.size())
return false;
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -414,7 +483,7 @@ public class Game implements Serializable {
public boolean DrawLowerBuildingCardByIndex(Player player,int cardIndex) {
if( cardIndex<0 || cardIndex >=board.lowerListBuilding.size())
return false;
if(currentState.getGameStage()!= GameStages.RESOLVING_ACTIONS)
if(currentState.getGameStage()!= GameStages.RES_ACTIONS)
{
return false;
}
@@ -459,7 +528,7 @@ public class Game implements Serializable {
* @return {@code true} if the operation succeeds, {@code false} otherwise.
*/
public boolean PickOptionalTribeCardByIndex(Player player,int cardIndex) {
if(currentState.getGameStage() != GameStages.OPTIONAL_CARD_EFFECT){
if(currentState.getGameStage() != GameStages.OPT_CARD_E){
return false;
}
if(!player.equals(currentState.getCurrentPlayer())){
@@ -494,7 +563,7 @@ public class Game implements Serializable {
* @return {@code true} if the operation succeeds, {@code false} otherwise.
*/
public boolean PickOptionalBuildingCard(Player player, int cardIndex) {
if(currentState.getGameStage() != GameStages.OPTIONAL_CARD_EFFECT){
if(currentState.getGameStage() != GameStages.OPT_CARD_E){
return false;
}
if(!player.equals(currentState.getCurrentPlayer())){
@@ -526,7 +595,7 @@ public class Game implements Serializable {
* @return {@code true} if the operation succeeds, {@code false} otherwise.
*/
public boolean NoOptionalCard(Player player) {
if(currentState.getGameStage() != GameStages.OPTIONAL_CARD_EFFECT){
if(currentState.getGameStage() != GameStages.OPT_CARD_E){
return false;
}
if(!player.equals(currentState.getCurrentPlayer())){
@@ -565,11 +634,11 @@ public class Game implements Serializable {
currentState.PlayerUpdate(tempPlayer, null);
return;
}
currentState.GameStageUpdate(GameStages.RESOLVING_ACTIONS);
currentState.GameStageUpdate(GameStages.RES_ACTIONS);
for (Slot s : slotMap.keySet()) {
if (slotMap.get(s) != null) {
currentState.PlayerUpdate(slotMap.get(s), s);
if(!((currentState.getNLower() ==0 ||( getLowerListTribeCards().size()==0 && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||( getUpperListTribeCards().size()==0 && getUpperListBuilding().size()==0))))
if(!((currentState.getNLower() ==0 ||(!hasDrawableDown() && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||(!hasDrawableUp() && getUpperListBuilding().size()==0))))
break;
else
{
@@ -581,13 +650,13 @@ public class Game implements Serializable {
return;
}
if(GameStages.RESOLVING_ACTIONS==currentState.getGameStage()) {
if(GameStages.RES_ACTIONS ==currentState.getGameStage()) {
orderLogicCard.push(currentState.getCurrentPlayer());
slotMap.put(currentState.getSlot(), null);
for (Slot s : slotMap.keySet()) {
if (slotMap.get(s) != null) {
currentState.PlayerUpdate(slotMap.get(s), s);
if((currentState.getNLower() ==0 ||( getLowerListTribeCards().size()==0 && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||( getUpperListTribeCards().size()==0 && getUpperListBuilding().size()==0))) {
if((currentState.getNLower() ==0 ||(!hasDrawableDown() && getLowerListBuilding().size()==0)) && ((currentState.getNUpper() ==0)||( !hasDrawableUp() && getUpperListBuilding().size()==0))) {
orderLogicCard.push(currentState.getCurrentPlayer());
slotMap.put(currentState.getSlot(), null);
@@ -600,9 +669,9 @@ public class Game implements Serializable {
}
if(slotMap.values().stream().allMatch(v -> v == null))
{
currentState.GameStageUpdate(GameStages.OPTIONAL_CARD_EFFECT);
currentState.GameStageUpdate(GameStages.OPT_CARD_E);
HashMap<Player,Integer> optional=new LinkedHashMap<>();
for (Player p : playersList) {
for (Player p : orderLogicCard.players) {
int tempCount=(int)p.buildingCards.stream().filter(x->x.getEffectId()==12).count();
if(tempCount>0)
{
@@ -621,14 +690,13 @@ public class Game implements Serializable {
return;
}
currentState.GameStageUpdate(GameStages.RESOLVING_EVENT);
currentState.GameStageUpdate(GameStages.RES_EVENT);
if (currentState.getRound() < 10) {
nextRound();
currentState.PlayerUpdate(orderLogicCard.pull(), null);
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
} else {
EventResolution();
currentState.GameStageUpdate(GameStages.ENDING);
endGame();
}
@@ -637,7 +705,7 @@ public class Game implements Serializable {
}
}
if (GameStages.OPTIONAL_CARD_EFFECT == currentState.getGameStage()) {
if (GameStages.OPT_CARD_E == currentState.getGameStage()) {
Player optionalPlayer = OptionalCardQueue.poll();
if (optionalPlayer != null) {
@@ -645,23 +713,48 @@ public class Game implements Serializable {
return;
}
currentState.GameStageUpdate(GameStages.RESOLVING_EVENT);
currentState.GameStageUpdate(GameStages.RES_EVENT);
if (currentState.getRound() < 10) {
nextRound();
currentState.PlayerUpdate(orderLogicCard.pull(), null);
currentState.GameStageUpdate(GameStages.SLOT_CHOICE);
} else {
EventResolution();
currentState.GameStageUpdate(GameStages.ENDING);
endGame();
}
return;
/**
* Checks whether there are any drawable lower tribe cards on the board,
* i.e. lower tribe cards that are not event cards.
*
* @return {@code true} if at least one non-event lower tribe card is available, {@code false} otherwise.
*/
}
}
/**
* Checks whether there are any drawable upper tribe cards on the board,
* i.e. upper tribe cards that are not event cards.
*
* @return {@code true} if at least one non-event upper tribe card is available, {@code false} otherwise.
*/
private boolean hasDrawableUp()
{
return getUpperListTribeCards().stream().filter(x-> !x.IsEventCard()).count()!=0;
}
/**
* Checks whether there are any drawable lower tribe cards on the board,
* i.e. lower tribe cards that are not event cards.
*
* @return {@code true} if at least one non-event lower tribe card is available, {@code false} otherwise.
*/
private boolean hasDrawableDown()
{
return getLowerListTribeCards().stream().filter(x-> !x.IsEventCard()).count()!=0;
}
/**
* Resolves all pending event cards if the current game stage is {@code RESOLVING_EVENT}.
* All pending events are activated on the player list.
@@ -669,7 +762,7 @@ public class Game implements Serializable {
*/
private void EventResolution() {
if(currentState.getGameStage()!= GameStages.RESOLVING_EVENT)
if(currentState.getGameStage()!= GameStages.RES_EVENT)
{
return;
}
@@ -719,6 +812,28 @@ public class Game implements Serializable {
* and updating the game stage to {@code ENDED}.
*/
private void endGame() {
Queue<EventCard> events;
events=Stream.concat(board.lowerListTribe.stream().filter(TribeCard::IsEventCard),board.upperListTribe.stream().filter(TribeCard::IsEventCard)).map(x->((EventCard)x)).collect(Collectors.toCollection(LinkedList::new));
ArrayList<EventCard>sustenance=events.stream().filter(x->x.getType().equals(EventType.SUSTENANCE)).collect(Collectors.toCollection(ArrayList::new));
events.removeAll(sustenance);
events.forEach(event->event.activateEvent(playersList));
sustenance.forEach(event->event.activateEvent(playersList));
playersList.forEach(p->{
int temp= p.builders.stream().mapToInt(Builder::getPrestigeValue).sum();
p.addPrestige(temp);
});
playersList.forEach(p->{
int temp=(int) p.inventors.stream().mapToInt(Inventor::Icon).distinct().count();
p.addPrestige(temp*p.getNType(CharacterType.INVENTOR));
});
playersList.forEach(p->{
p.addPrestige(10 * (p.getNType(CharacterType.ARTIST)/2));
});
playersList.forEach(p->{
int temp= p.buildingCards.stream().mapToInt(BuildingCard::getPrestigeValue).sum();
p.addPrestige(temp);
});
playersList.forEach(
p -> p.buildingCards.stream().filter(x -> x.getEffectType() == EffectType.FINAL).
forEach(x -> x.applyEffect(p))
@@ -772,6 +887,14 @@ public class Game implements Serializable {
public String toString() {
return PlayersStamp()+"\n"+BoardStamp()+"\n";
}
/**
* Returns a string representation of all the players currently in the game,
* arranged side by side in pairs.
* If the number of players is odd, the last player is printed on its own line.
*
* @return {@code String} - a string representation of all the players.
*/
public String PlayersStamp()
{
StringBuilder stringBuilder=new StringBuilder();
@@ -787,15 +910,24 @@ public class Game implements Serializable {
}
return stringBuilder.toString();
}
/**
* Returns a string representation of the board, including the current state,
* the offer track with slot assignments, the upper and lower tribe card lists,
* and the upper and lower building card lists.
*
* @return {@code String} - a string representation of the board.
*/
public String BoardStamp()
{
var offerTrack = new AsciiTable(BorderStyle.UNICODE, slotMap.size());
List<String> stringUpOffer=new ArrayList<>();
List<String> stringDownOffer=new ArrayList<>();
int index=0;
for(Map.Entry<Slot,Player> entry:slotMap.entrySet())
{
stringDownOffer.add(entry.getKey().toStringTUI());
stringDownOffer.add((index++)+"."+entry.getKey().toStringTUI());
if(entry.getValue()!=null)
stringUpOffer.add(entry.getValue().getUserName());
else
@@ -813,11 +945,11 @@ public class Game implements Serializable {
{
if(i<getUpperListTribeCards().size())
{
stringUpperListTribe.add(getUpperListTribeCards().get(i).toStringBoard());
stringUpperListTribe.add(i+"-"+getUpperListTribeCards().get(i).toStringBoard());
}
if(i<getLowerListTribeCards().size())
{
stringLowerListTribe.add(getLowerListTribeCards().get(i).toStringBoard());
stringLowerListTribe.add(i+"-"+getLowerListTribeCards().get(i).toStringBoard());
}
}
var BuildTableUpper = new AsciiTable(BorderStyle.UNICODE,1);
@@ -829,11 +961,11 @@ public class Game implements Serializable {
{
if(i<getUpperListBuilding().size())
{
BuildTableUpper.addRow(getUpperListBuilding().get(i).toString());
BuildTableUpper.addRow(i+"-"+getUpperListBuilding().get(i).toString());
}
if(i<getLowerListBuilding().size())
{
BuildTableLower.addRow(getLowerListBuilding().get(i).toString());
BuildTableLower.addRow(i+"-"+getLowerListBuilding().get(i).toString());
}
}
stringUpperListTribe.forEach(x->TribeTableUpper.addRow(x));
@@ -41,6 +41,8 @@ public class Board implements Serializable {
/** Contains all the building cards of the upper list. When a new era starts, the old era's buildings are moved from the upper to the lower list */
public List<BuildingCard> lowerListBuilding;
private final ArrayList<List<BuildingCard>> buildingCardsAllEras;
/** Number of players */
private int nTotem;
@@ -88,6 +90,7 @@ public class Board implements Serializable {
tribeDeck=generateTribeDeck(nTotem);
era=1;
for(int i=0;i<nTotem+1;i++)
{
TribeCard tempCard = tribeDeck.remove();
@@ -110,10 +113,44 @@ public class Board implements Serializable {
ArrayList<BuildingCard> buildingDeck = new ArrayList<>(DecksCreator.loadBuildingDeckByEra(1));
Collections.shuffle(buildingDeck);
buildingCardsAllEras= new ArrayList<>();
buildingCardsAllEras.add(new ArrayList<>());
buildingCardsAllEras.add(new ArrayList<>());
buildingCardsAllEras.add(new ArrayList<>());
if(nTotem==2)
{
buildingCardsAllEras.set(0, new ArrayList<>(buildingDeck.subList(0, 1)));
upperListBuilding = new ArrayList<>(buildingDeck.subList(0,1));
}
else
{
buildingCardsAllEras.set(0, new ArrayList<>(buildingDeck.subList(0, 2)));
upperListBuilding = new ArrayList<>(buildingDeck.subList(0,2));
}
buildingDeck=new ArrayList<>(DecksCreator.loadBuildingDeckByEra(2));
Collections.shuffle(buildingDeck);
if(nTotem<=3)
{
buildingCardsAllEras.set(1, new ArrayList<BuildingCard>(buildingDeck.subList(0, 2)));
}
else
{
buildingCardsAllEras.set(1, new ArrayList<BuildingCard>(buildingDeck.subList(0, 3)));
}
buildingDeck=new ArrayList<>(DecksCreator.loadBuildingDeckByEra(3));
Collections.shuffle(buildingDeck);
if(nTotem==2)
{
buildingCardsAllEras.set(2, new ArrayList<BuildingCard>(buildingDeck.subList(0, 3)));
}else if(nTotem==5)
{
buildingCardsAllEras.set(2, new ArrayList<BuildingCard>(buildingDeck.subList(0, 5)));
}
else {
buildingCardsAllEras.set(2, new ArrayList<BuildingCard>(buildingDeck.subList(0, 4)));
}
}
/**
@@ -230,27 +267,11 @@ public class Board implements Serializable {
Collections.shuffle(buildingCards);
if(era==2)
{
if(nTotem<=3)
{
upperListBuilding.addAll(buildingCards.subList(0,2));
}
else
{
upperListBuilding.addAll( buildingCards.subList(0,3));
}
upperListBuilding.addAll(buildingCardsAllEras.get(1));
}
else // Era 3
else
{
if(nTotem==2)
{
upperListBuilding.addAll( buildingCards.subList(0,3));
}else if(nTotem==5)
{
upperListBuilding.addAll( buildingCards.subList(0,5));
}
else {
upperListBuilding.addAll(buildingCards.subList(0,4));
}
upperListBuilding.addAll(buildingCardsAllEras.get(2));
}
}
}
@@ -1,5 +1,5 @@
package it.polimi.ingsw.gc14.Model.GamePackage;
public enum GameStages {
WAITING,SLOT_CHOICE, RESOLVING_ACTIONS, OPTIONAL_CARD_EFFECT, RESOLVING_EVENT,ENDING,ENDED
WAITING, SLOT_CHOICE, RES_ACTIONS, OPT_CARD_E, RES_EVENT, ENDING, ENDED
}
@@ -52,30 +52,29 @@ public class Order2 extends OrderLogicCard {
}
}
}
/**
* Creates the TURN ORDER box of the TUI.
* @return the string containing the box
*/
@Override
public String toString()
{
var table = new AsciiTable(BorderStyle.UNICODE, 2);
List<String> stringUp=new ArrayList<>();
List<String> stringDown=new ArrayList<>();
for(int i=0;i<2;i++)
{
try {
playerList.get(i);
stringUp.add(i+". "+playerList.get(i).player.getUserName());
if(playerList.get(i).played)
stringDown.add(" Placed");
stringUp.add(" ");
else
stringDown.add(" Not Placed");
stringUp.add(i+". "+playerList.get(i).player.getUserName());
}
catch (IndexOutOfBoundsException e) {
stringUp.add("");
stringDown.add("");
}
}
table.addRow(stringUp);
table.addRow(stringDown);
List<String> stringList=new ArrayList<>();
stringList.add("+1 Food");
@@ -53,6 +53,11 @@ public class Order3 extends OrderLogicCard {
}
}
}
/**
* Creates the TURN ORDER box of the TUI.
* @return the string containing the box
*/
@Override
public String toString()
{
@@ -60,24 +65,19 @@ public class Order3 extends OrderLogicCard {
var table = new AsciiTable(BorderStyle.UNICODE, 3);
List<String> stringUp=new ArrayList<>();
List<String> stringDown=new ArrayList<>();
for(int i=0;i<3;i++)
{
try {
playerList.get(i);
stringUp.add(i+". "+playerList.get(i).player.getUserName());
if(playerList.get(i).played)
stringDown.add(" Placed");
stringUp.add(" ");
else
stringDown.add(" Not Placed");
stringUp.add(i+". "+playerList.get(i).player.getUserName());
}
catch (IndexOutOfBoundsException e) {
stringUp.add("");
stringDown.add("");
}
}
table.addRow(stringUp);
table.addRow(stringDown);
List<String> stringList=new ArrayList<>();
@@ -60,30 +60,30 @@ public class Order4 extends OrderLogicCard {
}
}
}
/**
* Creates the TURN ORDER box of the TUI.
* @return the string containing the box
*/
@Override
public String toString()
{
var table = new AsciiTable(BorderStyle.UNICODE, 4);
List<String> stringUp=new ArrayList<>();
List<String> stringDown=new ArrayList<>();
for(int i=0;i<4;i++)
{
try {
playerList.get(i);
stringUp.add(i+". "+playerList.get(i).player.getUserName());
if(playerList.get(i).played)
stringDown.add(" Placed");
stringUp.add(" ");
else
stringDown.add(" Not Placed");
stringUp.add(i+". "+playerList.get(i).player.getUserName());
}
catch (IndexOutOfBoundsException e) {
stringUp.add("");
stringDown.add("");
}
}
table.addRow(stringUp);
table.addRow(stringDown);
List<String> stringList=new ArrayList<>();
stringList.add("+2 Food");
@@ -61,30 +61,30 @@ public class Order5 extends OrderLogicCard {
}
}
}
/**
* Creates the TURN ORDER box of the TUI.
* @return the string containing the box
*/
@Override
public String toString()
{
var table = new AsciiTable(BorderStyle.UNICODE, 5);
List<String> stringUp=new ArrayList<>();
List<String> stringDown=new ArrayList<>();
for(int i=0;i<5;i++)
{
try {
playerList.get(i);
stringUp.add(i+". "+playerList.get(i).player.getUserName());
if(playerList.get(i).played)
stringDown.add(" Placed");
stringUp.add(" ");
else
stringDown.add(" Not Placed");
stringUp.add(i+". "+playerList.get(i).player.getUserName());
}
catch (IndexOutOfBoundsException e) {
stringUp.add("");
stringDown.add("");
}
}
table.addRow(stringUp);
table.addRow(stringDown);
List<String> stringList=new ArrayList<>();
stringList.add("+3 Food");
@@ -17,6 +17,10 @@ public class OrderPlayer implements Serializable {
this.player=player;
this.played=played;
}
/**
* @return the string containing the username and whether it played or not.
*/
@Override
public String toString() {
return player.getUserName()+" "+played;
@@ -172,7 +172,7 @@ public class Slot implements Serializable {
public String toStringTUI()
{
StringBuilder s = new StringBuilder();
s.append(this.getSlotId()+" ");
//s.append(this.getSlotId()+" ");
for(int i=0;i<this.getNUpper();i++)
{
s.append("");
@@ -8,5 +8,8 @@ public enum EventType {
DRAW_UPPER_BUILD,
DRAW_LOWER_BUILD,
PICK_OPTIONAL_TRIBE,
PICK_OPTIONAL_BUILD
PICK_OPTIONAL_BUILD,
SKIP_UPPER,
SKIP_LOWER,
NO_OPTIONAL_CARD
}
@@ -4,39 +4,60 @@ import it.polimi.ingsw.gc14.Controller.GameController;
import java.io.Serializable;
//TODO javadoc
/**
* Represents an event sent over the network
*/
public abstract class NetworkEvent implements Serializable {
//TODO javadoc
/** Username of the player requesting the event */
protected String username;
//TODO javadoc
/**
* @return the username of the player requesting the event
*/
public String getUsername() {
return username;
}
//TODO javadoc
/** EventType of the event */
protected EventType eventType;
//TODO javadoc
/**
* @return the type of the event
*/
public EventType getEventType() {return eventType;}
//TODO javadoc
/** Flag signaling whether the event could not be applied to the server model */
protected boolean isError;
//TODO javadoc
/**
* @return the flag signaling whether the event could be applied to the server model
*/
public boolean getIsError() {return isError;}
//TODO javadoc
/**
* Set the isError flag.
* @param isError the value to set
*/
public void setIsError(boolean isError) {this.isError = isError;}
//TODO javadoc
/**
* Class constructor.
* Initializes all attributes.
* @param username the username of the player requesting the event
* @param eventType the type of the event
* @param isError the flag signaling if the event could be applied to the server model
*/
protected NetworkEvent(String username, EventType eventType, boolean isError) {
this.username = username;
this.eventType = eventType;
this.isError = isError;
}
//TODO javadoc
/**
* @return a string describing the name of the event and whether it is an error or not
*/
@Override
public String toString() {
if(isError) {
@@ -46,6 +67,10 @@ public abstract class NetworkEvent implements Serializable {
}
}
//TODO javadoc
/**
* The method to apply the current event to the specified Game Controller.
* @param gameController the Game Controller on which to apply the event
* @return true if the event could be applied; false otherwise
*/
public abstract boolean apply(GameController gameController);
}
@@ -7,30 +7,38 @@ import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
//TODO javadoc
/**
* NetworkEvent to add a player.
*/
public class AddPlayer extends NetworkEvent implements Serializable {
//TODO javadoc
/** Number of proposed players to add to the match */
private int proposedNPlayer;
//TODO javadoc
/**
* @return the number of proposed players to add to the match
*/
public int getProposedNPlayer() {
return proposedNPlayer;
}
//TODO javadoc
/**
* Class constructor.
* Initializes all the attributes.
* @param username the name of the player requesting the event
* @param proposedNPlayer the number of proposed players to add to the match
*/
public AddPlayer(String username, int proposedNPlayer) {
super(username, EventType.ADD_PLAYER, false);
this.proposedNPlayer = proposedNPlayer;
}
//TODO javadoc
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could be added to the match, false otherwise
*/
@Override
public boolean apply(GameController gameController)
{
return gameController.addPlayer(username);
}
public String apply(IView gameController)
{
return gameController.toString();
}
}
@@ -7,25 +7,31 @@ import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
//TODO javadoc
/**
* NetworkEvent to draw a building card from the lower card list.
*/
public class DrawLowerBuildingCard extends NetworkEvent implements Serializable{
//TODO javadoc
/** Index of the card to draw */
private int pos;
//TODO javadoc
/**
* Class constructor.
* Initialized all the attributes.
* @param username the name of the player requesting the event
* @param pos the index of the card to draw
*/
public DrawLowerBuildingCard(String username, int pos){
super(username, EventType.DRAW_LOWER_BUILD, false);
this.pos = pos;
}
//TODO javadoc
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController){
return gameController.drawLowerBuildingCard(username, pos);
}
//TODO javadoc
public String apply(IView gameController){
return gameController.toString();
}
}
@@ -7,24 +7,32 @@ import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
/**
* NetworkEvent to draw a tribe card from the lower card list.
*/
public class DrawLowerTribeCard extends NetworkEvent implements Serializable{
//TODO javadoc
/** Index of the card to draw */
private int pos;
//TODO javadoc
/**
* Class constructor.
* Initialized all the attributes.
* @param username the name of the player requesting the event
* @param pos the index of the card to draw
*/
public DrawLowerTribeCard(String username, int pos){
super(username, EventType.DRAW_LOWER_TRIBE, false);
this.pos = pos;
}
//TODO javadoc
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController){
return gameController.drawLowerTribeCard(username, pos);
}
//TODO javadoc
public String apply(IView gameController){
return gameController.toString();
}
}
@@ -7,25 +7,32 @@ import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
//TODO javadoc
/**
* NetworkEvent to draw a building card from the upper card list.
*/
public class DrawUpperBuildingCard extends NetworkEvent implements Serializable{
//TODO javadoc
/** Index of the card to draw */
private int pos;
//TODO javadoc
/**
* Class constructor.
* Initialized all the attributes.
* @param username the name of the player requesting the event
* @param pos the index of the card to draw
*/
public DrawUpperBuildingCard(String username, int pos){
super(username, EventType.DRAW_UPPER_BUILD, false);
this.pos = pos;
}
//TODO javadoc
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController){
return gameController.drawUpperBuildingCard(username, pos);
}
//TODO javadoc
public String apply(IView gameController){
return gameController.toString();
}
}
@@ -7,25 +7,33 @@ import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
//TODO javadoc
/**
* NetworkEvent to draw a tribe card from the upper card list.
*/
public class DrawUpperTribeCard extends NetworkEvent implements Serializable{
//TODO javadoc
/** Index of the card to draw */
private int pos;
//TODO javadoc
/**
* Class constructor.
* Initialized all the attributes.
* @param username the name of the player requesting the event
* @param pos the index of the card to draw
*/
public DrawUpperTribeCard(String username, int pos){
super(username, EventType.DRAW_UPPER_TRIBE, false);
this.pos = pos;
}
//TODO javadoc
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController){
return gameController.drawUpperTribeCard(username, pos);
}
//TODO javadoc
public String apply(IView gameController){
return gameController.toString();
}
}
@@ -0,0 +1,32 @@
package it.polimi.ingsw.gc14.Network.NetworkEvents;
import it.polimi.ingsw.gc14.Controller.GameController;
import it.polimi.ingsw.gc14.Network.EventType;
import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
/**
* NetworkEvent to avoid drawing a card from the upper list (see the effect of Building 12)
*/
public class NoOptionalCard extends NetworkEvent implements Serializable{
/**
* Class constructor.
* Initialized all the attributes.
* @param username the name of the player requesting the event
*/
public NoOptionalCard(String username){
super(username, EventType.NO_OPTIONAL_CARD, false);
}
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController){
return gameController.noOptionalCard(username);
}
}
@@ -7,25 +7,31 @@ import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
//TODO javadoc
/**
* NetworkEvent to draw a building card from the upper list (see the effect of Building 12)
*/
public class PickOptionalBuildingCard extends NetworkEvent implements Serializable{
//TODO javadoc
/** Index of the card to draw */
private int pos;
//TODO javadoc
/**
* Class constructor.
* Initialized all the attributes.
* @param username the name of the player requesting the event
* @param pos the index of the card to draw
*/
public PickOptionalBuildingCard(String username, int pos){
super(username, EventType.PICK_OPTIONAL_BUILD, false);
this.pos = pos;
}
//TODO javadoc
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController){
return gameController.pickOptionalBuildingCard(username, pos);
}
//TODO javadoc
public String apply(IView gameController){
return gameController.toString();
}
}
@@ -7,26 +7,32 @@ import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
//TODO javadoc
/**
* NetworkEvent to draw a tribe card from the upper list (see the effect of Building 12)
*/
public class PickOptionalTribeCard extends NetworkEvent implements Serializable{
//TODO javadoc
/** Index of the card to draw */
private int pos;
//TODO javadoc
/**
* Class constructor.
* Initialized all the attributes.
* @param username the name of the player requesting the event
* @param pos the index of the card to draw
*/
public PickOptionalTribeCard(String username, int pos){
super(username, EventType.PICK_OPTIONAL_TRIBE, false);
this.pos = pos;
}
//TODO javadoc
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController){
return gameController.pickOptionalTribeCard(username, pos);
}
//TODO javadoc
public String apply(IView gameController){
return gameController.toString();
}
}
@@ -0,0 +1,33 @@
package it.polimi.ingsw.gc14.Network.NetworkEvents;
import it.polimi.ingsw.gc14.Controller.GameController;
import it.polimi.ingsw.gc14.Network.EventType;
import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
/**
* NetworkEvent to avoid drawing a card from the lower card list
*/
public class SkipLower extends NetworkEvent implements Serializable{
/**
* Class constructor.
* Initializes all the attributes.
* @param username the name of the player requesting the event
*/
public SkipLower(String username){
super(username, EventType.SKIP_LOWER, false);
}
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController){
return gameController.SkipLowerDrawing(username);
}
}
@@ -0,0 +1,33 @@
package it.polimi.ingsw.gc14.Network.NetworkEvents;
import it.polimi.ingsw.gc14.Controller.GameController;
import it.polimi.ingsw.gc14.Network.EventType;
import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
/**
* NetworkEvent to avoid drawing a card from the upper card list
*/
public class SkipUpper extends NetworkEvent implements Serializable{
/**
* Class constructor.
* Initializes all the attributes.
* @param username the name of the player requesting the event
*/
public SkipUpper(String username){
super(username, EventType.SKIP_UPPER, false);
}
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController){
return gameController.SkipUpperDrawing(username);
}
}
@@ -7,25 +7,32 @@ import it.polimi.ingsw.gc14.View.IView;
import java.io.Serializable;
//TODO javadoc
/**
* NetworkEvent to select a slot where to place the player totem.
*/
public class SlotChoice extends NetworkEvent implements Serializable {
//TODO javadoc
/** Index of the card to draw */
private int pos;
//TODO javadoc
/**
* Class constructor.
* Initializes all the attributes.
* @param username the name of the player requesting the event
* @param pos the index of the card to draw
*/
public SlotChoice(String username, int pos) {
super(username, EventType.SLOT_CHOICE, false);
this.pos = pos;
}
//TODO javadoc
/**
* @param gameController the Game Controller on which to apply the event
* @return true if the player could draw the card, false otherwise
*/
@Override
public boolean apply(GameController gameController) {
return gameController.slotChoice(username, pos);
}
//TODO javadoc
public String apply(IView gameController) {
return gameController.toString();
}
}
@@ -1,7 +0,0 @@
package it.polimi.ingsw.gc14.Network;
import it.polimi.ingsw.gc14.Model.Game;
public interface Observer {
public void update(Game model);
}
@@ -8,6 +8,7 @@ import it.polimi.ingsw.gc14.Network.IClient;
import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.RMI.Common.IClientCallback;
import it.polimi.ingsw.gc14.Network.RMI.Common.IGameServer;
import it.polimi.ingsw.gc14.Network.RMI.Server.RMIServer;
/**
* Client RMI. Uses the methods exposed by the server RMI.
@@ -39,7 +40,7 @@ public class RMIClient implements IClient {
this.port = port;
}
//TODO Javadoc fix
/**
* Connects to the RMI server and attempts to join the game.
* Looks up the RMI registry to retrieve the {@link IGameServer} stub.
@@ -90,6 +90,7 @@ public class RMIServer extends UnicastRemoteObject implements IGameServer {
if (controller.addPlayer(username)) {
clients.put(username, callback);
playerList.add(username);
System.out.println("Accepted player: " + username);
return true;
}
return false;
@@ -87,7 +87,14 @@ public class TCPClient implements IClient {
private void receiveMessage() {
while (true) {
try {
Object read = socketReceive.readObject();
Object read;
try {
read = socketReceive.readObject();
} catch (IOException e) {
e.printStackTrace();
break;
}
if (read instanceof NetworkEvent event) { //TODO: avoid instanceof
if (event.getIsError()) {
System.out.println(event);
@@ -99,10 +106,9 @@ public class TCPClient implements IClient {
controller.setModel(model);
controller.view.render();
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
e.printStackTrace();
break;
}
}
}
@@ -7,6 +7,7 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent;
import it.polimi.ingsw.gc14.Network.NetworkEvents.AddPlayer;
import it.polimi.ingsw.gc14.Network.RMI.Server.RMIServer;
import it.polimi.ingsw.gc14.Network.TCP.Server.TCPServer;
import it.polimi.ingsw.gc14.View.TUI.TUI;
import java.rmi.RemoteException;
import java.util.concurrent.BlockingQueue;
@@ -56,6 +57,8 @@ public class ServerLauncher {
*/
static LimitedList<String> playerList;
TUI view;
/**
* Class constructor that initializes the attributes.
@@ -137,11 +140,14 @@ public class ServerLauncher {
System.out.println("\n\nNotifying model");
serverRMI.notifyAll(gameController.getModel());
serverTCP.notifyAll(gameController.getModel());
this.view = new TUI(gameController.getModel());
this.view.fullRender();
// Game execution
while (true) {
try {
this.doFirstEvent();
this.view.fullRender();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
@@ -29,7 +29,6 @@ public class AsciiTable {
//TODO javadoc
public void addHeader(String... cells) { rows.add(0, Arrays.asList(cells)); separators.add(0); }
public void addSeparator() { separators.add(rows.size()-1); }
//TODO javadoc
public void addSeparator() { separators.add(rows.size()-1); }
@@ -1,9 +1,11 @@
package it.polimi.ingsw.gc14.View.TUI;
public enum BorderStyle {
UNICODE("","","","","","","","","","","","","","",""),
ASCII ("+","+","+","+","-","|","+","+","+","+","+","+","+","-","+"),
ROUNDED("","","","","","","","","","","","","","","");
//UNICODE("","","","","","","","","","","","","","",""),
UNICODE ("+","+","+","+","-","|","+","+","+","+","+","+","+","-","+"),
ROUNDED ("+","+","+","+","-","|","+","+","+","+","+","+","+","-","+");
//ROUNDED("","","","","","","","","","","","","","","");
private final String tl,tr,bl,br,h,v,ml,mr,mt,mb,x,sl,sr,sh,sx;
@@ -2,6 +2,8 @@ package it.polimi.ingsw.gc14.View.TUI;
import it.polimi.ingsw.gc14.Model.Game;
import it.polimi.ingsw.gc14.View.IView;
import java.util.List;
public class TUI implements IView {
// dati di stato
@@ -23,6 +25,10 @@ public class TUI implements IView {
// punto di ingresso
public void render()
{
renderBoard();
}
public void fullRender()
{
try{
String os = System.getProperty("os.name").toLowerCase();
@@ -36,7 +42,10 @@ public class TUI implements IView {
}
catch(Exception e){
}
System.out.println(model.toString());
List<String>lines=List.of(model.BoardStamp().split("\n"));
List<String> lines2=List.of((PrintMenuOptions()+"\n"+model.getPlayerByUsername(username)).split("\n"));
System.out.println(model.PlayersStamp()+"\n"+ AsciiTable.sideBySide(lines,lines2,3));
}
public void renderBoard()
@@ -53,7 +62,9 @@ public class TUI implements IView {
}
catch(Exception e){
}
System.out.println(model.BoardStamp());
List<String>lines=List.of(model.BoardStamp().split("\n"));
List<String> lines2=List.of((PrintMenuOptions()+"\nYOUR HAND\n"+model.getPlayerByUsername(username)).split("\n"));
System.out.println(AsciiTable.sideBySide(lines,lines2,3));
}
public void renderPlayer()
{
@@ -69,25 +80,10 @@ public class TUI implements IView {
}
catch(Exception e){
}
System.out.println(model.BoardStamp());
List<String>lines=List.of(model.PlayersStamp().split("\n"));
List<String> lines2=List.of(PrintMenuOptions().split("\n"));
System.out.println(AsciiTable.sideBySide(lines,lines2,3));
}
public void renderMyHand()
{
try{
String os = System.getProperty("os.name").toLowerCase();
ProcessBuilder pb;
if (os.contains("win")) {
pb = new ProcessBuilder("cmd", "/c", "cls");
} else {
pb = new ProcessBuilder("clear");
}
pb.inheritIO().start().waitFor();
}
catch(Exception e){
}
System.out.println(model.getPlayerByUsername(username));
}
public void showMessage(String message)
{
@@ -100,4 +96,21 @@ public class TUI implements IView {
System.out.println(message);
}
private String PrintMenuOptions()
{
var table=new AsciiTable(BorderStyle.ROUNDED,2);
table.addHeader( "Menu Options","Render Options");
table.addRow( List.of("0-SlotChoice(pos)","A-Full Render"));
table.addRow(List.of("1-DrawUpperTribe(pos)","B-Board Render"));
table.addRow(List.of("2-DrawUpperBuilding(pos)","C-Players Render"));
table.addRow(List.of("3-DrawLowerTribe(pos)",""));
table.addRow(List.of("4-DrawLowerBuilding(pos)",""));
table.addRow(List.of("5-PickOptionalTribe(pos)",""));
table.addRow(List.of("6-PickOptionalBuilding(pos)",""));
table.addRow(List.of("7-NoOptional",""));
table.addRow(List.of("8-NoUpperCard",""));
table.addRow(List.of("9-NoLowerCard",""));
return table.build();
}
}