source: src/main/java/agents/ai2014/group11/Group11.java@ 126

Last change on this file since 126 was 126, checked in by Aron Hammond, 6 years ago

Added function to calculate opposition to MultiLateralAnalysis.java

Moved code to add RLBOA listeners to RLBOAUtils is misc package

Added input for strategyParameters to SessionPanel (gui)

!! close SessionInfo after tournament; this caused /tmp/ to fill up with GeniusData files

Our own package:

  • Added opponents and strategies that are mentioned in the report
  • Change class hierarchy, agents can now extend from RLBOAagentBilateral to inherit RL functionality.
  • States extend from AbstractState
File size: 13.2 KB
Line 
1package agents.ai2014.group11;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.Comparator;
6import java.util.HashMap;
7import java.util.List;
8import java.util.Map.Entry;
9import java.util.Random;
10
11import agents.ai2014.group11.OpponentUtilityModel.InvalidBidException;
12import agents.ai2014.group11.OpponentUtilityModel.InvalidDomainException;
13import genius.core.AgentID;
14import genius.core.Bid;
15import genius.core.BidHistory;
16import genius.core.DeadlineType;
17import genius.core.actions.Accept;
18import genius.core.actions.Action;
19import genius.core.actions.DefaultAction;
20import genius.core.actions.EndNegotiation;
21import genius.core.actions.Inform;
22import genius.core.actions.Offer;
23import genius.core.bidding.BidDetails;
24import genius.core.boaframework.SortedOutcomeSpace;
25import genius.core.misc.Range;
26import genius.core.parties.AbstractNegotiationParty;
27import genius.core.parties.NegotiationInfo;
28
29/**
30 * This is your negotiation party.
31 */
32public class Group11 extends AbstractNegotiationParty {
33
34 private SortedOutcomeSpace possibleBids;
35 private ArrayList<BidDetailsWithNash> nashBids;
36 private HashMap<Object, OpponentUtilityModel> opponents;
37 private BidHistory allBids;
38 private int round;
39 private double lastUtility;
40 private static final double startReservationUtility = 0.95;
41 private double reservationUtility = startReservationUtility;
42
43 private int lastAcceptCount;
44
45 /**
46 * Please keep this constructor. This is called by genius.
47 *
48 * @param utilitySpace
49 * Your utility space.
50 * @param deadlines
51 * The deadlines set for this negotiation.
52 * @param timeline
53 * Value counting from 0 (start) to 1 (end).
54 * @param randomSeed
55 * If you use any randomization, use this seed for it.
56 */
57 @Override
58 public void init(NegotiationInfo info) {
59 super.init(info);
60
61 this.round = 0;
62 this.lastUtility = 1;
63
64 // create a list of bids
65 possibleBids = new SortedOutcomeSpace(utilitySpace);
66 allBids = new BidHistory();
67 opponents = new HashMap<Object, OpponentUtilityModel>();
68
69 utilitySpace.setReservationValue(reservationUtility);
70 }
71
72 /**
73 * Convenience method to make a new offer and save the relevant information
74 *
75 * @param bid
76 * @return
77 */
78 private Offer bid(Bid bid) {
79 BidDetails bd = new BidDetails(bid, getUtility(bid));
80 lastUtility = bd.getMyUndiscountedUtil();
81 allBids.add(bd);
82 return new Offer(getPartyId(), bid);
83 }
84
85 /**
86 * Each round this method gets called and ask you to accept or offer. The
87 * first party in the first round is a bit different, it can only propose an
88 * offer.
89 *
90 * @param validActions
91 * Either a list containing both accept and offer or only offer.
92 * @return The chosen action.
93 */
94 @Override
95 public Action chooseAction(List<Class<? extends Action>> validActions) {
96 this.round++;
97 double currentTime = getTime();
98 // if we are the first party, make the best offer.
99 if (!validActions.contains(Accept.class))
100 return getActionForTactic(Tactics.ASOCIAL);
101
102 // Give in to our reservation value in the endgame;
103 double timeTostartGiveInReservationValue = 0.9;
104 if (currentTime > timeTostartGiveInReservationValue) {
105 double giveInProgress = (currentTime - timeTostartGiveInReservationValue)
106 / (1 - timeTostartGiveInReservationValue);
107 reservationUtility = startReservationUtility - (0.4 * giveInProgress);
108 utilitySpace.setReservationValue(reservationUtility);
109 }
110
111 if (previousBidHasBeenAcceptedEnough()) {
112 reservationUtility *= 0.9;
113 }
114
115 BidDetails lastBid = allBids.getLastBidDetails();
116
117 if (currentTime > 0.95 || (lastBid != null && lastBid.getMyUndiscountedUtil() > reservationUtility)) {
118 return new Accept(getPartyId(), lastBid.getBid());
119 } else {
120 // Short negotiation
121 if (thereWillNeverBeATrustedOpponentModel()) {
122 if (previousBidHasBeenAcceptedEnough())
123 return getActionForTactic(Tactics.EDGEPUSHER);
124 else {
125 // No consensus yet
126 if (currentTime < 0.25) {
127 // First quarter:
128 return getActionForTactic(Tactics.HARDTOGET);
129 } else if (currentTime < 0.5) {
130 // Second quarter:
131 return getActionForTactic(Tactics.NOSTALGIAN);
132 } else {
133 // Last half:
134 return getActionForTactic(Tactics.GIVEIN);
135 }
136 }
137 } else {
138 // Long negotiation
139 if (weTrustOurOpponentModel()) {
140 // Enough rounds have passed
141 sortOutcomeSpaceOnNashProduct();
142
143 int unknownCounter = 0;
144 int modifyPreviousCounter = 0;
145 int modifySelfCounter = 0;
146 for (Entry<Object, OpponentUtilityModel> e : opponents.entrySet()) {
147 switch (e.getValue().getMostLikelyStrategy()) {
148 case UNKNOWN:
149 unknownCounter++;
150 break;
151 case MODIFY_PREVIOUS:
152 modifyPreviousCounter++;
153 break;
154 case MODIFY_SELF:
155 modifySelfCounter++;
156 break;
157 }
158 }
159
160 if (unknownCounter >= modifyPreviousCounter && unknownCounter >= modifySelfCounter)
161 return getActionForTactic(Tactics.BESTNASH);
162 else if (modifyPreviousCounter >= modifySelfCounter)
163 return getActionForTactic(Tactics.EDGEPUSHER);
164 else
165 return getActionForTactic(Tactics.BESTNASH);
166 } else {
167 // Build opponent model
168 return getActionForTactic(Tactics.RANDOM);
169 }
170 }
171 }
172 }
173
174 /**
175 * The minimum required rounds needed to make an opponent model
176 */
177 private static final int numberOfRoundForOpponentModel = 50;
178
179 /**
180 * Determine whether we will ever have an opponent model significant enough
181 *
182 * @return true iff there will never be a trusted opponent model
183 */
184 private boolean thereWillNeverBeATrustedOpponentModel() {
185 return (round / getTime()) < numberOfRoundForOpponentModel;
186 }
187
188 /**
189 * Determine whether the current opponent model is trustworthy based on the
190 * amount of rounds passed
191 *
192 * @return true iff the opponent model is trusted
193 */
194 private boolean weTrustOurOpponentModel() {
195 return round > numberOfRoundForOpponentModel;
196 }
197
198 /**
199 * Determine whether the previous bid has been accepted many times by other
200 * parties
201 *
202 * @return true iff enough parties have accepted the previous bid
203 */
204 private boolean previousBidHasBeenAcceptedEnough() {
205 // 0.7, because 2 otherParties, should result in 1 required accept
206 int requiredAccepts = (int) ((getNumberOfParties() - 1) * 0.7);
207 return lastAcceptCount != 0 && lastAcceptCount >= requiredAccepts;
208 }
209
210 /**
211 * Definition of the available tactics for this agent.
212 *
213 * RANDOM - Offer a random bid above your reservation value BESTNASH - Offer
214 * the best Nash bid according to opponent models NOSTALGIAN - Offer the
215 * best bid that has ever been done by any agent ASOCIAL - Offer the best
216 * bid possible for you HARDTOGET - Offer a bid of 0.99 * the previous
217 * utility EDGEPUSHER - Offer a bid slightly better than the one before
218 * GIVEIN - Offer a bid near your reservation value THEFINGER - Leave the
219 * negotiation
220 */
221 private enum Tactics {
222 RANDOM, BESTNASH, NOSTALGIAN, ASOCIAL, HARDTOGET, EDGEPUSHER, GIVEIN, THEFINGER
223 }
224
225 /**
226 * Based on a specific tactic and the internal parameters, this will give an
227 * action to perform.
228 *
229 * @param t
230 * @return
231 */
232 private Action getActionForTactic(Tactics t) {
233 // System.out.println("Round " + round + " | Tactic: " + t);
234 switch (t) {
235 case RANDOM:
236 // We don't want to bid under our reservation value
237 List<BidDetails> randomBids = possibleBids
238 .getBidsinRange(new Range(getUtilitySpace().getReservationValue(), 1));
239 if (randomBids.size() == 0) {
240 return getActionForTactic(Tactics.GIVEIN);
241 } else {
242 return bid(randomBids.get(new Random().nextInt(randomBids.size())).getBid());
243 }
244 case BESTNASH:
245 // In the assumption that our opponent does not do this as well,
246 // else this will keep on giving the same bid
247 return bid(nashBids.get(nashBids.size() - 1).getBid());
248 case NOSTALGIAN:
249 return bid(allBids.getBestBidDetails().getBid());
250 case ASOCIAL:
251 return bid(possibleBids.getMaxBidPossible().getBid());
252 case HARDTOGET:
253 return getOfferFromPreviousUtil(0.99);
254 case EDGEPUSHER:
255 // do a new bid that is a little better then last
256 Bid lastBid = allBids.getLastBid();
257 double lastUtil = getUtility(lastBid);
258 List<BidDetails> allBetterBids = possibleBids.getBidsinRange(new Range(lastUtil, 1));
259 // Get first that is better, since i don't know how getBidsInRange
260 // is
261 // sorted. Also I want to avoid picking the lastBid;
262 for (BidDetails bd : allBetterBids) {
263 if (bd.getMyUndiscountedUtil() > lastUtil)
264 return bid(bd.getBid());
265 }
266 // No better bid to find, accept as well
267 return new Accept(getPartyId(), lastBid);
268 case GIVEIN:
269 if (getTime() > 0.95)
270 return new Accept(getPartyId(), allBids.getLastBid());
271 else {
272 // double currentTime = getTime();
273 // double discount = Math.max(1,
274 // (-1.9531 * Math.pow(currentTime, 2))
275 // + (2.2251 * currentTime) + 0.3626);
276 // discount = 1.3 - (0.6 * currentTime);
277 return getOfferFromPreviousUtil(0.975);
278 }
279 case THEFINGER:
280 return new EndNegotiation(getPartyId());
281 default:
282 break;
283 }
284
285 return getActionForTactic(Tactics.ASOCIAL);
286 }
287
288 /**
289 * Get an offer with discount times the utility of your last utility
290 *
291 * @param discount
292 * multiplication factor
293 * @return
294 */
295 private Offer getOfferFromPreviousUtil(double discount) {
296 BidDetails bid = possibleBids.getBidNearUtility(discount * lastUtility);
297 return bid(bid.getBid());
298 }
299
300 /**
301 *
302 * @return the partial of rounds done, or 0 when there is no deadline
303 */
304 private double getTime() {
305 if (getDeadlines() != null) {
306 Integer d = getDeadlines().getType() == DeadlineType.ROUND ? getDeadlines().getValue() : 0;
307
308 if (d != null && d != 0) {
309 return (double) this.round / (int) d;
310 }
311 }
312 return getTimeLine().getTime();
313 }
314
315 /**
316 * All offers proposed by the other parties will be received as a message.
317 * You can use this information to your advantage, for example to predict
318 * their utility.
319 *
320 * @param sender
321 * The party that did the action.
322 * @param action
323 * The action that party did.
324 */
325 @Override
326 public void receiveMessage(AgentID sender, Action action) {
327 super.receiveMessage(sender, action);
328
329 // Here you can listen to other parties' messages
330
331 try {
332 OpponentUtilityModel opponent = opponents.get(sender);
333 if (opponent == null) {
334 opponent = new OpponentUtilityModel(getUtilitySpace().getDomain());
335 opponents.put(sender, opponent);
336 }
337 Bid prevousBid = allBids.getLastBid();
338
339 // Update opponent specific history
340 if (action instanceof Offer) {
341 // Update global history
342 Bid bid = DefaultAction.getBidFromAction(action);
343 BidDetails details = new BidDetails(bid, getUtility(bid));
344 allBids.add(details);
345
346 opponent.addOffer(prevousBid, bid);
347
348 lastAcceptCount = 0;
349 } else if (action instanceof Accept) {
350 opponent.addAccept(prevousBid);
351
352 lastAcceptCount++;
353 } else if (action instanceof Inform) {
354 // TODO handle info
355 // Inform inform = (Inform) action;
356 // if (inform.getName().equals("numParties")) {
357 // int numParties = ((Integer) inform.getValue()).intValue();
358 // for (int i = 0; i < numParties; i++) {
359 // System.out
360 // .println("Simon says: \"Welcome to the negotiation, party "
361 // + (i + 1) + "!\"");
362 // }
363 // }
364 } else {
365 System.out.println("WARNING :: UNKNOWN ACTION :: " + action.getClass().getCanonicalName());
366 }
367 } catch (InvalidDomainException e) {
368 e.printStackTrace();
369 } catch (InvalidBidException e) {
370 e.printStackTrace();
371 }
372 }
373
374 /**
375 * Method to set up some of the internal parameters.
376 *
377 * Creates from the list of possible bids a list of bids sorted on Nash
378 * product, determined by the opponent models available.
379 */
380 private void sortOutcomeSpaceOnNashProduct() {
381 ArrayList<OpponentUtilityModel> opponentModels = new ArrayList<OpponentUtilityModel>();
382 for (Entry<Object, OpponentUtilityModel> e : opponents.entrySet()) {
383 opponentModels.add(e.getValue());
384 }
385
386 List<BidDetails> bids = possibleBids.getAllOutcomes();
387 ArrayList<BidDetailsWithNash> nashes = new ArrayList<BidDetailsWithNash>();
388
389 for (BidDetails bd : bids) {
390 nashes.add(new BidDetailsWithNash(bd.getBid(), getNashUtilityProduct(bd.getBid(), opponentModels)));
391 }
392
393 Collections.sort(nashes, new Comparator<BidDetailsWithNash>() {
394 @Override
395 public int compare(BidDetailsWithNash lbdwn, BidDetailsWithNash rbdwn) {
396 // Big value (1000000000) is because else the values would be so
397 // small that Java would throw a 'MisuseOfContractException'
398 return (int) (2000000000 * (lbdwn.getEstimatedNashValue() - rbdwn.getEstimatedNashValue()));
399 }
400 });
401
402 nashBids = nashes;
403 }
404
405 /**
406 * Based on a list of opponent models, this function determines the Nash
407 * product for a certain bid.
408 *
409 * @param b
410 * Bid to evaluate
411 * @param opponentModels
412 * list of opponents
413 * @return Nash product
414 */
415 private double getNashUtilityProduct(Bid b, ArrayList<OpponentUtilityModel> opponentModels) {
416
417 double res = getUtility(b);
418 for (OpponentUtilityModel m : opponentModels) {
419 try {
420 double util = m.getUtility(b);
421 if (!Double.isNaN(util))
422 res *= util;
423 } catch (InvalidBidException e) {
424 e.printStackTrace();
425 }
426 }
427
428 return res;
429 }
430
431 protected AgentID partyId = new AgentID("Group 11");
432
433 @Override
434 public String getDescription() {
435 return "ai2014 group11";
436 }
437
438}
Note: See TracBrowser for help on using the repository browser.