From df9bd77754bd0fece93badd9ed3075f21e634215 Mon Sep 17 00:00:00 2001 From: AleandroPagani Date: Sat, 2 May 2026 19:04:43 +0200 Subject: [PATCH 01/13] Fix: JavaDOC to Game --- .../polimi/ingsw/gc14/Model/DecksCreator.java | 76 ++++++++++++++++--- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/DecksCreator.java b/src/main/java/it/polimi/ingsw/gc14/Model/DecksCreator.java index 4b7388a..971b545 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/DecksCreator.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/DecksCreator.java @@ -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 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 loadTribeDeck(String resourcePath) { Gson gson = new Gson(); Type listType = new com.google.gson.reflect.TypeToken>(){}.getType(); @@ -51,14 +66,26 @@ public class DecksCreator { } } - //TODO javadoc - public static List 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 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 loadBuildingDeck(String resourcePath) { Gson gson = new Gson(); Type listType = new com.google.gson.reflect.TypeToken>(){}.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 loadSlotDeck() { List 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 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; From dc18a650780913cc2a7dba88423b90a7ec171259 Mon Sep 17 00:00:00 2001 From: AleandroPagani Date: Sat, 2 May 2026 19:05:51 +0200 Subject: [PATCH 02/13] Microfix: add break in TCP client if connection fails --- .../it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java index 3408e99..f3a34e2 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java @@ -99,10 +99,9 @@ public class TCPClient implements IClient { controller.setModel(model); controller.view.render(); } - } catch (IOException e) { + } catch (Exception e) { e.printStackTrace(); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); + break; } } } From 4a69e2c8dbd4ff732fce105f8041f19a840b2bb0 Mon Sep 17 00:00:00 2001 From: AleandroPagani Date: Sat, 2 May 2026 19:12:47 +0200 Subject: [PATCH 03/13] Add: JavaDOC to LimitedList --- .../it/polimi/ingsw/gc14/LimitedList.java | 58 +++++++++++++++---- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/LimitedList.java b/src/main/java/it/polimi/ingsw/gc14/LimitedList.java index ad351d0..5ac39ff 100644 --- a/src/main/java/it/polimi/ingsw/gc14/LimitedList.java +++ b/src/main/java/it/polimi/ingsw/gc14/LimitedList.java @@ -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 the type of elements held in this list. + */ public class LimitedList extends ArrayList { - //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 extends ArrayList { 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; } } \ No newline at end of file From 4fdb99167eef6ed0df4d6be1d76beb845e7562e2 Mon Sep 17 00:00:00 2001 From: AleandroPagani Date: Sat, 2 May 2026 19:22:12 +0200 Subject: [PATCH 04/13] Add: JavaDOC to ClientLauncherTUI --- .../polimi/ingsw/gc14/ClientLauncherTUI.java | 91 ++++++++++++------- .../gc14/Network/RMI/Client/RMIClient.java | 2 +- 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/ClientLauncherTUI.java b/src/main/java/it/polimi/ingsw/gc14/ClientLauncherTUI.java index 6d2d854..03a7a6a 100644 --- a/src/main/java/it/polimi/ingsw/gc14/ClientLauncherTUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/ClientLauncherTUI.java @@ -4,16 +4,32 @@ import it.polimi.ingsw.gc14.Network.NetworkEvent; 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.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 - TUI view; - public void main() throws InterruptedException { - view=new TUI(null); - ClientController controller = new ClientController(view); + /** + * 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 { + view = new TUI(null); + ClientController controller = new ClientController(view); Scanner scanner = new Scanner(System.in); System.out.println("Selezionare nome utente: "); String username = scanner.next(); @@ -22,9 +38,6 @@ public class ClientLauncherTUI { int proposedNumPlayers = scanner.nextInt(); System.out.println("Selezionare RMI[0] o TCP[1]: "); int networkType = scanner.nextInt(); - - - // RMI if (networkType == 0) { // Connect @@ -36,17 +49,10 @@ 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); @@ -57,33 +63,53 @@ 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. + *

