Coverage Summary for Class: Card10 (it.polimi.ingsw.Model)

Class Class, % Method, % Branch, % Line, %
Card10 100% (1/1) 100% (3/3) 82,1% (23/28) 98% (48/49)


1 package it.polimi.ingsw.Model; 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.Misc.Pair; 8 import it.polimi.ingsw.Model.Enums.PawnColour; 9  10 import java.io.Serial; 11 import java.util.ArrayList; 12 import java.util.EnumMap; 13 import java.util.List; 14 import java.util.Map; 15  16 import static it.polimi.ingsw.Misc.Utils.canMapFit; 17  18 /** 19  * EFFECT: You may exchange up to 2 Students between your entrance and your Dining Room 20  */ 21 public class Card10 extends StatelessEffect { 22  @Serial 23  private static final long serialVersionUID = 112L; // convention: 1 for model, (01 -> 99) for objects 24  25  public Card10(Model ctx) { 26  super(10, 1, ctx); 27  } 28  29  /** 30  * Refer to: {@link CharacterCard#overridableCheckInput(CharacterCardInput)} for further information 31  * 32  * @param input CharacterCardInput should contain: 33  * <ul> 34  * <li>A valid list of pair having following properties: </li> 35  * <ul> 36  * No more than two pairs<br> 37  * No null values inside pairs 38  * </ul> 39  * <li>Every pairs must follow this format:</li> 40  * <ul> 41  * first element from entrance and second from diningRoom 42  * </ul> 43  * <li>a valid PawnColour from card</li> 44  * </ul> 45  */ 46  @Override 47  public OptionalValue<InputValidationException> overridableCheckInput(CharacterCardInput input) { 48  //convention of input.targetPawnPairs ---> array of pairs, first element is from entrance, second is from diningRoom 49  OptionalValue<List<Pair<PawnColour, PawnColour>>> optionalPawnPairs = input.getTargetPawnPairs(); 50  // make sure that: 51  if ( 52  optionalPawnPairs.isEmpty() || // target pawn pairs was set as parameter 53  //optionalPawnPair.get().size() == 0 || // target pawn pairs is not empty (technically allowed) 54  optionalPawnPairs.get().size() > 2 || // target pawn pairs are not over the pair limit of 2 swaps 55  optionalPawnPairs.get().stream().anyMatch(p -> p.first() == null || p.second() == null) // no null values in pair 56  ) { 57  // in case throw exception for invalid element in input 58  return OptionalValue.of(new InvalidElementException("Target Pawn Pairs")); 59  } 60  // explode pawnpairs into respective arrays of elements 61  List<Pair<PawnColour, PawnColour>> pawnPairs = optionalPawnPairs.get(); 62  // first count how many students of each colour the user picked 63  Map<PawnColour, Integer> comingFromEntrance = new EnumMap<>(PawnColour.class); // counts user entrance selected colours 64  Map<PawnColour, Integer> comingFromDiningRoom = new EnumMap<>(PawnColour.class); // counts diningroom selected colours 65  for (Pair<PawnColour, PawnColour> pair : pawnPairs) { 66  comingFromEntrance.merge(pair.first(), 1, Integer::sum); 67  comingFromDiningRoom.merge(pair.second(), 1, Integer::sum); 68  } 69  70  // get user entrance counts per colour 71  PlayerBoard playerBoard = input.getCaller(); 72  Map<PawnColour, Integer> entranceMap = new EnumMap<>(PawnColour.class); // counts user entrance total colours 73  for (PawnColour pawn : playerBoard.getEntranceStudents().stream() 74  .filter(OptionalValue::isPresent) 75  .map(OptionalValue::get) 76  .toList()) { 77  entranceMap.merge(pawn, 1, Integer::sum); 78  } 79  80  // make sure the elements coming from user (first) are also mapped to entrance 81  if (!canMapFit(entranceMap, comingFromEntrance)) { 82  return OptionalValue.of(new InvalidElementException("Target Pawn Pairs")); 83  } 84  85  Map<PawnColour, Integer> diningRoomMap = new EnumMap<>(PawnColour.class); // counts user diningRoom total colours 86  for (PawnColour pawn : PawnColour.values()) { 87  diningRoomMap.merge(pawn, playerBoard.getDiningRoomCount(pawn), Integer::sum); 88  } 89  // make sure the elements coming from diningRoom (second) are also mapped to the diningroom 90  if (!canMapFit(diningRoomMap, comingFromDiningRoom)) { 91  return OptionalValue.of(new InvalidElementException("Target Pawn Pairs")); 92  } 93  94  // validate size of dining room 95  for (PawnColour p : comingFromEntrance.keySet()) { 96  if (playerBoard.getDiningRoomCount(p) - comingFromDiningRoom.getOrDefault(p, 0) + comingFromEntrance.getOrDefault(p, 0) > 10) { 97  return OptionalValue.of(new GenericInputValidationException("Dining Room", 98  "can't contain " + pawnPairs.size() 99  + "elements without overflowing on one of its lanes.")); 100  } 101  } 102  103  return OptionalValue.empty(); // all checks passed, return true 104  } 105  106  /** 107  * Refer to: {@link CharacterCard#unsafeApplyEffect(CharacterCardInput)} for further information 108  */ 109  @Override 110  protected void unsafeApplyEffect(CharacterCardInput input) throws Exception { 111  // explode pawnpairs into respective arrays of elements 112  List<Pair<PawnColour, PawnColour>> pawnPairs = input.getTargetPawnPairs().get(); 113  List<PawnColour> fromEntrance = new ArrayList<>(pawnPairs.size()); 114  List<PawnColour> fromDiningRoom = new ArrayList<>(pawnPairs.size()); 115  // get the playerboard to operate on 116  PlayerBoard playerBoard = input.getCaller(); 117  for (Pair<PawnColour, PawnColour> p : pawnPairs) { 118  fromEntrance.add(p.first()); 119  fromDiningRoom.add(p.second()); 120  playerBoard.removeStudentFromEntrance(p.first()); 121  this.context.removeStudentFromDiningRoom(p.second(), playerBoard); 122  } 123  // true effect happens here 124  playerBoard.addStudentsToEntrance(fromDiningRoom); 125  for (PawnColour student : fromEntrance) { 126  this.context.addStudentToDiningRoom(student, playerBoard); 127  } 128  } 129  130  //test purpose only 131 }