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 }