Coverage Summary for Class: PlayerAction (it.polimi.ingsw.Controller.Actions)
| Class | Class, % | Method, % | Branch, % | Line, % |
|---|---|---|---|---|
| PlayerAction | 100% (1/1) | 100% (6/6) | 85% (17/20) | 91,7% (22/24) |
1 package it.polimi.ingsw.Controller.Actions; 2 3 import it.polimi.ingsw.Exceptions.Input.GenericInputValidationException; 4 import it.polimi.ingsw.Exceptions.Input.InputValidationException; 5 import it.polimi.ingsw.Exceptions.Input.InvalidElementException; 6 import it.polimi.ingsw.Misc.OptionalValue; 7 import it.polimi.ingsw.Model.Model; 8 9 import java.io.Serial; 10 import java.io.Serializable; 11 import java.util.List; 12 13 /** 14 * The {@link PlayerAction} object is the definition of a user's intention. <br> 15 * The various Classes that extend it are the only possible way to interact safely with the model. 16 */ 17 public abstract class PlayerAction implements Serializable { 18 @Serial 19 private static final long serialVersionUID = 200L; // convention: 2 for controller, (01 -> 99) for objects 20 21 private final int playerBoardID; 22 private final boolean uniquePerTurn; 23 24 /** 25 * Package protected constructor used to initialize the playerBoardID. 26 * 27 * @param playerBoardID the ID of the player who wishes to interact with the controller. 28 * @param uniquePerTurn if set to false, the user can submit multiple actions of the same type during his turn. 29 */ 30 protected PlayerAction(int playerBoardID, boolean uniquePerTurn) { 31 this.playerBoardID = playerBoardID; 32 this.uniquePerTurn = uniquePerTurn; 33 } 34 35 /** 36 * The validate function is used to check whether or not the declared {@link PlayerAction} is possible.<br> 37 * The validate function will check for: 38 * <ul> 39 * <li>The game must not be over</li> 40 * <li>The action must be called during the correct turn</li> 41 * <li>If the action is unique, check that no duplicates have been played before</li> 42 * <li>Any additional constraint imposed by {@link #customValidation(List, Model)}</li> 43 * </ul> 44 * 45 * @param history the controller stores a {@link List} of previous {@link PlayerAction}s related to the player taking 46 * the current turn (at every new turn, the history is cleared). 47 * Some actions may use this {@link List} to check for duplicates. 48 * @param ctx a reference to {@link Model}. Some actions may use this reference to check for consistency between what 49 * the actions declares and what the Model offers. 50 * @return An empty {@link OptionalValue} in case of a successful validation. Otherwise the returned {@link OptionalValue} 51 * contains the related {@link InputValidationException} 52 */ 53 public final OptionalValue<InputValidationException> validate(List<PlayerAction> history, Model ctx) { 54 OptionalValue<InputValidationException> gameRunningCheck = isGameRunning(ctx); 55 if (gameRunningCheck.isPresent()) return gameRunningCheck; 56 57 OptionalValue<InputValidationException> correctTurnCheck = isCorrectTurn(ctx); 58 if (correctTurnCheck.isPresent()) return correctTurnCheck; 59 60 OptionalValue<InputValidationException> duplicateCheck = isDuplicate(history); 61 if (duplicateCheck.isPresent()) return duplicateCheck; 62 63 OptionalValue<InputValidationException> customValidationCheck = customValidation(history, ctx); 64 if (customValidationCheck.isPresent()) return customValidationCheck; 65 66 return OptionalValue.empty(); 67 } 68 69 /** 70 * SUB-VALIDATION FUNCTION: <br> 71 * if the game is not active anymore (i.e. the game is over and no actions can be made), this function will return a non-empty value. 72 * 73 * @param ctx the {@link Model} object, used during verification. 74 * @return an {@link OptionalValue} value, the value is empty if no issues are found during the validation of the function. Else the 75 * value will contain a {@link Throwable} {@link Exception} that can be used to propagate the error message. 76 */ 77 private OptionalValue<InputValidationException> isGameRunning(Model ctx) { 78 if (ctx.isGameOver()) { 79 return OptionalValue.of(new GenericInputValidationException(this.getClass().getSimpleName(), "Game is over")); 80 } 81 return OptionalValue.empty(); 82 } 83 84 /** 85 * SUB-VALIDATION FUNCTION: <br> 86 * if the {@link PlayerAction}'s declared player is not the current player that needs to play, this function will return a non-empty value. 87 * 88 * @param ctx the {@link Model} object, used during verification. 89 * @return an {@link OptionalValue} value, the value is empty if no issues are found during the validation of the function. Else the 90 * value will contain a {@link Throwable} {@link Exception} that can be used to propagate the error message. 91 */ 92 private OptionalValue<InputValidationException> isCorrectTurn(Model ctx) { 93 if (!(ctx.getMutablePlayerBoards().size() > this.getPlayerBoardID())) { 94 return OptionalValue.of(new InvalidElementException("PlayerBoardID out of range")); 95 } 96 if (ctx.getMutableTurnOrder().getMutableCurrentPlayer().getId() != this.getPlayerBoardID()) { 97 return OptionalValue.of(new GenericInputValidationException(this.getClass().getSimpleName(), "It's not your turn yet")); 98 } 99 return OptionalValue.empty(); 100 } 101 102 /** 103 * SUB-VALIDATION FUNCTION: <br> 104 * if the {@link PlayerAction} is marked as unique per turn, this function will return a non-empty value in case of a duplicate 105 * action being present in the history 106 * 107 * @param history a list of previous actions submitted by the player 108 * @return an {@link OptionalValue} value, the value is empty if no issues are found during the validation of the function. Else the 109 * value will contain a {@link Throwable} {@link Exception} that can be used to propagate the error message. 110 */ 111 private OptionalValue<InputValidationException> isDuplicate(List<PlayerAction> history) { 112 if (!this.uniquePerTurn || history.stream().noneMatch(h -> h.getClass() == this.getClass())) { 113 return OptionalValue.empty(); 114 } 115 return OptionalValue.of(new GenericInputValidationException(this.getClass().getSimpleName(), "Too many similar actions have been executed")); 116 } 117 118 /** 119 * This function is used by {@link #validate(List, Model)} to check whether or not the declared {@link PlayerAction} is possible.<br> 120 * This function will check for the following requirements: 121 * 122 * @param history the controller stores a {@link List} of previous {@link PlayerAction}s related to the player taking 123 * the current turn (at every new turn, the history is cleared). 124 * Some actions may use this {@link List} to check for duplicates. 125 * @param ctx a reference to {@link Model}. Some actions may use this reference to check for consistency between what 126 * the actions declares and what the Model offers. 127 * @return An empty {@link OptionalValue} in case of a successful validation. Otherwise the returned {@link OptionalValue} 128 * contains the related {@link InputValidationException} 129 */ 130 protected abstract OptionalValue<InputValidationException> customValidation(List<PlayerAction> history, Model ctx); 131 132 /** 133 * @return the {@link it.polimi.ingsw.Model.PlayerBoard} id set during construction of the Action. 134 */ 135 final public int getPlayerBoardID() { 136 return playerBoardID; 137 } 138 139 /** 140 * Every class extending {@link PlayerAction} must implement the following method, which takes a {@link Model} reference and 141 * applies the concrete effect of the action. <br> 142 * Warning: this function, as implied by the name, is unsafe. it should never be called by called outside the scope 143 * of the class {@link it.polimi.ingsw.Controller.Controller}, which takes adequate precautions in order to guarantee 144 * a coherent execution of the method. 145 * 146 * @param ctx the {@link Model} reference, once the method finishes running the game state will be altered. 147 * @throws Exception Should an error occur during the execution of the method, such error will be reported through the 148 * thrown {@link Exception}. Note that any {@link PlayerAction} inheritor should guarantee the absence of Exceptions 149 * for any positive return value yielded by {@link #validate(List, Model)} 150 */ 151 public abstract void unsafeExecute(Model ctx) throws Exception; 152 }