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 02a31ec..e3e5bec 100644 --- a/src/main/java/it/polimi/ingsw/gc14/Model/Game.java +++ b/src/main/java/it/polimi/ingsw/gc14/Model/Game.java @@ -19,13 +19,9 @@ import it.polimi.ingsw.gc14.Model.GamePackage.GameStages; import java.io.Serializable; import java.util.*; -import java.util.random.RandomGenerator; import java.util.stream.Collectors; import java.util.stream.Stream; -import it.polimi.ingsw.gc14.View.TUI.AsciiTable; -import it.polimi.ingsw.gc14.View.TUI.BorderStyle; - /** * Represents the main game model. * A Game object stores the players, the current state of the match, diff --git a/src/test/java/it/polimi/ingsw/gc14/Controller/GameControllerTest.java b/src/test/java/it/polimi/ingsw/gc14/Controller/GameControllerTest.java index ddb1425..321669b 100644 --- a/src/test/java/it/polimi/ingsw/gc14/Controller/GameControllerTest.java +++ b/src/test/java/it/polimi/ingsw/gc14/Controller/GameControllerTest.java @@ -5,6 +5,8 @@ import it.polimi.ingsw.gc14.Model.Cards.TribeCard; import it.polimi.ingsw.gc14.Model.Game; import it.polimi.ingsw.gc14.Model.GamePackage.GameStages; import it.polimi.ingsw.gc14.Model.Player; +import it.polimi.ingsw.gc14.Model.Totems; + import org.junit.jupiter.api.Test; import java.util.LinkedList; @@ -15,6 +17,30 @@ import static org.junit.jupiter.api.Assertions.*; class GameControllerTest { + private void completeTotemChoice(Game game, GameController controller) { + assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); + + while (game.getCurrentState().getGameStage() == GameStages.TOTEM_CHOICE) { + Player current = game.getCurrentState().getCurrentPlayer(); + assertNotNull(current); + + List availableTotems = game.getAvailableTotems(); + assertFalse(availableTotems.isEmpty()); + + Totems selectedTotem = availableTotems.get(0); + + assertTrue(controller.TotemChoice( + current.getUserName(), + selectedTotem.name() + )); + + assertEquals(selectedTotem, current.totem); + } + + assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); + assertNotNull(game.getCurrentState().getCurrentPlayer()); + } + private Game createStartedGame() { Game game = new Game(3); GameController controller = new GameController(game); @@ -23,6 +49,8 @@ class GameControllerTest { assertTrue(controller.addPlayer("Marco")); assertTrue(controller.addPlayer("Luca")); + completeTotemChoice(game, controller); + return game; } @@ -113,12 +141,17 @@ class GameControllerTest { if (!game.getLowerListBuilding().isEmpty()) { current.addFood(100); - assertTrue(controller.drawLowerBuildingCard(username, 0)); - return; + + if (controller.drawLowerBuildingCard(username, 0)) { + return; + } } - assertTrue(controller.SkipNoDrawable(username)); - return; + if (game.getCurrentState().getNUpper() == 0 + || game.getUpperListTribeCards().stream().allMatch(TribeCard::IsEventCard)) { + assertTrue(controller.SkipNoDrawable(username)); + return; + } } if (game.getCurrentState().getNUpper() > 0) { @@ -131,12 +164,17 @@ class GameControllerTest { if (!game.getUpperListBuilding().isEmpty()) { current.addFood(100); - assertTrue(controller.drawUpperBuildingCard(username, 0)); - return; + + if (controller.drawUpperBuildingCard(username, 0)) { + return; + } } - assertTrue(controller.SkipNoDrawable(username)); - return; + if (game.getCurrentState().getNLower() == 0 + || game.getLowerListTribeCards().stream().allMatch(TribeCard::IsEventCard)) { + assertTrue(controller.SkipNoDrawable(username)); + return; + } } fail("Current player has no remaining draw actions."); @@ -173,10 +211,74 @@ class GameControllerTest { assertNotNull(game.getPlayerByUsername("Marco")); assertNotNull(game.getPlayerByUsername("Luca")); - assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); + assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); assertFalse(controller.addPlayer("Extra")); } + @Test + void totemChoiceShouldAssignTotemsAndStartSlotChoice() { + Game game = new Game(3); + GameController controller = new GameController(game); + + assertTrue(controller.addPlayer("Giorgio")); + assertTrue(controller.addPlayer("Marco")); + assertTrue(controller.addPlayer("Luca")); + + completeTotemChoice(game, controller); + + assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); + + assertNotNull(game.getPlayerByUsername("Giorgio").totem); + assertNotNull(game.getPlayerByUsername("Marco").totem); + assertNotNull(game.getPlayerByUsername("Luca").totem); + } + + @Test + void totemChoiceShouldReturnFalseForWrongPlayer() { + Game game = new Game(3); + GameController controller = new GameController(game); + + assertTrue(controller.addPlayer("Giorgio")); + assertTrue(controller.addPlayer("Marco")); + assertTrue(controller.addPlayer("Luca")); + + Player current = game.getCurrentState().getCurrentPlayer(); + assertNotNull(current); + + String wrongUsername = + current.getUserName().equals("Giorgio") ? "Marco" : "Giorgio"; + + Totems selectedTotem = game.getAvailableTotems().get(0); + + assertFalse(controller.TotemChoice(wrongUsername, selectedTotem.name())); + } + + @Test + void disconnectedPlayerShouldDelegateToModel() { + Game game = createStartedGame(); + GameController controller = new GameController(game); + + Player current = game.getCurrentState().getCurrentPlayer(); + assertNotNull(current); + + assertTrue(controller.DisconnectedPlayer(current.getUserName())); + + assertTrue(game.disconnetedPlayers.containsKey(current)); + assertTrue(game.disconnetedPlayers.get(current)); + } + + @Test + void reconnectPlayerShouldDelegateToModel() { + Game game = createStartedGame(); + GameController controller = new GameController(game); + + Player current = game.getCurrentState().getCurrentPlayer(); + assertNotNull(current); + + assertTrue(controller.DisconnectedPlayer(current.getUserName())); + assertTrue(controller.ReconnectPlayer(current.getUserName())); + } + @Test void allMethodsShouldReturnFalseForUnknownUsername() { Game game = new Game(3); @@ -191,6 +293,9 @@ class GameControllerTest { assertFalse(controller.pickOptionalTribeCard("ghost", 0)); assertFalse(controller.pickOptionalBuildingCard("ghost", 0)); assertFalse(controller.noOptionalCard("ghost")); + assertFalse(controller.TotemChoice("ghost", Totems.values()[0].name())); + assertFalse(controller.DisconnectedPlayer("ghost")); + assertFalse(controller.ReconnectPlayer("ghost")); } @Test @@ -310,6 +415,8 @@ class GameControllerTest { assertFalse(controller.addPlayer("p2")); assertTrue(controller.addPlayer("p3")); + completeTotemChoice(game, controller); + Queue players = new LinkedList<>(); for (int i = 0; i < game.getNPlayers(); i++) { 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 8aaa3a8..a8b479f 100644 --- a/src/test/java/it/polimi/ingsw/gc14/Model/GameTest.java +++ b/src/test/java/it/polimi/ingsw/gc14/Model/GameTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; import java.util.*; +import java.util.stream.Stream; import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.*; @@ -18,8 +19,33 @@ import static org.junit.jupiter.api.Assertions.*; @Timeout(value = 10, unit = TimeUnit.SECONDS) class GameTest { + private void completeTotemChoice(Game game) { + assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); + + while (game.getCurrentState().getGameStage() == GameStages.TOTEM_CHOICE) { + Player current = game.getCurrentState().getCurrentPlayer(); + assertNotNull(current); + + List availableTotems = game.getAvailableTotems(); + assertFalse(availableTotems.isEmpty()); + + Totems selectedTotem = availableTotems.get(0); + + assertTrue(game.TotemChoice(current, selectedTotem)); + assertEquals(selectedTotem, current.totem); + } + + assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); + assertNotNull(game.getCurrentState().getCurrentPlayer()); + } private Queue completeSlotChoice(Game game) { + if (game.getCurrentState().getGameStage() == GameStages.TOTEM_CHOICE) { + completeTotemChoice(game); + } + + assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); + Queue order = new LinkedList<>(); for (int i = 0; i < game.getNPlayers(); i++) { @@ -228,6 +254,12 @@ class GameTest { assertEquals(nPlayers + 1, game.getLowerListTribeCards().size()); } + @Test + void getBoardShouldReturnBoard() { + Game game = new Game(3); + + assertNotNull(game.getBoard()); + } @Test void getPlayerByUsernameShouldReturnPlayerOrNull() { @@ -252,7 +284,7 @@ class GameTest { } @Test - void addPlayerShouldRejectDuplicatesAndStartSlotChoiceWhenFull() { + void addPlayerShouldRejectDuplicatesAndStartTotemChoiceWhenFull() { Game game = new Game(3); Player p1 = new Player("p1"); Player p2 = new Player("p2"); @@ -264,11 +296,118 @@ class GameTest { assertFalse(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); - assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); + assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); + assertNotNull(game.getCurrentState().getCurrentPlayer()); assertFalse(game.addPlayer(p4)); } + @Test + void gameShouldEnterTotemChoiceWhenAllPlayersAreAdded() { + Game game = new Game(3); + + assertTrue(game.addPlayer(new Player("p1"))); + assertTrue(game.addPlayer(new Player("p2"))); + assertTrue(game.addPlayer(new Player("p3"))); + + assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); + assertNotNull(game.getCurrentState().getCurrentPlayer()); + } + + @Test + void totemChoiceShouldAssignDistinctTotemsAndStartSlotChoice() { + Game game = new Game(3); + + Player p1 = new Player("p1"); + Player p2 = new Player("p2"); + Player p3 = new Player("p3"); + + assertTrue(game.addPlayer(p1)); + assertTrue(game.addPlayer(p2)); + assertTrue(game.addPlayer(p3)); + + completeTotemChoice(game); + + assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); + + assertNotNull(p1.totem); + assertNotNull(p2.totem); + assertNotNull(p3.totem); + + assertEquals( + 3, + Stream.of(p1.totem, p2.totem, p3.totem).distinct().count() + ); + } + + @Test + void totemChoiceShouldRejectAlreadyChosenTotem() { + Game game = new Game(3); + + Player p1 = new Player("p1"); + Player p2 = new Player("p2"); + Player p3 = new Player("p3"); + + assertTrue(game.addPlayer(p1)); + assertTrue(game.addPlayer(p2)); + assertTrue(game.addPlayer(p3)); + + Player firstPlayer = game.getCurrentState().getCurrentPlayer(); + Totems chosenTotem = game.getAvailableTotems().get(0); + + assertTrue(game.TotemChoice(firstPlayer, chosenTotem)); + + Player secondPlayer = game.getCurrentState().getCurrentPlayer(); + assertNotNull(secondPlayer); + + assertFalse(game.TotemChoice(secondPlayer, chosenTotem)); + } + + @Test + void totemChoiceShouldRejectWrongPlayer() { + Game game = new Game(3); + + Player p1 = new Player("p1"); + Player p2 = new Player("p2"); + Player p3 = new Player("p3"); + + assertTrue(game.addPlayer(p1)); + assertTrue(game.addPlayer(p2)); + assertTrue(game.addPlayer(p3)); + + Player current = game.getCurrentState().getCurrentPlayer(); + Player wrongPlayer = current.equals(p1) ? p2 : p1; + + Totems availableTotem = game.getAvailableTotems().get(0); + + assertFalse(game.TotemChoice(wrongPlayer, availableTotem)); + } + + @Test + void getAvailableTotemsShouldExcludeChosenTotems() { + Game game = new Game(3); + + Player p1 = new Player("p1"); + Player p2 = new Player("p2"); + Player p3 = new Player("p3"); + + assertTrue(game.addPlayer(p1)); + assertTrue(game.addPlayer(p2)); + assertTrue(game.addPlayer(p3)); + + int initialAvailableTotems = game.getAvailableTotems().size(); + + Player current = game.getCurrentState().getCurrentPlayer(); + Totems chosenTotem = game.getAvailableTotems().get(0); + + assertTrue(game.TotemChoice(current, chosenTotem)); + + assertEquals(initialAvailableTotems - 1, game.getAvailableTotems().size()); + assertFalse(game.getAvailableTotems().contains(chosenTotem)); + } + + + @Test void shouldRejectInvalidSlotChoices() { Game game = new Game(3); @@ -281,6 +420,8 @@ class GameTest { assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); + completeTotemChoice(game); + Player current = game.getCurrentState().getCurrentPlayer(); assertFalse(game.SlotChoiceByIndex(current, -1)); @@ -307,6 +448,8 @@ class GameTest { assertFalse(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); + completeTotemChoice(game); + Queue players = new LinkedList<>(); for (int i = 0; i < game.getNPlayers(); i++) { players.add(game.getCurrentState().getCurrentPlayer()); @@ -523,6 +666,10 @@ class GameTest { assertTrue(game.addPlayer(player)); } + if (game.getCurrentState().getGameStage() == GameStages.TOTEM_CHOICE) { + completeTotemChoice(game); + } + return players; } @@ -579,6 +726,10 @@ class GameTest { assertTrue(game.addPlayer(p2)); assertTrue(game.addPlayer(p3)); + /* + * The game is currently in TOTEM_CHOICE: + * draw requests must be rejected because the game is not in RES_ACTIONS. + */ Player current = game.getCurrentState().getCurrentPlayer(); assertNotNull(current); @@ -587,6 +738,10 @@ class GameTest { assertFalse(game.DrawUpperBuildingCardByIndex(current, 0)); assertFalse(game.DrawLowerBuildingCardByIndex(current, 0)); + /* + * The totem choice phase and the slot choice phase are completed, + * so the game enters RES_ACTIONS. + */ completeSlotChoice(game); current = game.getCurrentState().getCurrentPlayer(); @@ -621,7 +776,6 @@ class GameTest { } } - @Test void optionalMethodsShouldReturnFalseOutsideOptionalState() { Game game = new Game(3); @@ -694,6 +848,10 @@ class GameTest { assertTrue(game.addPlayer(new Player("p2"))); assertTrue(game.addPlayer(new Player("p3"))); + assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); + + completeTotemChoice(game); + assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); Player current = game.getCurrentState().getCurrentPlayer(); @@ -712,6 +870,8 @@ class GameTest { assertTrue(game.addPlayer(new Player("p" + nPlayers + "_" + i))); } + completeTotemChoice(game); + assertEquals(nPlayers, game.getCurrentPlayerNumber()); assertEquals(nPlayers, game.getPlayers().size()); assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); @@ -852,34 +1012,6 @@ class GameTest { assertFalse(game.PickOptionalBuildingCard(current, 0)); } - @Test - void toStringModel() { - Game game=new Game(5); - Player p1=new Player("p1"); - Player p2=new Player("p2"); - Player p3=new Player("p3"); - Player p4=new Player("p4"); - Player p5=new Player("p5"); - - assertTrue(game.addPlayer(p1)); - assertTrue(game.addPlayer(p2)); - assertTrue(game.addPlayer(p3)); - assertTrue(game.addPlayer(p4)); - assertTrue(game.addPlayer(p5)); - - Queueplayers=new LinkedList<>(); - for (int i = 0; i < game.getNPlayers(); i++) { - players.add(game.getCurrentState().getCurrentPlayer()); - assertTrue(game.SlotChoiceByIndex(game.getCurrentState().getCurrentPlayer(), i)); - } - - String result = game.toString(); - - assertNotNull(result); - assertFalse(result.isBlank()); - assertTrue(result.contains("CURRENT STATE")); - } - @Test @Timeout(value = 5, unit = TimeUnit.SECONDS) void shouldDrawLowerBuildingWhenAvailableAndPlayerCanPay() { @@ -1076,8 +1208,8 @@ class GameTest { } /* - * Mantiene l'effetto opzionale, ma con prestigio finale nullo. - * Così la fase OPT_CARD_E rimane coerente e il confronto resta controllato. + * Keeps the optional effect, but with zero final prestige. + * This preserves the OPT_CARD_E phase while keeping the comparison controlled. */ player.buildingCards.add(new BuildingCard(12, 1, 1, 0)); } @@ -1223,6 +1355,65 @@ class GameTest { assertFalse(game.SkipNoDrawable(current)); } + @Test + void disconnectedCurrentPlayerDuringSlotChoiceShouldAdvanceTurn() { + Game game = new Game(3); + + addPlayers(game, 3, "disconnect_slot_"); + + Player current = game.getCurrentState().getCurrentPlayer(); + assertNotNull(current); + + assertTrue(game.DisconnectedPlayer(current)); + + assertTrue(game.disconnetedPlayers.containsKey(current)); + assertTrue(game.disconnetedPlayers.get(current)); + assertNotEquals(current, game.getCurrentState().getCurrentPlayer()); + } + + @Test + void disconnectedPlayerShouldReturnFalseIfAlreadyDisconnected() { + Game game = new Game(3); + + addPlayers(game, 3, "disconnect_twice_"); + + Player current = game.getCurrentState().getCurrentPlayer(); + + assertTrue(game.DisconnectedPlayer(current)); + assertFalse(game.DisconnectedPlayer(current)); + } + + @Test + void reconnectPlayerShouldRemovePlayerFromDisconnectedMapDuringSlotChoice() { + Game game = new Game(3); + + addPlayers(game, 3, "reconnect_"); + + Player current = game.getCurrentState().getCurrentPlayer(); + + assertTrue(game.DisconnectedPlayer(current)); + assertTrue(game.disconnetedPlayers.containsKey(current)); + + assertTrue(game.ReconnectPlayer(current)); + assertFalse(game.disconnetedPlayers.containsKey(current)); + } + + @Test + void clearDisconnectedShouldEmptyDisconnectedPlayersMap() { + Game game = new Game(3); + + addPlayers(game, 3, "clear_disconnect_"); + + Player current = game.getCurrentState().getCurrentPlayer(); + + assertTrue(game.DisconnectedPlayer(current)); + assertFalse(game.disconnetedPlayers.isEmpty()); + + game.ClearDisconnected(); + + assertTrue(game.disconnetedPlayers.isEmpty()); + } + @Test @Timeout(value = 5, unit = TimeUnit.SECONDS) void drawLowerBuildingShouldReturnFalseIfPlayerCannotPay() { @@ -1376,7 +1567,7 @@ class GameTest { assertTrue(game.addPlayer(p4)); assertTrue(game.addPlayer(p5)); - assertEquals(GameStages.SLOT_CHOICE, game.getCurrentState().getGameStage()); + assertEquals(GameStages.TOTEM_CHOICE, game.getCurrentState().getGameStage()); List foodValues = game.getPlayers().stream() .map(Player::getFoodValue) @@ -1446,8 +1637,8 @@ class GameTest { assertNotNull(testedPlayer); /* - * I due player vengono resi identici rispetto a Eventi e final scoring. - * La partita è comunque arrivata realmente al round 10. + * The two players are made equivalent with respect to events and final scoring. + * The game has still reached round 10 through the real flow. */ preparePlayerForComparableFinalScoring(controlPlayer); preparePlayerForComparableFinalScoring(testedPlayer);