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 }