+ * Available actions: + *

    + *
  • {@code 0} - Choose a slot by index.
  • + *
  • {@code 1} - Draw an upper building card by index.
  • + *
  • {@code 2} - Draw an upper tribe card by index.
  • + *
  • {@code 3} - Draw a lower building card by index.
  • + *
  • {@code 4} - Draw a lower tribe card by index.
  • + *
  • {@code 5} - Pick an optional tribe card by index.
  • + *
  • {@code 6} - Pick an optional building card by index.
  • + *
  • {@code 7} - Skip the optional card choice.
  • + *
  • {@code 8} - Skip the upper draw.
  • + *
  • {@code 9} - Skip the lower draw.
  • + *
  • {@code A} - Render the full game view.
  • + *
  • {@code B} - Render the board view.
  • + *
  • {@code C} - Render the player view.
  • + *
+ * + * @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) { String action = scanner.next(); - int pos=-1; - if(!action.equals("7")&&!action.equals("8")&&!action.equals("9")&&!action.equals("A")&&!action.equals("B")&&!action.equals("C")) { - try - { + int pos = -1; + 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) - { + } catch (Exception e) { System.out.println("ERROR: Invalid input(expected number)"); } } - switch(action) { + switch (action) { case "0" -> controller.slotChoice(username, pos); case "1" -> controller.drawUpperBuildingCard(username, pos); case "2" -> controller.drawUpperTribeCard(username, pos); @@ -97,8 +123,7 @@ public class ClientLauncherTUI { case "A" -> view.fullRender(); case "B" -> view.renderBoard(); case "C" -> view.renderPlayer(); + default -> {} } - - return; } } \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/RMIClient.java b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/RMIClient.java index 5cdbf37..be92164 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/RMIClient.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/RMI/Client/RMIClient.java @@ -40,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. From fc15a3a15b24175d21d0d235466bda4f045f9bf6 Mon Sep 17 00:00:00 2001 From: AleandroPagani Date: Sat, 2 May 2026 19:35:03 +0200 Subject: [PATCH 05/13] Fix: error managing in TCP client --- .../ingsw/gc14/Network/TCP/Client/TCPClient.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java index f3a34e2..cfcee1e 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java +++ b/src/main/java/it/polimi/ingsw/gc14/Network/TCP/Client/TCPClient.java @@ -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,7 +106,7 @@ public class TCPClient implements IClient { controller.setModel(model); controller.view.render(); } - } catch (Exception e) { + } catch (ClassNotFoundException e) { e.printStackTrace(); break; } From 4afe4b25b9805336965e35118a70e6a10cd413ef Mon Sep 17 00:00:00 2001 From: rubenpirreram Date: Sat, 2 May 2026 19:44:34 +0200 Subject: [PATCH 06/13] Fix:EndGame #2 --- .idea/inspectionProfiles/Project_Default.xml | 6 ++++++ src/main/java/it/polimi/ingsw/gc14/Model/Game.java | 12 +++--------- 2 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..40155f0 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/Game.java b/src/main/java/it/polimi/ingsw/gc14/Model/Game.java index 94f27cf..a9410f7 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Game.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Game.java @@ -812,18 +812,12 @@ public class Game implements Serializable { */ private void endGame() { Queue events; - events=Stream.concat(board.lowerListTribe.stream().filter(x->!x.IsEventCard()),board.upperListTribe.stream().filter(x->!x.IsEventCard())).map(x->((EventCard)x)).collect(Collectors.toCollection(LinkedList::new)); + events=Stream.concat(board.lowerListTribe.stream().filter(TribeCard::IsEventCard),board.upperListTribe.stream().filter(TribeCard::IsEventCard)).map(x->((EventCard)x)).collect(Collectors.toCollection(LinkedList::new)); ArrayListsustenance=events.stream().filter(x->x.getType().equals(EventType.SUSTENANCE)).collect(Collectors.toCollection(ArrayList::new)); events.removeAll(sustenance); - for(EventCard event:events) - { - event.activateEvent(playersList); - } + events.forEach(event->event.activateEvent(playersList)); + sustenance.forEach(event->event.activateEvent(playersList)); - for(EventCard e : sustenance) - { - e.activateEvent(playersList); - } playersList.forEach(p->{ int temp= p.builders.stream().mapToInt(Builder::getPrestigeValue).sum(); p.addPrestige(temp); From 918b056d4c1932df5f15c136fa157e5409a29234 Mon Sep 17 00:00:00 2001 From: rubenpirreram Date: Sat, 2 May 2026 19:51:12 +0200 Subject: [PATCH 07/13] Removed: Observer --- .../ingsw/gc14/Controller/ClientController.java | 2 -- src/main/java/it/polimi/ingsw/gc14/Model/Game.java | 13 ------------- .../java/it/polimi/ingsw/gc14/Network/Observer.java | 7 ------- 3 files changed, 22 deletions(-) delete mode 100644 src/main/java/it/polimi/ingsw/gc14/Network/Observer.java diff --git a/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java b/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java index 144435f..5c2070b 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java +++ b/src/main/java/it/polimi/ingsw/gc14/Controller/ClientController.java @@ -1,10 +1,8 @@ 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; /** diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/Game.java b/src/main/java/it/polimi/ingsw/gc14/Model/Game.java index a9410f7..bc777d2 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Game.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Game.java @@ -22,7 +22,6 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; -import it.polimi.ingsw.gc14.Network.Observer; import it.polimi.ingsw.gc14.View.TUI.AsciiTable; import it.polimi.ingsw.gc14.View.TUI.BorderStyle; @@ -33,18 +32,6 @@ import it.polimi.ingsw.gc14.View.TUI.BorderStyle; */ public class Game implements Serializable { - private transient List 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 diff --git a/src/main/java/it/polimi/ingsw/gc14/Network/Observer.java b/src/main/java/it/polimi/ingsw/gc14/Network/Observer.java deleted file mode 100644 index 7677d92..0000000 --- a/src/main/java/it/polimi/ingsw/gc14/Network/Observer.java +++ /dev/null @@ -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); -} From be27500eafccd070a16113f6f2300c38c51596c9 Mon Sep 17 00:00:00 2001 From: MatteoPellegrino05 Date: Sat, 2 May 2026 20:13:02 +0200 Subject: [PATCH 08/13] Add: Improve game flow and endgame tests --- .../it/polimi/ingsw/gc14/Model/GameTest.java | 183 ++++++++++++++++-- 1 file changed, 163 insertions(+), 20 deletions(-) diff --git a/src/test/java/it/polimi/ingsw/gc14/Model/GameTest.java b/src/test/java/it/polimi/ingsw/gc14/Model/GameTest.java index 18df1f3..0e4f2a7 100644 --- a/src/test/java/it/polimi/ingsw/gc14/Model/GameTest.java +++ b/src/test/java/it/polimi/ingsw/gc14/Model/GameTest.java @@ -5,6 +5,9 @@ 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.GamePackage.GameStages; +import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Artist; +import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Builder; +import it.polimi.ingsw.gc14.Model.Cards.TribeCards.Characters.Inventor; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; @@ -77,9 +80,8 @@ class GameTest { return; } - if (!game.getLowerListBuilding().isEmpty()) { - current.addFood(100); - assertTrue(game.DrawLowerBuildingCardByIndex(current, 0)); + if (!game.getLowerListBuilding().isEmpty() + && game.DrawLowerBuildingCardByIndex(current, 0)) { return; } @@ -95,9 +97,8 @@ class GameTest { return; } - if (!game.getUpperListBuilding().isEmpty()) { - current.addFood(100); - assertTrue(game.DrawUpperBuildingCardByIndex(current, 0)); + if (!game.getUpperListBuilding().isEmpty() + && game.DrawUpperBuildingCardByIndex(current, 0)) { return; } @@ -294,7 +295,7 @@ class GameTest { assertTrue(game.addPlayer(p3)); Queue players = new LinkedList<>(); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < game.getNPlayers(); i++) { players.add(game.getCurrentState().getCurrentPlayer()); assertTrue(game.SlotChoiceByIndex(game.getCurrentState().getCurrentPlayer(), i)); } @@ -337,11 +338,14 @@ class GameTest { assertFalse(game.DrawUpperTribeCardByIndex(temp_player, eventIndex)); } - temp_player.addFood(100); - assertFalse(game.getUpperListBuilding().isEmpty()); + temp_player.builders.clear(); + index = 0; + BuildingCard selectedBuilding = game.getUpperListBuilding().get(index); + temp_player.addFood(selectedBuilding.getPrice()); + assertTrue(game.DrawUpperBuildingCardByIndex(temp_player, index)); int remainingTribeIndex = firstNonEventIndexOrMinusOne(game.getUpperListTribeCards()); @@ -445,15 +449,30 @@ class GameTest { assertFalse(game.getUpperListBuilding().isEmpty()); - current.addFood(100); + current.builders.clear(); + + BuildingCard selectedBuilding = game.getUpperListBuilding().get(0); + int expectedCost = selectedBuilding.getPrice(); + + current.addFood(expectedCost); - int foodBefore = current.getFoodValue(); int buildingsBefore = current.buildingCards.size(); + int upperBuildingsBefore = game.getUpperListBuilding().size(); + int foodBefore = current.getFoodValue(); assertTrue(game.PickOptionalBuildingCard(current, 0)); - assertTrue(current.getFoodValue() < foodBefore); assertEquals(buildingsBefore + 1, current.buildingCards.size()); + assertEquals(upperBuildingsBefore - 1, game.getUpperListBuilding().size()); + + assertTrue(current.buildingCards.stream() + .anyMatch(building -> + building.getPrice() == selectedBuilding.getPrice() + && building.getPrestigeValue() == selectedBuilding.getPrestigeValue() + && building.getEffectId() == selectedBuilding.getEffectId() + )); + + assertEquals(foodBefore - expectedCost, current.getFoodValue()); } @Test @@ -807,6 +826,8 @@ class GameTest { assertTrue(current.removeFood(1)); } + current.builders.clear(); + assertEquals(0, current.getFoodValue()); assertFalse( @@ -816,6 +837,7 @@ class GameTest { assertFalse(game.PickOptionalBuildingCard(current, 0)); } + @Test void toStringModel() { Game game=new Game(5); @@ -832,8 +854,8 @@ class GameTest { assertTrue(game.addPlayer(p5)); Queueplayers=new LinkedList<>(); - for(int i=0;i<3;i++) { - players.add( game.getCurrentState().getCurrentPlayer()); + for (int i = 0; i < game.getNPlayers(); i++) { + players.add(game.getCurrentState().getCurrentPlayer()); assertTrue(game.SlotChoiceByIndex(game.getCurrentState().getCurrentPlayer(), i)); } @@ -864,7 +886,12 @@ class GameTest { if (game.getCurrentState().getNLower() > 0 && !game.getLowerListBuilding().isEmpty()) { - current.addFood(100); + current.builders.clear(); + + BuildingCard selectedBuilding = game.getLowerListBuilding().get(0); + int expectedCost = selectedBuilding.getPrice(); + + current.addFood(expectedCost); int buildingsBefore = current.buildingCards.size(); int lowerBuildingsBefore = game.getLowerListBuilding().size(); @@ -877,8 +904,16 @@ class GameTest { assertEquals(buildingsBefore + 1, current.buildingCards.size()); assertEquals(lowerBuildingsBefore - 1, game.getLowerListBuilding().size()); - assertTrue(current.getFoodValue() < foodBefore); - + assertTrue(current.buildingCards.stream() + .anyMatch(building -> + building.getPrice() == selectedBuilding.getPrice() + && building.getPrestigeValue() == selectedBuilding.getPrestigeValue() + && building.getEffectId() == selectedBuilding.getEffectId() + )); + assertTrue( + current.getFoodValue() >= foodBefore - expectedCost, + "After buying the building, food should not be lower than the price paid because later effects may add food." + ); return; } @@ -908,14 +943,16 @@ class GameTest { Player current = game.getCurrentState().getCurrentPlayer(); if (game.getCurrentState().getNUpper() > 0 - && !game.getUpperListBuilding().isEmpty() - && current.builders.isEmpty()) { + && !game.getUpperListBuilding().isEmpty()) { while (current.getFoodValue() > 0) { assertTrue(current.removeFood(1)); } + current.builders.clear(); + assertEquals(0, current.getFoodValue()); + assertFalse(game.DrawUpperBuildingCardByIndex(current, 0)); return; } @@ -923,7 +960,7 @@ class GameTest { resolveOneMandatoryAction(game); } - fail("No upper building draw state reached with a player without builders."); + fail("No upper building draw state reached."); } @Test @@ -952,4 +989,110 @@ class GameTest { assertEquals(firstChooser, game.getCurrentState().getCurrentPlayer()); } + + @Test + @Timeout(value = 20, unit = TimeUnit.SECONDS) + void endGameShouldNotCrashWhenTriggeredAfterRoundTen() { + Game game = new Game(3); + + List players = addPlayers(game, 3, "end_game_"); + + giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); + + while (game.getCurrentState().getRound() < 10) { + playOneFullRound(game); + } + + assertEquals(10, game.getCurrentState().getRound()); + assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); + + completeSlotChoice(game); + resolveAllMandatoryActions(game); + + assertEquals(GameStages.OPTIONAL_CARD_EFFECT, game.getCurrentState().getGameStage()); + + assertDoesNotThrow(() -> resolveOptionalPhaseIfPresent(game)); + + assertEquals(GameStages.ENDED, game.getCurrentState().getGameStage()); + } + + @Test + @Timeout(value = 20, unit = TimeUnit.SECONDS) + void endGameShouldAddBuildingPrestigeValues() { + Game game = new Game(3); + + List players = addPlayers(game, 3, "building_prestige_"); + + giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); + + while (game.getCurrentState().getRound() < 10) { + playOneFullRound(game); + } + + completeSlotChoice(game); + resolveAllMandatoryActions(game); + + assertEquals(GameStages.OPTIONAL_CARD_EFFECT, game.getCurrentState().getGameStage()); + + Player player = players.get(0); + + int prestigeBefore = player.getPrestigeValue(); + + player.buildingCards.add(new BuildingCard(12, 1, 1, 7)); + player.buildingCards.add(new BuildingCard(12, 1, 1, 5)); + + int expectedMinimumIncrease = 7 + 5; + + resolveOptionalPhaseIfPresent(game); + + assertEquals(GameStages.ENDED, game.getCurrentState().getGameStage()); + + assertTrue( + player.getPrestigeValue() >= prestigeBefore + expectedMinimumIncrease, + "Final scoring should add at least the prestige values of the two added building cards." + ); + } + + @Test + @Timeout(value = 20, unit = TimeUnit.SECONDS) + void endGameShouldApplyFinalCharacterPrestigeBonuses() { + Game game = new Game(3); + + List players = addPlayers(game, 3, "final_characters_"); + giveOptionalEffectToAllPlayers(players.get(0), players.get(1), players.get(2)); + + while (game.getCurrentState().getRound() < 10) { + playOneFullRound(game); + } + + completeSlotChoice(game); + resolveAllMandatoryActions(game); + + assertEquals(GameStages.OPTIONAL_CARD_EFFECT, game.getCurrentState().getGameStage()); + + Player player = players.get(0); + assertNotNull(player); + + int prestigeBefore = player.getPrestigeValue(); + + player.builders.add(new Builder(1, 0, 4)); + + player.inventors.add(new Inventor(1, 0)); + player.inventors.add(new Inventor(1, 1)); + + player.artists.add(new Artist(1)); + player.artists.add(new Artist(1)); + + int expectedMinimumIncrease = 4 + 4 + 10; + + resolveOptionalPhaseIfPresent(game); + + assertEquals(GameStages.ENDED, game.getCurrentState().getGameStage()); + + assertTrue( + player.getPrestigeValue() >= prestigeBefore + expectedMinimumIncrease, + "Final scoring should add at least builder prestige, inventor bonus, and artist pair bonus." + ); + } + } \ No newline at end of file From 3c2cf38f34c6ec21262c527f26bf5a24346f6b2e Mon Sep 17 00:00:00 2001 From: rubenpirreram Date: Sun, 3 May 2026 15:12:51 +0200 Subject: [PATCH 09/13] Fix: building8 effect --- .../ingsw/gc14/Model/Cards/Building/Effects/Building8.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/Model/Cards/Building/Effects/Building8.java b/src/main/java/it/polimi/ingsw/gc14/Model/Cards/Building/Effects/Building8.java index d67017d..0c4db48 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Cards/Building/Effects/Building8.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Cards/Building/Effects/Building8.java @@ -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()); } } From c1092a2afaa5bc6d6385dd0a2d06db4d12220c01 Mon Sep 17 00:00:00 2001 From: AleandroPagani Date: Sun, 3 May 2026 15:20:40 +0200 Subject: [PATCH 10/13] Fix: Changed print in English. Add: request for server IP --- .../java/it/polimi/ingsw/gc14/ClientLauncherTUI.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/ClientLauncherTUI.java b/src/main/java/it/polimi/ingsw/gc14/ClientLauncherTUI.java index 1d2623c..77b7b87 100644 --- a/src/main/java/it/polimi/ingsw/gc14/ClientLauncherTUI.java +++ b/src/main/java/it/polimi/ingsw/gc14/ClientLauncherTUI.java @@ -31,17 +31,19 @@ public class ClientLauncherTUI { view = new TUI(null); 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(); view.setUsername(username); - System.out.println("Selezionare numero di giocatori desiderato: "); + 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 { @@ -55,7 +57,7 @@ public class ClientLauncherTUI { // 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 { From 55c8e38ceb5435e2e112af5c3f4c8b341093ac99 Mon Sep 17 00:00:00 2001 From: AleandroPagani Date: Sun, 3 May 2026 15:33:57 +0200 Subject: [PATCH 11/13] Fix: Firewall blocks RMI connection --- src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java b/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java index 252a9da..935a7b9 100644 --- a/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java +++ b/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java @@ -123,6 +123,7 @@ public class ServerLauncher { }).start(); }); + System.setProperty("java.rmi.server.port", "1100"); serverRMI.start(); new Thread(()->{serverTCP.start();}).start(); } From 2148dc3a095ddb1568c6b30cd0d9fd20ab5994c6 Mon Sep 17 00:00:00 2001 From: rubenpirreram Date: Sun, 3 May 2026 15:44:32 +0200 Subject: [PATCH 12/13] RMI START Changed --- src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java b/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java index 935a7b9..252a9da 100644 --- a/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java +++ b/src/main/java/it/polimi/ingsw/gc14/ServerLauncher.java @@ -123,7 +123,6 @@ public class ServerLauncher { }).start(); }); - System.setProperty("java.rmi.server.port", "1100"); serverRMI.start(); new Thread(()->{serverTCP.start();}).start(); } From 6afbc4493ba741876d02b4192802b2411a16297e Mon Sep 17 00:00:00 2001 From: rubenpirreram Date: Sun, 3 May 2026 16:03:11 +0200 Subject: [PATCH 13/13] TEST ASCII --- .../java/it/polimi/ingsw/gc14/View/TUI/BorderStyle.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/it/polimi/ingsw/gc14/View/TUI/BorderStyle.java b/src/main/java/it/polimi/ingsw/gc14/View/TUI/BorderStyle.java index 13b365d..6a3e11e 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/TUI/BorderStyle.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/TUI/BorderStyle.java @@ -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;