Coverage Summary for Class: MoveStudent (it.polimi.ingsw.Controller.Actions)
Class |
Method, %
|
Branch, %
|
Line, %
|
MoveStudent |
100%
(3/3)
|
78,1%
(25/32)
|
93,9%
(31/33)
|
MoveStudent$1 |
100%
(1/1)
|
100%
(1/1)
|
Total |
100%
(4/4)
|
78,1%
(25/32)
|
94,1%
(32/34)
|
1 package it.polimi.ingsw.Controller.Actions;
2
3 import it.polimi.ingsw.Controller.DestinationType;
4 import it.polimi.ingsw.Controller.MoveDestination;
5 import it.polimi.ingsw.Exceptions.Input.GenericInputValidationException;
6 import it.polimi.ingsw.Exceptions.Input.InputValidationException;
7 import it.polimi.ingsw.Exceptions.Input.InvalidElementException;
8 import it.polimi.ingsw.Misc.OptionalValue;
9 import it.polimi.ingsw.Model.Enums.GamePhase;
10 import it.polimi.ingsw.Model.Enums.PawnColour;
11 import it.polimi.ingsw.Model.Model;
12 import it.polimi.ingsw.Model.PlayerBoard;
13
14 import java.io.Serial;
15 import java.util.List;
16
17 import static it.polimi.ingsw.Misc.Utils.countSimilarClassOccurrences;
18
19 /**
20 * This {@link PlayerAction} allows the caller to move a single student from the entrance to the school to an island or a dining room table. This action
21 * is linked to the Action Phase.
22 */
23 public class MoveStudent extends PlayerAction {
24 @Serial
25 private static final long serialVersionUID = 205L; // convention: 2 for controller, (01 -> 99) for objects
26
27 private final int selectedEntrancePosition;
28 private final MoveDestination destination;
29
30 /**
31 * Create a new instance of this class with the following inputs:
32 *
33 * @param playerBoardId the ID of the current {@link PlayerBoard}
34 * @param destination a {@link MoveDestination} value specifying where the selected student will be moved
35 * @param selectedEntrancePosition id of the slot in the list returned by {@link PlayerBoard#getEntranceStudents()}, selects a student to be moved
36 */
37 public MoveStudent(int playerBoardId, int selectedEntrancePosition, MoveDestination destination) {
38 super(playerBoardId, false);
39 this.selectedEntrancePosition = selectedEntrancePosition;
40 this.destination = destination;
41 }
42
43 /**
44 * {@inheritDoc}
45 * <ul>
46 * <li>The {@link GamePhase} must be {@link GamePhase#ACTION}</li>
47 * <li>The previous {@link PlayerAction}s must be either {@link MoveStudent} or {@link PlayCharacterCard} or the history must be empty</li>
48 * <li>Only a limited number of actions like this one can be played (3 or 4 depending on the players)</li>
49 * <li>The student decleared to move must be part of the entrance on the {@link PlayerBoard}</li>
50 * <li>If the destination is {@link DestinationType#ISLAND} then the island ID must be within bounds (0 to 12 excluded)</li>
51 * <li>If the destination is {@link DestinationType#DININGROOM} then the dining room must be able to contain the pawn</li>
52 * </ul>
53 *
54 * @param history the controller stores a {@link List} of previous {@link PlayerAction}s related to the player taking
55 * the current turn (at every new turn, the history is cleared).
56 * Some actions may use this {@link List} to check for duplicates.
57 * @param ctx a reference to {@link Model}. Some actions may use this reference to check for consistency between what
58 * the actions declares and what the Model offers.
59 * @return An empty {@link OptionalValue} in case of a successful validation. Otherwise the returned {@link OptionalValue}
60 * contains the related {@link InputValidationException}
61 */
62 @Override
63 protected OptionalValue<InputValidationException> customValidation(List<PlayerAction> history, Model ctx) {
64 int maxCount = ctx.getMutablePlayerBoards().size() == 3 ? 4 : 3;
65 int entranceSize = ctx.getMutablePlayerBoards().size() == 3 ? 9 : 7;
66 PlayerBoard caller = ctx.getMutableTurnOrder().getMutableCurrentPlayer();
67 if (ctx.getMutableTurnOrder().getGamePhase() != GamePhase.ACTION) {
68 return OptionalValue.of(new GenericInputValidationException("GamePhase", "the game is not in the correct phase"));
69 }
70 if (history.size() > 0) {
71 if (!(history.get(history.size() - 1).getClass() == MoveStudent.class || history.get(history.size() - 1).getClass() == PlayCharacterCard.class)) {
72 return OptionalValue.of(new GenericInputValidationException("History", "MoveStudent can only be preceded by a PlayCharacterCard action or MoveStudent action"));
73 }
74 }
75 if (countSimilarClassOccurrences(MoveStudent.class, history) >= maxCount) {
76 return OptionalValue.of(new GenericInputValidationException("History", "only " + maxCount + " pawns can be moved from entrance"));
77 }
78
79 if (!(this.selectedEntrancePosition >= 0 && this.selectedEntrancePosition < entranceSize)) {
80 return OptionalValue.of(new InvalidElementException("Index Target Entrance Position"));
81 }
82 if (caller.getEntranceStudents().get(this.selectedEntrancePosition).isEmpty()) {
83 return OptionalValue.of(new InvalidElementException("Target Entrance Position"));
84 }
85
86 if (this.destination.getDestinationType() == DestinationType.ISLAND) {
87 int islandId = this.destination.getIslandID();
88 if (islandId < 0 || islandId > 12) {
89 return OptionalValue.of(new InvalidElementException("Target Island")); // target ti out of bounds for id
90 }
91 } else if (this.destination.getDestinationType() == DestinationType.DININGROOM) {
92 if (caller.isDiningRoomFull(caller.getEntranceStudents().get(this.selectedEntrancePosition).get())) {
93 return OptionalValue.of(new GenericInputValidationException("DiningRoom",
94 "can't contain the pawn without overflowing."));
95 }
96 }
97 return OptionalValue.empty();
98 }
99
100
101 @Override
102 public void unsafeExecute(Model ctx) throws Exception {
103 PlayerBoard pb = ctx.getMutablePlayerBoard(this.getPlayerBoardID());
104 // set entrance position to null
105 PawnColour toMove = pb.removeStudentFromEntrance(selectedEntrancePosition);
106 switch (this.destination.getDestinationType()) {
107 case ISLAND -> {
108 int id = this.destination.getIslandID();
109 ctx.getMutableIslandField().getMutableIslandById(id)
110 .addStudent(toMove);
111 }
112 case DININGROOM -> ctx.addStudentToDiningRoom(toMove, pb);
113 }
114 }
115 }