1 | from decimal import Decimal
|
---|
2 | from random import randint
|
---|
3 | from typing import cast
|
---|
4 |
|
---|
5 | from geniusweb.bidspace.AllBidsList import AllBidsList
|
---|
6 |
|
---|
7 | from ..Constants import Constants
|
---|
8 |
|
---|
9 |
|
---|
10 | class TradeOff:
|
---|
11 | def __init__(self, profile, opponent_model, offer, domain):
|
---|
12 | self._profile = profile
|
---|
13 | self._opponent_model = opponent_model
|
---|
14 | self._offer = offer
|
---|
15 | self._tolerance = Constants.iso_bids_tolerance
|
---|
16 | self._domain = domain
|
---|
17 | self._issues = domain.getIssues()
|
---|
18 | self._sorted_bids = self._sort_bids(AllBidsList(self._domain))
|
---|
19 |
|
---|
20 | # sort bids on Utility descending
|
---|
21 | def _sort_bids(self, all_bids):
|
---|
22 | bids = []
|
---|
23 | for b in all_bids:
|
---|
24 | bid = {"bid": b, "utility": self._profile.getUtility(b)}
|
---|
25 | bids.append(bid)
|
---|
26 | return sorted(bids, key=lambda d: d['utility'], reverse=True)
|
---|
27 |
|
---|
28 | # return set of iso curve bids
|
---|
29 | def _iso_bids(self, n=5):
|
---|
30 | bids = []
|
---|
31 | i = 0
|
---|
32 | for bid in self._sorted_bids:
|
---|
33 | if self._offer + self._tolerance > bid["utility"] > self._offer - self._tolerance:
|
---|
34 | bids.append(bid["bid"])
|
---|
35 | i += 1
|
---|
36 | if i == n:
|
---|
37 | break
|
---|
38 | return bids
|
---|
39 |
|
---|
40 | # return a random bid
|
---|
41 | def _get_random_bid(self):
|
---|
42 | all_bids = AllBidsList(self._domain)
|
---|
43 | return all_bids.get(randint(0, all_bids.size() - 1))
|
---|
44 |
|
---|
45 | # decrease our utility if we do not make any progress
|
---|
46 | def _decrease_offer(self, received_bids, sent_bids, boulware):
|
---|
47 | if len(sent_bids) > 3:
|
---|
48 | utilLast = self._profile.getUtility(sent_bids[len(sent_bids) - 1])
|
---|
49 | utilThreeStepsAgo = self._profile.getUtility(sent_bids[len(sent_bids) - 4])
|
---|
50 | opponentUtilLast = self._profile.getUtility(received_bids[len(received_bids) - 1])
|
---|
51 | opponentUtilOneStepAgo = self._profile.getUtility(received_bids[len(received_bids) - 2])
|
---|
52 | if utilLast == utilThreeStepsAgo and opponentUtilLast <= opponentUtilOneStepAgo:
|
---|
53 | self._offer = boulware
|
---|
54 |
|
---|
55 | # find a bid by using trade off strategy
|
---|
56 | def find_bid(self, opponent_model, last_opponent_bid, received_bids, sent_bids, boulware):
|
---|
57 | self._opponent_model = opponent_model
|
---|
58 |
|
---|
59 | self._decrease_offer(received_bids, sent_bids, boulware)
|
---|
60 |
|
---|
61 | # generate n bids
|
---|
62 | bids = self._iso_bids()
|
---|
63 |
|
---|
64 | if last_opponent_bid is None:
|
---|
65 | if len(bids) > 0:
|
---|
66 | return bids[0]
|
---|
67 | else:
|
---|
68 | return self._get_random_bid()
|
---|
69 |
|
---|
70 | if len(bids) == 0:
|
---|
71 | return self._get_random_bid()
|
---|
72 |
|
---|
73 | # choose bid with maximum utility for opponent
|
---|
74 | best_bid = bids[0]
|
---|
75 | max_util = 0
|
---|
76 | for bid in bids:
|
---|
77 | util = self._opponent_model.utility(bid)
|
---|
78 | if util > max_util:
|
---|
79 | best_bid = bid
|
---|
80 | max_util = util
|
---|
81 |
|
---|
82 | return best_bid
|
---|