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

Last change on this file since 127 was 127, checked in by Wouter Pasman, 6 years ago

#41 ROLL BACK of rev.126 . So this version is equal to rev. 125

File size: 13.6 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.