source: CSE3210/agent14/agent14.py

Last change on this file was 74, checked in by wouter, 21 months ago

#6 Added CSE3210 parties

File size: 7.2 KB
Line 
1import logging
2import time
3from decimal import Decimal
4from typing import cast
5
6from geniusweb.actions.Accept import Accept
7from geniusweb.actions.Action import Action
8from geniusweb.actions.Offer import Offer
9from geniusweb.bidspace.BidsWithUtility import BidsWithUtility
10from geniusweb.bidspace.Interval import Interval
11from geniusweb.inform.ActionDone import ActionDone
12from geniusweb.inform.Finished import Finished
13from geniusweb.inform.Inform import Inform
14from geniusweb.inform.Settings import Settings
15from geniusweb.inform.YourTurn import YourTurn
16from geniusweb.issuevalue.Bid import Bid
17from geniusweb.opponentmodel.FrequencyOpponentModel import FrequencyOpponentModel
18from geniusweb.party.Capabilities import Capabilities
19from geniusweb.party.DefaultParty import DefaultParty
20from geniusweb.profileconnection.ProfileConnectionFactory import (
21 ProfileConnectionFactory,
22)
23from geniusweb.progress.ProgressRounds import ProgressRounds
24from tudelft_utilities_logging.Reporter import Reporter
25
26
27class Agent14(DefaultParty):
28
29 def __init__(self, reporter: Reporter = None):
30 super().__init__(reporter)
31 self.getReporter().log(logging.INFO, "party is initialized")
32 self._last_received_bid = None
33 self.last_my_utility = 1
34 self.last_bids = []
35
36 def notifyChange(self, info: Inform):
37 """This is the entry point of all interaction with your agent after is has been initialised.
38
39 Args:
40 info (Inform): Contains either a request for action or information.
41 """
42
43 # a Settings message is the first message that will be send to your
44 # agent containing all the information about the negotiation session.
45 if isinstance(info, Settings):
46 self._settings: Settings = cast(Settings, info)
47 self._me = self._settings.getID()
48
49 # progress towards the deadline has to be tracked manually through the use of the Progress object
50 self._progress = self._settings.getProgress()
51 # the profile contains the preferences of the agent over the domain
52 self._profile = ProfileConnectionFactory.create(
53 info.getProfile().getURI(), self.getReporter()
54 )
55 # initialize FrequencyOpponentModel
56 self._opponent_model = FrequencyOpponentModel.create().With(
57 newDomain=self._profile.getProfile().getDomain(),
58 newResBid=self._profile.getProfile().getReservationBid())
59
60 # sort all issues by relevance
61 profile = self._profile.getProfile()
62 issue_infos = BidsWithUtility._getInfo(profile, 6)
63 weights = self._profile.getProfile().getWeights()
64 issue_infos.sort(key=lambda x: weights[x.getName()])
65 issue_infos.reverse()
66
67 # initialize BidsWithUtility with sorted issues
68 self._all_bids = BidsWithUtility(issue_infos, 6)
69
70 # ActionDone is an action send by an opponent (an offer or an accept)
71 elif isinstance(info, ActionDone):
72 action: Action = cast(ActionDone, info).getAction()
73
74 # if it is an offer, set the last received bid
75 if isinstance(action, Offer):
76 self._last_received_bid = cast(Offer, action).getBid()
77
78 if self._last_received_bid:
79 # Adjust FrequencyOpponentModel with new bid
80 self._opponent_model = self._opponent_model.WithAction(action=action, progress=self._progress)
81 # YourTurn notifies you that it is your turn to act
82 elif isinstance(info, YourTurn):
83 action = self._myTurn()
84 if isinstance(self._progress, ProgressRounds):
85 self._progress = self._progress.advance()
86 self.getConnection().send(action)
87
88 # Finished will be send if the negotiation has ended (through agreement or deadline)
89 elif isinstance(info, Finished):
90 # terminate the agent MUST BE CALLED
91 self.terminate()
92 else:
93 self.getReporter().log(
94 logging.WARNING, "Ignoring unknown info " + str(info)
95 )
96
97 # lets the geniusweb system know what settings this agent can handle
98 # leave it as it is for this competition
99 def getCapabilities(self) -> Capabilities:
100 return Capabilities(
101 set(["SAOP"]),
102 set(["geniusweb.profile.utilityspace.LinearAdditive"]),
103 )
104
105 # terminates the agent and its connections
106 # leave it as it is for this competition
107 def terminate(self):
108 self.getReporter().log(logging.INFO, "party is terminating:")
109 super().terminate()
110 if self._profile is not None:
111 self._profile.close()
112 self._profile = None
113
114 # give a description of your agent
115 def getDescription(self) -> str:
116 return "Group 14 Negotiation agent"
117
118 # execute a turn
119 def _myTurn(self):
120 # check if the last received offer if the opponent is good enough
121 if self._isGood(self._last_received_bid):
122 # if so, accept the offer
123 action = Accept(self._me, self._last_received_bid)
124 else:
125 # if not, find a bid to propose as counter offer
126 bid = self._findBid()
127 action = Offer(self._me, bid)
128
129 # send the action
130 return action
131
132 # method that checks if we would agree with an offer.
133 # our agent accepts the offer only if utility received is higher than
134 # last utility calculated by _getNextUtility
135 def _isGood(self, bid: Bid) -> bool:
136 if bid is None:
137 return False
138 return self._profile.getProfile().getUtility(bid) >= self.last_my_utility
139
140 # This calculates utility of the next bid agent should make
141 # e in range [1, inf] - exponential coefficient
142 # k in range [1, inf] - linear coefficient
143 def _getNextUtility(self, e, k):
144 util = 1 - self._progress.get(time.time() * 1000) ** e - 1/k * self._progress.get(time.time() * 1000)
145 return util
146
147 def _findBid(self) -> Bid:
148 # Calculate next utility
149 # Optimal values are k=4 and e=10
150 utility = Decimal(self._getNextUtility(4, 10))
151 eps = Decimal(0.01)
152
153 # Looks for bids in BidsUtilitySpace in interval(utility-eps, utility+eps)
154 # In case no bids found, extends interval
155 best_bid = None
156 while best_bid is None:
157 bids_interval = self._all_bids.getBids(Interval(min=utility - eps, max=utility + eps))
158
159 # Finds the maximum utility bid for the opponent in interval
160 max_util = Decimal(0)
161 for bid in bids_interval:
162 # Making sure that bid was not proposed in last n turns
163 # Optimal parameter for n is 5
164 if bid not in self.last_bids[-5:]:
165 bid_util = self._opponent_model.getUtility(bid)
166 if bid_util >= max_util:
167 best_bid = bid
168 max_util = bid_util
169 eps = eps + Decimal(0.01)
170
171 self.last_my_utility = utility
172 self.last_best_bid = best_bid
173 self.last_bids.append(best_bid)
174 return best_bid
Note: See TracBrowser for help on using the repository browser.