source: protocol/src/main/java/geniusweb/protocol/session/saop/SAOPState.java@ 39

Last change on this file since 39 was 39, checked in by bart, 3 years ago

Geniusweb 2.0.3. MOPAC protocol translated to Python. Small fixes.

File size: 5.9 KB
Line 
1package geniusweb.protocol.session.saop;
2
3import java.util.Collections;
4import java.util.HashSet;
5import java.util.List;
6import java.util.Map;
7
8import com.fasterxml.jackson.annotation.JsonCreator;
9import com.fasterxml.jackson.annotation.JsonProperty;
10
11import geniusweb.actions.Accept;
12import geniusweb.actions.Action;
13import geniusweb.actions.EndNegotiation;
14import geniusweb.actions.Offer;
15import geniusweb.actions.PartyId;
16import geniusweb.inform.Agreements;
17import geniusweb.issuevalue.Bid;
18import geniusweb.progress.Progress;
19import geniusweb.progress.ProgressRounds;
20import geniusweb.protocol.ProtocolException;
21import geniusweb.protocol.session.DefaultSessionState;
22import geniusweb.protocol.session.SessionResult;
23import geniusweb.references.PartyWithProfile;
24
25/**
26 * Immutable.
27 */
28public class SAOPState extends DefaultSessionState<SAOPState, SAOPSettings> {
29
30 /**
31 *
32 * @param actions the actions done by the parties
33 * @param connections the existing party connections. If null, default
34 * empty list is used. Can be less than 2 parties in
35 * the first phases of the setup or after parties
36 * disconnected.
37 * @param progress the {@link Progress} line. can be null
38 * @param settings the {@link SAOPSettings}
39 * @param partyprofiles map with the {@link PartyWithProfile} for connected
40 * parties. null is equivalent to an empty map.
41 * @param error the {@link ProtocolException}, or null if none
42 * occurred.
43 */
44 @JsonCreator
45 public SAOPState(@JsonProperty("actions") List<Action> actions,
46 @JsonProperty("connections") List<PartyId> connections,
47 @JsonProperty("progress") Progress progress,
48 @JsonProperty("settings") SAOPSettings settings,
49 @JsonProperty("partyprofiles") Map<PartyId, PartyWithProfile> partyprofiles,
50 @JsonProperty("error") ProtocolException error) {
51 super(actions, connections, progress, settings, partyprofiles, error);
52 }
53
54 @Override
55 public SAOPState with(List<Action> actions, List<PartyId> conns,
56 Progress progr, SAOPSettings settings,
57 Map<PartyId, PartyWithProfile> partyprofiles, ProtocolException e) {
58 return new SAOPState(actions, conns, progr, settings, partyprofiles, e);
59 }
60
61 /**
62 * Creates the initial state from the given settings and progress=null
63 *
64 * @param settings the {@link SAOPSettings}
65 */
66 public SAOPState(SAOPSettings settings) {
67 this(Collections.emptyList(), Collections.emptyList(), null, settings,
68 null, null);
69
70 }
71
72 @Override
73 public Agreements getAgreements() {
74 Agreements agree = new Agreements();
75 List<Action> acts = getActions();
76 int nparticipants = getConnections().size();
77 if (nparticipants < 2 || acts.size() < nparticipants) {
78 return agree;
79 }
80 Action offer = acts.get(acts.size() - nparticipants);
81 if (!(offer instanceof Offer))
82 return agree;
83 Bid bid = ((Offer) offer).getBid();
84
85 // check that the last n-1 are accepts.
86 boolean allaccept = acts.stream().skip(acts.size() - nparticipants + 1)
87 .allMatch(act -> act instanceof Accept
88 && bid.equals(((Accept) act).getBid()));
89 if (allaccept)
90 agree = agree
91 .with(new Agreements(bid, new HashSet<>(getParties())));
92 return agree;
93 }
94
95 /**
96 *
97 * @return all currently connected parties.
98 */
99 public List<PartyId> getParties() {
100 return getConnections();
101 }
102
103 @Override
104 public boolean isFinal(long currentTimeMs) {
105 List<Action> acts = getActions();
106 return super.isFinal(currentTimeMs)
107 || !getAgreements().getMap().isEmpty() || (!acts.isEmpty()
108 && acts.get(acts.size() - 1) instanceof EndNegotiation);
109 }
110
111 @Override
112 public SAOPState with(PartyId actor, Action action) {
113 return super.with(actor, action).with(advanceProgress());
114 }
115
116 @Override
117 public String checkAction(PartyId actor, Action action) {
118 String msg = super.checkAction(actor, action);
119 if (msg != null)
120 return msg;
121
122 if (!actor.equals(getNextActor()))
123 return "Party does not have the turn ";
124
125 // check protocol is followed for specific actions
126 if (action instanceof Accept) {
127 Bid bid = getLastBid();
128 if (bid == null)
129 return "Accept without a recent offer";
130
131 if (!bid.equals(((Accept) action).getBid()))
132 return "Party accepts a bid differing from the last offer ="
133 + bid + ", action=" + action + ")";
134 return null;
135 } else if (action instanceof Offer) {
136 return null;
137 } else if (action instanceof EndNegotiation) {
138 return null;
139 }
140 return "Action " + action + " is not allowed in SAOP";
141 }
142
143 /**
144 * Check up to nparticipants-1 steps back if there was an offer.
145 *
146 * @return Bid from the most recent offer, or null if no such offer
147 */
148 private Bid getLastBid() {
149 int nparticipants = getConnections().size();
150 List<Action> acts = getActions();
151 for (int n = acts.size() - 1; n > acts.size() - nparticipants
152 && n >= 0; n--) {
153 Action action = acts.get(n);
154 if (action instanceof Offer) {
155 return ((Offer) action).getBid();
156 }
157 }
158 return null;
159
160 }
161
162 /**
163 *
164 * @return the next actor in the current state. Assumes 1 action per actor
165 * every time. NOTE if party disconnects this would jump wildly but
166 * nego stops then anyway
167 */
168 protected PartyId getNextActor() {
169 return getConnections()
170 .get(getActions().size() % getConnections().size());
171 }
172
173 /**
174 * @return new progress state
175 */
176 public Progress advanceProgress() {
177 Progress newprogress = getProgress();
178 if (newprogress instanceof ProgressRounds && isLastActor()) {
179 newprogress = ((ProgressRounds) newprogress).advance();
180 }
181 return newprogress;
182 }
183
184 /**
185 * @return true if the current actor is the last actor in the list
186 */
187 private boolean isLastActor() {
188 int nparticipants = getConnections().size();
189 return getActions().size() % nparticipants == nparticipants - 1;
190 }
191
192 @Override
193 public SessionResult getResult() {
194 return new SessionResult(getPartyProfiles(), getAgreements(),
195 Collections.emptyMap(), getError());
196 }
197
198}
Note: See TracBrowser for help on using the repository browser.