Coverage Summary for Class: Controller (it.polimi.ingsw.Controller)
Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Controller |
100%
(1/1)
|
100%
(5/5)
|
90%
(9/10)
|
92,3%
(24/26)
|
1 package it.polimi.ingsw.Controller;
2
3 import it.polimi.ingsw.Controller.Actions.EndTurnOfActionPhase;
4 import it.polimi.ingsw.Controller.Actions.PlayAssistantCard;
5 import it.polimi.ingsw.Controller.Actions.PlayerAction;
6 import it.polimi.ingsw.Exceptions.Input.GenericInputValidationException;
7 import it.polimi.ingsw.Exceptions.Input.InputValidationException;
8 import it.polimi.ingsw.Misc.OptionalValue;
9 import it.polimi.ingsw.Model.Enums.GameMode;
10 import it.polimi.ingsw.Model.Model;
11 import it.polimi.ingsw.Model.ModelWrapper;
12 import it.polimi.ingsw.Server.Lobby;
13 import it.polimi.ingsw.Server.Messages.Events.Internal.GameOverEvent;
14 import it.polimi.ingsw.Server.Messages.Events.Internal.ModelUpdateEvent;
15
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.Objects;
19
20 /**
21 * This is the Controller of the whole game. <br>
22 * The Controller should be the only entity able to modify the model.
23 */
24 public class Controller {
25 private final List<PlayerAction> history;
26 private final ModelWrapper modelWrapper;
27 private boolean unsafeReferences = false;
28
29 /**
30 * Subscribes a new {@link Controller} object to a {@link ModelWrapper} instance, allowing the creation of a
31 * Controller to Model connection.
32 *
33 * @param modelWrapper an instance of {@link ModelWrapper}
34 */
35 private Controller(ModelWrapper modelWrapper) {
36 Objects.requireNonNull(modelWrapper);
37
38 this.history = new ArrayList<>(6);
39 this.modelWrapper = modelWrapper;
40 }
41
42 /**
43 * Generates a new instance of the {@link Controller}. This is the debug method to call to create a game, since the internal attributes
44 * are set to the parameters.<br>
45 *
46 * <b>Note:</b> this method will not protect model references after editing actions to the model.
47 * <b>Note:</b> this method should be called <b>ONLY</b> by test code.
48 *
49 * @param modelWrapper an instance of {@link ModelWrapper}
50 * @param history an instance to a list of {@link PlayerAction}, used by the controller to check the flow of the game
51 */
52 Controller(ModelWrapper modelWrapper, List<PlayerAction> history) {
53 this.history = history;
54 this.modelWrapper = modelWrapper;
55 this.unsafeReferences = true;
56 }
57
58 /**
59 * Generates a new instance. This is the static method to call for general purpose creation of a game.
60 *
61 * @param gameMode the game mode the players are going to use
62 * @param lobby in case a server is used, insert the {@linkplain Lobby} object wrapped in an {@link OptionalValue} to let it
63 * receive {@link ModelUpdateEvent} and {@link GameOverEvent}
64 * @param players a list of minimum 2 and maximum 4 strings containing the nicknames of the players.
65 * In the case of 4 players: players at index 0 and 2 go together against players at index 1 and 3
66 * @return the generated controller
67 * @throws InputValidationException if the supplied players are less than 2 or more than 4
68 */
69 public static Controller createGame(GameMode gameMode, OptionalValue<Lobby> lobby, String... players) throws InputValidationException {
70 Objects.requireNonNull(gameMode);
71 Objects.requireNonNull(lobby);
72 Objects.requireNonNull(players);
73
74 if (players.length > 1 && players.length <= 4) {
75 return new Controller(new ModelWrapper(new Model(gameMode, players), lobby));
76 } else {
77 throw new GenericInputValidationException("Players", "The number of players must be 2, 3 or 4.\n" +
78 "Players received: " + players.length);
79 }
80 }
81
82 /**
83 * An execution request handler. Actions are passed in, validated and (if possible) executed. <br>
84 * Warning: this request is not thread safe, that job is delegated to the caller to handle.
85 * <p>
86 * Note: if this Controller was generated using the debug constructor, then references to the model, once modified, are
87 * going to be kept unsafe, generally decreasing the security of the editing mechanism.
88 *
89 * @param action the action to be validated and executed.
90 * @throws InputValidationException thrown when validation fails, carries information about the error. If thrown,
91 * the model is guaranteed to not have been modified.
92 */
93 public void executeAction(PlayerAction action) throws InputValidationException {
94 Model model = this.modelWrapper.modelCopy(false);
95 OptionalValue<InputValidationException> validation = action.validate(this.getHistory(), model);
96 if (validation.isPresent()) throw validation.get();
97 // as right now we are abusing the hell out of exception throwing
98 try {
99 this.modelWrapper.editModel(action::unsafeExecute, unsafeReferences);
100 } catch (Exception e) {
101 e.printStackTrace();
102 }
103
104 history.add(action);
105 if (action.getClass() == EndTurnOfActionPhase.class || action.getClass() == PlayAssistantCard.class) {
106 this.history.clear();
107 }
108 }
109
110 /**
111 * @return an immutable copy of the list of player actions.<br>
112 * <b>Note:</b> the single actions are immutable by default, so do not get cloned
113 */
114 private List<PlayerAction> getHistory() {
115 return List.copyOf(history);
116 }
117 }