Coverage Summary for Class: IslandField (it.polimi.ingsw.Model)
Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
IslandField |
100%
(1/1)
|
100%
(11/11)
|
100%
(14/14)
|
86,8%
(46/53)
|
1 package it.polimi.ingsw.Model;
2
3 import it.polimi.ingsw.Exceptions.Container.EmptyContainerException;
4 import it.polimi.ingsw.Exceptions.Container.InvalidContainerIndexException;
5 import it.polimi.ingsw.Exceptions.Operation.OperationException;
6 import it.polimi.ingsw.Logger;
7 import it.polimi.ingsw.Misc.Utils;
8
9 import java.io.Serial;
10 import java.io.Serializable;
11 import java.util.ArrayList;
12 import java.util.List;
13
14 /**
15 * All {@link IslandGroup}s in the game need to be contained in a circular structure. This class does just that - along
16 * joining the groups and tracking Mother Nature's position
17 */
18 public class IslandField implements Serializable {
19 @Serial
20 private static final long serialVersionUID = 122L; // convention: 1 for model, (01 -> 99) for objects
21
22 private static final int FIELD_SIZE = 12;
23 private final ArrayList<IslandGroup> groups;
24 private final ArrayList<Island> islands;
25 private IslandGroup motherNaturePosition;
26
27 /**
28 * Creates the Field, populating it with 12 {@link Island}s and 12 {@link IslandGroup}s.
29 * The generated elements are populated with following the rules of the game.
30 */
31 public IslandField() {
32 this.groups = new ArrayList<>(FIELD_SIZE);
33 this.islands = new ArrayList<>(FIELD_SIZE);
34 for (int i = 0; i < FIELD_SIZE; i++) {
35 Island island = new Island(i);
36 IslandGroup islandGroup = new IslandGroup(island);
37 this.islands.add(island);
38 this.groups.add(islandGroup);
39 }
40
41 this.motherNaturePosition = Utils.random(this.groups);
42 int motherNatureIslandId = this.motherNaturePosition.getId();
43
44 StudentBag tempBag = new StudentBag(2);
45
46 for (Island island : this.islands) {
47 if (island.getId() != motherNatureIslandId && island.getId() != (motherNatureIslandId + 6) % FIELD_SIZE) {
48 try {
49 island.addStudent(tempBag.extract());
50 } catch (EmptyContainerException e) {
51 // should never happen
52 Logger.severe("student bag was found empty while adding a student to an island. Critical, unrecoverable, error");
53 throw new RuntimeException(e);
54 }
55 }
56 }
57 }
58
59 /**
60 * @return an unmodifiable {@link List} containing all the {@link IslandGroup}s on the field. Each element on the list
61 * CAN be modified, the list itself can't.
62 */
63 public List<IslandGroup> getMutableGroups() {
64 return List.copyOf(this.groups);
65 }
66
67 /**
68 * @return an unmodifiable {@link List} containing all the {@link Island}s on the field. Each element on the list
69 * CAN be modified, the list itself can't.
70 */
71 public List<Island> getMutableIslands() {
72 return List.copyOf(this.islands);
73 }
74
75 /**
76 * @param id the ID of the group to search for
77 * @return the {@link IslandGroup} matching the ID on the input
78 * @throws InvalidContainerIndexException if the specified ID is not in the list of currently active groups, this exception
79 * is thrown
80 */
81 public IslandGroup getMutableIslandGroupById(int id) throws InvalidContainerIndexException {
82 return groups.stream()
83 .filter(g -> g.getId() == id)
84 .findAny()
85 .orElseThrow(() -> new InvalidContainerIndexException("Island Groups"));
86 }
87
88 /**
89 * @param id the ID of the island to search for
90 * @return the {@link Island} matching the ID on the input
91 * @throws InvalidContainerIndexException if the specified ID is not in the list of currently active islands, this exception
92 * is thrown
93 */
94 public Island getMutableIslandById(int id) throws InvalidContainerIndexException {
95 return islands.stream()
96 .filter(i -> i.getId() == id)
97 .findAny()
98 .orElseThrow(() -> new InvalidContainerIndexException("Islands"));
99 }
100
101 /**
102 * this method is Package-private - moving mother nature through this method does not enact its power. it is therefore unsafe
103 * to call this outside of very specific circumstances.
104 *
105 * @param moves the amount of moves mother nature will move.
106 */
107 protected void moveMotherNature(int moves) {
108 motherNaturePosition = groups.get((groups.indexOf(motherNaturePosition) + moves) % groups.size());
109 }
110
111 /**
112 * When called, this method will join the groups adjacent to mother nature following the game's rules.
113 */
114 public void joinGroups() {
115 IslandGroup motherGroup = this.getMutableMotherNaturePosition();
116 IslandGroup nextGroup = this.nextGroup(motherGroup);
117 IslandGroup prevGroup = this.prevGroup(motherGroup);
118 // look to the group before mother nature position and join if necessary
119 ifJoinableThenJoin(motherGroup, prevGroup);
120 motherGroup = this.getMutableMotherNaturePosition();
121 ifJoinableThenJoin(motherGroup, nextGroup);
122 }
123
124 /**
125 * @return the {@link IslandGroup} matching the position of mother nature
126 */
127 public IslandGroup getMutableMotherNaturePosition() {
128 return motherNaturePosition;
129 }
130
131 /**
132 * searches for the {@link IslandGroup} adjacent to a selected one
133 *
134 * @param curr the {@link IslandGroup} you wish to find the next adjacent one
135 * @return the {@link IslandGroup} that comes after the one in input
136 */
137 private IslandGroup nextGroup(IslandGroup curr) {
138 int groupSize = this.groups.size();
139 int currIndex = this.groups.indexOf(curr);
140 return groups.get(
141 (currIndex + groupSize + 1) % groupSize
142 );
143 }
144
145 /**
146 * searches for the {@link IslandGroup} adjacent to a selected one
147 *
148 * @param curr the {@link IslandGroup} you wish to find the previous adjacent one
149 * @return the {@link IslandGroup} that comes before the one in input
150 */
151 private IslandGroup prevGroup(IslandGroup curr) {
152 int groupSize = this.groups.size();
153 int currIndex = this.groups.indexOf(curr);
154 return groups.get(
155 (currIndex + groupSize - 1) % groupSize
156 );
157 }
158
159 /**
160 * Two groups are considered joinable if they share the same tower colour.
161 *
162 * @param motherGroup the group on which Mother nature is standing
163 * @param otherGroup a group adjacent to motherGroup
164 */
165 private void ifJoinableThenJoin(IslandGroup motherGroup, IslandGroup otherGroup) {
166 try {
167 if (motherGroup.canJoin(otherGroup)) {
168 IslandGroup joined = new IslandGroup(motherGroup, otherGroup);
169 this.groups.remove(otherGroup);
170 this.groups.set(this.groups.indexOf(motherGroup), joined);
171 this.motherNaturePosition = joined;
172 }
173 } catch (OperationException e) {
174 Logger.severe("Unreachable statement has been reached. Severe, unrecoverable error");
175 e.printStackTrace();
176 throw new RuntimeException();
177 }
178 }
179
180 }