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

Class Class, % Method, % Branch, % Line, %
IslandGroup 100% (1/1) 100% (14/14) 79,2% (19/24) 92,2% (47/51)


1 package it.polimi.ingsw.Model; 2  3 import it.polimi.ingsw.Exceptions.Operation.FailedOperationException; 4 import it.polimi.ingsw.Exceptions.Operation.ForbiddenOperationException; 5 import it.polimi.ingsw.Exceptions.Operation.OperationException; 6 import it.polimi.ingsw.Misc.OptionalValue; 7 import it.polimi.ingsw.Model.Enums.PawnColour; 8 import it.polimi.ingsw.Model.Enums.TowerColour; 9  10 import java.io.Serial; 11 import java.io.Serializable; 12 import java.util.*; 13  14 /** 15  * Every {@link Island} can be contained in an IslandGroup and multiple Islands can be grouped up. 16  */ 17 public class IslandGroup implements Serializable { 18  @Serial 19  private static final long serialVersionUID = 123L; // convention: 1 for model, (01 -> 99) for objects 20  21  private final int id; 22  private final ArrayList<Island> islands; 23  private final Stack<NoEntryTile> noEntryTiles; 24  25  /** 26  * Construct an IslandGroup starting from a single {@link Island} 27  * 28  * @param i a single {@link Island}, its {@link Island#getId()} becomes the group's ID 29  */ 30  public IslandGroup(Island i) { 31  this.islands = new ArrayList<>(); 32  this.id = i.getId(); 33  this.islands.add(i); 34  this.noEntryTiles = new Stack<>(); 35  } 36  37  /** 38  * Construct a new amalgamation of groups. The new group contains the sum of all the {@link PawnColour} on each group, the sum of the 39  * {@link NoEntryTile}s on each group. Groups can only be joined if their {@link Tower#getColour()} returns the same value.<br> 40  * The ID assigned to the new group will be the lowest between the input groups. 41  * 42  * @param islandGroups an array of groups to be merged into one 43  * @throws OperationException if the groups cannot be joined 44  */ 45  public IslandGroup(IslandGroup... islandGroups) throws OperationException { 46  if (islandGroups.length > 0 && islandGroups[0].canJoin(islandGroups)) { 47  this.islands = new ArrayList<>(); 48  this.noEntryTiles = new Stack<>(); 49  for (IslandGroup i : islandGroups) { 50  this.islands.addAll(i.getMutableIslands()); 51  this.noEntryTiles.addAll(i.getMutableNoEntryTiles()); 52  } 53  this.id = Arrays.stream(islandGroups) 54  .min(Comparator.comparingInt(IslandGroup::getId)) 55  .orElseThrow(() -> new FailedOperationException("Island Groups Constructor", "no minimum ID between groups found")) 56  .getId(); 57  } else { 58  throw new ForbiddenOperationException("Island Groups Constructor", "groups are not join-able"); 59  } 60  } 61  62  /** 63  * returns true if the inputted {@link IslandGroup} all contain the same type of tower 64  * 65  * @param groups the groups you'd like to join 66  */ 67  public boolean canJoin(IslandGroup... groups) { 68  if (groups.length <= 0) { 69  return false; 70  } else { 71  if (this.getTowerColour().isEmpty()) return false; 72  else return 73  Arrays.stream(groups).allMatch(g -> g.getTowerColour().equals(this.getTowerColour())); 74  } 75  } 76  77  /** 78  * @return an unmodifiable {@link List} containing all the {@link Island}s in the group. Each element on the list 79  * CAN be modified, the list itself can't. 80  */ 81  public List<Island> getMutableIslands() { 82  return List.copyOf(islands); 83  } 84  85  /** 86  * @return an unmodifiable {@link List} containing all the {@link NoEntryTile}s in the group. Each element on the list 87  * CAN be modified, the list itself can't. 88  */ 89  public List<NoEntryTile> getMutableNoEntryTiles() { 90  return List.copyOf(noEntryTiles); 91  } 92  93  /** 94  * @return the ID of the group 95  */ 96  public int getId() { 97  return id; 98  } 99  100  /** 101  * Get the colour of the towers stored on the islands. 102  * 103  * @return a non empty {@link OptionalValue} containing the {@link TowerColour}, if present. Note: if at least an island doesn't match the {@link TowerColour} of the others, this method will return an empty 104  * {@link OptionalValue}. 105  */ 106  public OptionalValue<TowerColour> getTowerColour() { 107  List<Island> islands = this.getMutableIslands(); 108  if (islands.stream().allMatch(i -> i.getTowerColour().equals(islands.get(0).getTowerColour()))) { 109  return islands.get(0).getTowerColour(); 110  } else return OptionalValue.empty(); 111  } 112  113  /** 114  * @return the amount of towers in the group (either 0 or equal to the number of islands in the group) 115  */ 116  public int getTowerCount() { 117  if (getTowerColour().isPresent()) return getMutableIslands().size(); 118  else return 0; 119  } 120  121  /** 122  * @return an unmodifiable {@link Map} a {@link PawnColour} to the amount of students of that colour in the group. 123  */ 124  public Map<PawnColour, Integer> getStudentCount() { 125  Map<PawnColour, Integer> studentCount = new EnumMap<>(PawnColour.class); 126  for (PawnColour p : this.getStudents()) { 127  studentCount.merge(p, 1, Integer::sum); 128  } 129  return Map.copyOf(studentCount); 130  } 131  132  /** 133  * @return an unmodifiable {@link List} containing all the {@link PawnColour}s in the group. 134  */ 135  public List<PawnColour> getStudents() { 136  List<PawnColour> islandGroupStudents = new ArrayList<>(); 137  for (Island s : this.getMutableIslands()) { 138  islandGroupStudents.addAll(s.getStudents()); 139  } 140  return List.copyOf(islandGroupStudents); 141  } 142  143  /** 144  * Checks to see if an island is contained in the group 145  * 146  * @param i the {@link Island} you wish to search for in the group 147  * @return true if the island is contained, false otherwise 148  */ 149  public boolean contains(Island i) { 150  for (Island island : islands) { 151  if (island.equals(i)) { 152  return true; 153  } 154  } 155  return false; 156  } 157  158  /** 159  * adds a {@link NoEntryTile} to the group 160  * 161  * @param tile the no entry tile to add 162  */ 163  public void addNoEntry(NoEntryTile tile) { 164  this.noEntryTiles.add(tile); 165  } 166  167  /** 168  * removes a {@link NoEntryTile} from the stack of tiles and puts it back on the character card where it came from 169  */ 170  public void resetNoEntry() { 171  this.noEntryTiles.remove(0).goHome(); 172  } 173  174  /** 175  * multiple {@link Tower}s may need to be swapped or added during the Group's lifespan, this method can be used for that 176  * 177  * @param ts the new {@link TowerStorage} where towers are coming from. the old towers (if any were present) will all be returned to its 178  * rightful storage automatically. If the new tower storage runs out of towers before swapping out all the towers from the group, 179  * then some islands fill be left empty while others will be full. Note that the empty islands will keep staying in 180  * the group, which is going to become un-join able. 181  */ 182  public void swapTower(TowerStorage ts) { 183  for (Island i : this.islands) { 184  i.swapTower(ts.extractTower()); 185  } 186  } 187 }