source: protocol/src/main/java/geniusweb/protocol/session/mopac2/PartyStates.java@ 52

Last change on this file since 52 was 52, checked in by ruud, 14 months ago

Fixed small issues in domaineditor.

File size: 9.7 KB
Line 
1package geniusweb.protocol.session.mopac2;
2
3import java.util.Collections;
4import java.util.HashMap;
5import java.util.HashSet;
6import java.util.LinkedList;
7import java.util.List;
8import java.util.Map;
9import java.util.Set;
10import java.util.stream.Collectors;
11
12import com.fasterxml.jackson.annotation.JsonAutoDetect;
13import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
14import com.fasterxml.jackson.annotation.JsonCreator;
15import com.fasterxml.jackson.annotation.JsonProperty;
16
17import geniusweb.actions.Action;
18import geniusweb.actions.EndNegotiation;
19import geniusweb.actions.PartyId;
20import geniusweb.inform.Agreements;
21import geniusweb.protocol.ProtocolException;
22
23/**
24 * Invariant: contains the current state of all participating parties. A party
25 * either notYetActed, did action, reached an agreement, walked away or made a
26 * {@link ProtocolException}.
27 * <p>
28 * After a phase completes, the actions are filtered/handled to collect
29 * agreements and move remaining parties back to notYetActed.
30 *
31 */
32@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE)
33public class PartyStates {
34 // all parties must be in exactly one state at all times.
35 private final Set<PartyId> notYetActed;
36 private final List<Action> actions; // chrono order
37 private final Agreements agreements;
38 private final List<PartyId> walkedAway;
39 private final Map<PartyId, ProtocolException> exceptions;
40 private final Map<PartyId, Integer> powers;
41
42 @JsonCreator
43 protected PartyStates(@JsonProperty("notYetActed") Set<PartyId> notYetActed,
44 @JsonProperty("actions") List<Action> actions,
45 @JsonProperty("agreements") Agreements agreements,
46 @JsonProperty("walkedAway") List<PartyId> walkedAway,
47 @JsonProperty("exceptions") Map<PartyId, ProtocolException> exceptions,
48 @JsonProperty("powers") Map<PartyId, Integer> powers) {
49 this.notYetActed = notYetActed;
50 this.actions = actions;
51 this.agreements = agreements;
52 this.walkedAway = walkedAway;
53 this.exceptions = exceptions;
54 this.powers = powers;
55 }
56
57 /**
58 * Initial constructor.
59 *
60 * @param powers the powers of all parties.
61 */
62 public PartyStates(Map<PartyId, Integer> powers) {
63 this.notYetActed = new HashSet<>(powers.keySet());
64 this.actions = Collections.emptyList();
65 this.agreements = new Agreements();
66 this.walkedAway = Collections.emptyList();
67 this.exceptions = Collections.emptyMap();
68 this.powers = new HashMap<>(powers);
69 }
70
71 /**
72 *
73 * @param action the action done by some party. The correctness of action,
74 * particularly of {@link Action#getActor()}, must be correct.
75 * @return new state with party done given action. This just accepts any
76 * given action and is not considering number of rounds, time or
77 * whether an action is allowed.
78 *
79 * @throws IllegalArgumentException if party doing action already acted.
80 * This is just a safety check as legality
81 * of actions should be checked before
82 * calling this.
83 */
84 public PartyStates with(Action action) {
85 if (!(notYetActed.contains(action.getActor())))
86 throw new IllegalArgumentException(
87 "actor already acted: " + action);
88 if (action instanceof EndNegotiation)
89 return withWalkAway(action.getActor());
90 List<Action> newActions = new LinkedList<Action>(actions);
91 newActions.add(action);
92 return new PartyStates(removeParty(action.getActor()), newActions,
93 agreements, walkedAway, exceptions, powers);
94 }
95
96 /**
97 *
98 * @param newAgree a new agreements to be merged with existing agreements.
99 * The parties in the agreement must have acted and thus in
100 * actions.
101 * @return new PartyStates with agreeing parties removed from actions and
102 * added to Agreements.
103 */
104 public PartyStates with(Agreements newAgree) {
105 Set<PartyId> parties = newAgree.getMap().keySet();
106 List<Action> newActions = actions.stream()
107 .filter(act -> !(parties.contains(act.getActor())))
108 .collect(Collectors.toList());
109 return new PartyStates(notYetActed, newActions,
110 agreements.with(newAgree), walkedAway, exceptions, powers);
111 }
112
113 public PartyStates withWalkAway(PartyId actor) {
114 if (!(notYetActed.contains(actor)))
115 throw new IllegalArgumentException("actor already acted: " + actor);
116 LinkedList<PartyId> newWalkAway = new LinkedList<>(walkedAway);
117 newWalkAway.add(actor);
118 return new PartyStates(removeParty(actor), actions, agreements,
119 newWalkAway, exceptions, powers);
120 }
121
122 /**
123 * Move party from active to exceptions.
124 *
125 * @param e the exception that the party caused
126 * @return new PartyStates with party that caused the exception in the
127 * exceptions list and removed from the active list. Nothing happens
128 * if party is not active.
129 */
130 public PartyStates with(ProtocolException e) {
131 if (!notYetActed.contains(e.getParty())) {
132 // complex case. Party did valid action but now is messing around.
133 // Easiest seems to completely ignore it. CHECK.
134 return this;
135 }
136 Map<PartyId, ProtocolException> newExc = new HashMap<>(exceptions);
137 newExc.put(e.getParty(), e);
138 return new PartyStates(removeParty(e.getParty()), actions, agreements,
139 walkedAway, newExc, powers);
140 }
141
142 /**
143 *
144 * @return parties that have not yet acted
145 */
146 public Set<PartyId> getNotYetActed() {
147 return notYetActed;
148 }
149
150 /**
151 *
152 * @return parties that are still in the negotiation. These are the parties
153 * that not yet acted plus the ones that did an action.
154 */
155 public Set<PartyId> getNegotiatingParties() {
156 Set<PartyId> parties = actions.stream().map(act -> act.getActor())
157 .collect(Collectors.toSet());
158 parties.addAll(notYetActed);
159 return parties;
160 }
161
162 /**
163 * @param actor
164 * @return {@link #notYetActed} with actor removed
165 * @throws IllegalArgumentException if party already acted (not in
166 * {@link #notYetActed}).
167 */
168 private Set<PartyId> removeParty(PartyId party) {
169 Set<PartyId> newActiveParties = new HashSet<>(notYetActed);
170 if (!newActiveParties.remove(party))
171 throw new IllegalArgumentException(
172 "Party " + party + " is not active, can't be removed");
173 return newActiveParties;
174
175 }
176
177 public Agreements getAgreements() {
178 return agreements;
179 }
180
181 public Map<PartyId, Integer> getPowers() {
182 return Collections.unmodifiableMap(powers);
183 }
184
185 public Map<PartyId, ProtocolException> getExceptions() {
186 return Collections.unmodifiableMap(exceptions);
187 }
188
189 /**
190 * @return new state where all {@link #notYetActed} are moved to the
191 * exceptions list.
192 */
193 public PartyStates finish() {
194 PartyStates newstate = this;
195 for (PartyId party : notYetActed) {
196 newstate = newstate
197 .with(new ProtocolException("Party did not act", party));
198 }
199 return newstate;
200 }
201
202 public List<Action> getActions() {
203 return Collections.unmodifiableList(actions);
204 }
205
206 /**
207 *
208 * @return all parties that walked away
209 */
210 public List<PartyId> getWalkedAway() {
211 return walkedAway;
212 }
213
214 /**
215 * @param <T> the type of objects requested
216 * @param type the type of actions to extract. Must be of type T, needed
217 * because of java's type erasure.
218 *
219 * @return all actions of type done in this phase
220 */
221 public <T extends Action> List<T> getActions(Class<T> type) {
222 return actions.stream().filter(act -> type.isInstance(act))
223 .map(act -> (T) act).collect(Collectors.toList());
224 }
225
226 @Override
227 public String toString() {
228 return "PartyStates[" + notYetActed + "," + actions + "," + agreements
229 + "," + walkedAway + "," + exceptions + "]";
230 }
231
232 /**
233 *
234 * @return states with all parties that are in {@link #actions} moved back
235 * to {@link #notYetActed}. This state is then ready for a next
236 * phase.
237 * @throws IllegalStateException if {@link #notYetActed} is not empty
238 */
239 public PartyStates flush() {
240 if (!notYetActed.isEmpty())
241 throw new IllegalStateException(
242 "Some parties did not yet act:" + notYetActed);
243 return new PartyStates(getNegotiatingParties(), Collections.emptyList(),
244 agreements, walkedAway, exceptions, powers);
245 }
246
247 @Override
248 public int hashCode() {
249 final int prime = 31;
250 int result = 1;
251 result = prime * result + ((actions == null) ? 0 : actions.hashCode());
252 result = prime * result
253 + ((agreements == null) ? 0 : agreements.hashCode());
254 result = prime * result
255 + ((exceptions == null) ? 0 : exceptions.hashCode());
256 result = prime * result
257 + ((notYetActed == null) ? 0 : notYetActed.hashCode());
258 result = prime * result + ((powers == null) ? 0 : powers.hashCode());
259 result = prime * result
260 + ((walkedAway == null) ? 0 : walkedAway.hashCode());
261 return result;
262 }
263
264 @Override
265 public boolean equals(Object obj) {
266 if (this == obj)
267 return true;
268 if (obj == null)
269 return false;
270 if (getClass() != obj.getClass())
271 return false;
272 PartyStates other = (PartyStates) obj;
273 if (actions == null) {
274 if (other.actions != null)
275 return false;
276 } else if (!actions.equals(other.actions))
277 return false;
278 if (agreements == null) {
279 if (other.agreements != null)
280 return false;
281 } else if (!agreements.equals(other.agreements))
282 return false;
283 if (exceptions == null) {
284 if (other.exceptions != null)
285 return false;
286 } else if (!exceptions.equals(other.exceptions))
287 return false;
288 if (notYetActed == null) {
289 if (other.notYetActed != null)
290 return false;
291 } else if (!notYetActed.equals(other.notYetActed))
292 return false;
293 if (powers == null) {
294 if (other.powers != null)
295 return false;
296 } else if (!powers.equals(other.powers))
297 return false;
298 if (walkedAway == null) {
299 if (other.walkedAway != null)
300 return false;
301 } else if (!walkedAway.equals(other.walkedAway))
302 return false;
303 return true;
304 }
305
306}
Note: See TracBrowser for help on using the repository browser.