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 }