source: ANL2022/tjaronchery10_agent/tjaronchery10_agent.py

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

#6 added ANAC2022 parties

File size: 13.1 KB
Line 
1import json
2import random
3import logging
4from random import randint
5from time import time
6from typing import cast
7from utils.plot_trace import plot_trace
8from utils.runners import run_session
9from geniusweb.actions.Accept import Accept
10from geniusweb.actions.Action import Action
11from geniusweb.actions.Offer import Offer
12from geniusweb.actions.PartyId import PartyId
13from geniusweb.bidspace.AllBidsList import AllBidsList
14from geniusweb.inform.ActionDone import ActionDone
15from geniusweb.inform.Finished import Finished
16from geniusweb.inform.Inform import Inform
17from geniusweb.inform.Settings import Settings
18from geniusweb.inform.YourTurn import YourTurn
19from geniusweb.issuevalue.Bid import Bid
20from geniusweb.issuevalue.Domain import Domain
21from geniusweb.party.Capabilities import Capabilities
22from geniusweb.party.DefaultParty import DefaultParty
23from geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace import (
24 LinearAdditiveUtilitySpace,
25)
26from geniusweb.profileconnection.ProfileConnectionFactory import (
27 ProfileConnectionFactory,
28)
29from geniusweb.progress.ProgressTime import ProgressTime
30from geniusweb.references.Parameters import Parameters
31from tudelft_utilities_logging.ReportToLogger import ReportToLogger
32
33from .utils.opponent_model import OpponentModel
34
35
36class Tjaronchery10Agent(DefaultParty):
37 """
38 Template of a Python geniusweb agent.
39 """
40
41 def __init__(self):
42 super().__init__()
43 self.logger: ReportToLogger = self.getReporter()
44 self.tatic = 1
45 self.domain: Domain = None
46 self.parameters: Parameters = None
47 self.profile: LinearAdditiveUtilitySpace = None
48 self.progress: ProgressTime = None
49 self.me: PartyId = None
50 self.other: str = None
51 self.settings: Settings = None
52 self.storage_dir: str = None
53 self.datii = ""
54 self.last_received_bid: Bid = None
55 self.counter = 0
56 self.minicount = 0
57 self.flag = 0
58 self.dupli = 0.00
59 self.opponent_model: OpponentModel = None
60 self.logger.log(logging.INFO, "party is initialized")
61
62 def notifyChange(self, data: Inform):
63 """MUST BE IMPLEMENTED
64 This is the entry point of all interaction with your agent after is has been initialised.
65 How to handle the received data is based on its class type.
66
67 Args:
68 info (Inform): Contains either a request for action or information.
69 """
70
71 # a Settings message is the first message that will be send to your
72 # agent containing all the information about the negotiation session.
73
74 if isinstance(data, Settings):
75 self.settings = cast(Settings, data)
76 self.me = self.settings.getID()
77 # progress towards the deadline has to be tracked manually through the use of the Progress object
78 self.progress = self.settings.getProgress()
79
80 self.parameters = self.settings.getParameters()
81 self.storage_dir = self.parameters.get("storage_dir")
82
83 # the profile contains the preferences of the agent over the domain
84 profile_connection = ProfileConnectionFactory.create(
85 data.getProfile().getURI(), self.getReporter()
86 )
87 self.profile = profile_connection.getProfile()
88 self.domain = self.profile.getDomain()
89 profile_connection.close()
90
91 # ActionDone informs you of an action (an offer or an accept)
92 # that is performed by one of the agents (including yourself).
93 elif isinstance(data, ActionDone):
94 action = cast(ActionDone, data).getAction()
95 actor = action.getActor()
96
97 # ignore action if it is our action
98 if actor != self.me:
99 # obtain the name of the opponent, cutting of the position ID.
100 self.other = str(actor).rsplit("_", 1)[0]
101
102 if self.counter > 3:
103 with open(f"{self.storage_dir}/{self.other}datatactic.txt", "r") as t:
104 shura = t.readline()
105 if shura.__contains__("tac2"):
106 self.tatic = 2
107 t.close()
108 else:
109 with open(f"{self.storage_dir}/{self.other}data.txt", "r") as f:
110 lines = f.readlines()
111 last_lines = lines[-3:]
112 if last_lines[0] == '0\n' and last_lines[1] == '0\n' and last_lines[2] == '0\n':
113 # print("THIS IS MACABBIIIIIIIIIIIIIIIIIIIIIII")
114 self.tatic = 2
115 with open(f"{self.storage_dir}/{self.other}datatactic.txt", "a") as x:
116 x.write("tac2")
117 x.close()
118 else:
119 self.tatic = 1
120 f.close()
121 self.flag = 1
122 # process action done by opponent
123 self.opponent_action(action)
124 # YourTurn notifies you that it is your turn to act
125 elif isinstance(data, YourTurn):
126 # execute a turn
127 self.my_turn()
128
129 # Finished will be send if the negotiation has ended (through agreement or deadline)
130 elif isinstance(data, Finished):
131 self.save_data()
132 # terminate the agent MUST BE CALLED
133 self.logger.log(logging.INFO, "party is terminating:")
134 super().terminate()
135 else:
136 self.logger.log(logging.WARNING, "Ignoring unknown info " + str(data))
137
138 def getCapabilities(self) -> Capabilities:
139 """MUST BE IMPLEMENTED
140 Method to indicate to the protocol what the capabilities of this agent are.
141 Leave it as is for the ANL 2022 competition
142
143 Returns:
144 Capabilities: Capabilities representation class
145 """
146 return Capabilities(
147 set(["SAOP"]),
148 set(["geniusweb.profile.utilityspace.LinearAdditive"]),
149 )
150
151 def send_action(self, action: Action):
152 """Sends an action to the opponent(s)
153
154 Args:
155 action (Action): action of this agent
156 """
157 self.getConnection().send(action)
158
159 # give a description of your agent
160 def getDescription(self) -> str:
161 """MUST BE IMPLEMENTED
162 Returns a description of your agent. 1 or 2 sentences.
163
164 Returns:
165 str: Agent description
166 """
167 return "mine agent for the ANL 2022 competition"
168
169 def opponent_action(self, action):
170 """Process an action that was received from the opponent.
171
172 Args:
173 action (Action): action of opponent
174 """
175 # if it is an offer, set the last received bid
176 if isinstance(action, Offer):
177 # create opponent model if it was not yet initialised
178 if self.opponent_model is None:
179 self.opponent_model = OpponentModel(self.domain)
180
181 bid = cast(Offer, action).getBid()
182
183 # update opponent model with bid
184 self.opponent_model.update(bid)
185 # set bid as last received
186 self.last_received_bid = bid
187
188 def my_turn(self):
189 """This method is called when it is our turn. It should decide upon an action
190 to perform and send this action to the opponent.
191 """
192 # check if the last received offer is good enough
193 if self.minicount == 0:
194 try:
195 with open(f"{self.storage_dir}/{self.other}counter.txt", "r") as tt:
196 a = 1
197 content = tt.readlines()
198 tt.close()
199 for line in content:
200 for i in line:
201 # Checking for the digit in
202 # the string
203 if i.isdigit() == True:
204 a += int(i)
205 num = a
206 self.counter = num
207 print("this is macabiiiiiiiiiiiiiii")
208 print(num)
209 try:
210 with open(f"{self.storage_dir}/{self.other}counter.txt", "w") as ttt:
211 ttt.write(num.__str__())
212 ttt.close()
213 except FileNotFoundError:
214 print("file does not exist1 :(")
215 except FileNotFoundError:
216 print("file does not exist counter :(")
217 self.minicount = 1
218
219 if self.accept_condition(self.last_received_bid):
220 # if so, accept the offer
221 self.datii = self.profile.getUtility(self.last_received_bid).__str__()
222 action = Accept(self.me, self.last_received_bid)
223 else:
224 # if not, find a bid to propose as counter offer
225 bid = self.find_bid()
226
227 action = Offer(self.me, bid)
228 self.datii = self.profile.getUtility(bid).__str__()
229
230 # send the action
231 self.send_action(action)
232
233 def save_data(self):
234 """This method is called after the negotiation is finished. It can be used to store data
235 for learning capabilities. Note that no extensive calculations can be done within this method.
236 Taking too much time might result in your agent being killed, so use it for storage only.
237 """
238 data = "Data for learning (see README.md)"
239 progress = self.progress.get(time() * 1000)
240 s = self.datii
241 t = self.me.__str__()
242 r = self.settings.getID().__str__()
243 y = self.other
244 # path = self.storage_dir
245 # path = f"{self.storage_dir}/{y}"
246 # print(path)
247
248 if progress == 1:
249 s = 0
250 with open(f"{self.storage_dir}/{y}data.txt", "a") as f:
251 f.write(f"{s}\n")
252 f.close()
253 with open(f"{self.storage_dir}/{y}datatactic.txt", "a") as t:
254 t.close()
255 if self.counter == 0:
256 print("OPEN FILEEEEEEEEE")
257 with open(f"{self.storage_dir}/{y}counter.txt", "a") as x:
258 x.write("1\n")
259 x.close()
260
261
262 ###########################################################################################
263 ################################## Example methods below ##################################
264 ###########################################################################################
265
266 def accept_condition(self, bid: Bid) -> bool:
267 if bid is None:
268 return False
269
270 # progress of the negotiation session between 0 and 1 (1 is deadline)
271 progress = self.progress.get(time() * 1000)
272
273 # very basic approach that accepts if the offer is valued above 0.7 and
274 # 95% of the time towards the deadline has passed
275 # rand_b = 0.9
276 my_bid = self.find_bid()
277 # num = self.profile.getUtility(my_bid)
278 if self.tatic == 2:
279 conditions = [
280 self.profile.getUtility(bid) > 0.25,
281 progress > 0.8
282 ]
283
284 else:
285 conditions = [
286 self.profile.getUtility(bid) > 0.9,
287 # progress > 0.8,
288 ]
289 return all(conditions)
290
291 def find_bid(self) -> Bid:
292 # compose a list of all possible bids
293 domain = self.profile.getDomain()
294 all_bids = AllBidsList(domain)
295
296 best_bid_score = 0.0
297 best_bid = None
298
299 # take 500 attempts to find a bid according to a heuristic score
300 if self.tatic == 2:
301 for _ in range(1000):
302 bid = all_bids.get(randint(0, all_bids.size() - 1))
303 bid_score = self.score_bid(bid)
304 #bid_score = self.profile.getUtility(bid)
305
306 if 0.5 < bid_score < 0.9:
307 best_bid_score, best_bid = bid_score, bid
308
309 else:
310 for _ in range(1000):
311 bid = all_bids.get(randint(0, all_bids.size() - 1))
312 # bid_score = self.score_bid(bid)
313 bid_score = self.profile.getUtility(bid)
314 if bid_score > best_bid_score:
315 best_bid_score, best_bid = bid_score, bid
316
317 return best_bid
318
319 def score_bid(self, bid: Bid, alpha: float = 0.95, eps: float = 0.1) -> float:
320 """Calculate heuristic score for a bid
321
322 Args:
323 bid (Bid): Bid to score
324 alpha (float, optional): Trade-off factor between self interested and
325 altruistic behaviour. Defaults to 0.95.
326 eps (float, optional): Time pressure factor, balances between conceding
327 and Boulware behaviour over time. Defaults to 0.1.
328
329 Returns:
330 float: score
331 """
332 progress = self.progress.get(time() * 1000)
333
334 our_utility = float(self.profile.getUtility(bid))
335
336 time_pressure = 0.8 - progress ** (1 / eps)
337 score = alpha * time_pressure * our_utility
338 #score = our_utility
339
340 if self.opponent_model is not None:
341 opponent_utility = self.opponent_model.get_predicted_utility(bid)
342 opponent_score = (1.0 - alpha * time_pressure) * opponent_utility
343 score += opponent_score
344
345 return score
Note: See TracBrowser for help on using the repository browser.