-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstrategic_api.py
517 lines (392 loc) · 19.6 KB
/
strategic_api.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
from tactical_api import TurnContext
class StrategicApi(object):
def __init__(self, context: TurnContext):
"""Constructor. context allows us to use the tactical API."""
self.context = context
# ----------------------------------------------------------------------------
# Attacking military commands.
# ----------------------------------------------------------------------------
def attack(self, pieces, destination, radius):
"""Attack the area around the destination, using the given pieces.
This command should be interepreted as attacking a tile, whose distance of
`destination` is at most `radius` using the given set of `pieces` (set of
`StrategicPiece`s).
This method should return a command identifier.
"""
raise NotImplementedError()
def estimate_attack_time(self, pieces, destination, radius):
"""Estimate the amount of required turns for an attack command.
This method should return an integer, that is the estimated amount of
turns required for completing an attack command with the given arguments.
"""
raise NotImplementedError()
def report_attack_command_status(self, command_id):
"""Given a command identifier, report its status.
The returned value must be of type `CommandStatus`.
"""
raise NotImplementedError()
def report_attacking_pieces(self):
"""Report the current status of all attacking pieces.
The returned value should be a dict, mapping from StrategicPiece to its
current command ID that it is executing. Only attacking pieces should be
included in this report.
"""
raise NotImplementedError()
def estimated_required_attacking_pieces(self, destination, radius):
"""Estimates the amount of required pieces for conquering the destination.
The return value should be an integer.
"""
raise NotImplementedError()
def report_missing_intelligence_for_pending_attacks(self):
"""Return all coordinates in which we are missing intelligence.
Intelligence from the returned tiles would help in improving pending
attack commands.
The returned value should be a set of `Coordinates`s.
"""
raise NotImplementedError()
def set_intelligence_for_attacks(self, tiles):
"""Provide the implementation with missing intelligence for attacks.
`tiles` is a `dict` mapping a `Coordinates` object into an `int`,
representing the danger level of this tile.
This function does not return any value.
"""
raise NotImplementedError()
def report_required_pieces_for_attacks(self):
"""Returns a list of pieces, where they are needed and their priority.
This method returns a list of tuples, each containing the following values
(in this order):
0. Piece type (as `str`).
1. Destination tile (as `Coordinates`).
2. Improtance (as `int`).
"""
raise NotImplementedError()
def report_required_tiles_for_attacks(self):
"""Returns a list of tiles that are required for completing commands.
This mehtod returns a list of tuples, each containing the following values
(in this order):
0. Tile (as `Coordinates`).
1. Importance (as `int`).
"""
raise NotImplementedError()
def esscort_piece_with_attacking_piece(self, piece, pieces):
"""Esscort the given `piece` with the attacking `pieces`.
When this command is given, each piece in `pieces` should esscort `piece`.
`piece` is a `StrategicPiece`, and `pieces` is a `set` of
`StrategicPiece`s.
This method should return a command ID.
"""
raise NotImplementedError()
# ----------------------------------------------------------------------------
# Defensive military commands.
# ----------------------------------------------------------------------------
def defend(self, pieces, destination, radius):
"""Defend the area around the destination, using the given pieces.
This command should be interepreted as defending a tile, whose distance of
`destination` is at most `radius` using the given set of `pieces` (set of
`StrategicPiece`s).
This method should return a command identifier.
"""
raise NotImplementedError()
def estimate_defend_time(self, pieces, destination, radius):
"""Estimate the amount of required turns form a defense.
This method should return an integer, that is the estimated amount of
turns required for forming a defense command with the given arguments.
"""
raise NotImplementedError()
def report_defense_command_status(self, command_id):
"""Given a command identifier, report its status.
The returned value must be of type `CommandStatus`.
"""
raise NotImplementedError()
def report_defending_pieces(self):
"""Report the current status of all defending pieces.
The returned value should be a dict, mapping from StrategicPiece to its
current command ID that it is executing. Only defending pieces should be
included in this report.
"""
raise NotImplementedError()
def estimated_required_defending_pieces(self, destination, radius):
"""Estimates the amount of required pieces for defending the destination.
The return value should be an integer.
"""
raise NotImplementedError()
def report_missing_intelligence_for_pending_defends(self):
"""Return all coordinates in which we are missing intelligence.
Intelligence from the returned tiles would help in improving pending
defend commands.
The returned value should be a set of `Coordinates`s.
"""
raise NotImplementedError()
def set_intelligence_for_defends(self, tiles):
"""Provide the implementation with missing intelligence for defends.
`tiles` is a `dict` mapping a `Coordinates` object into an `int`,
representing the danger level of this tile.
This function does not return any value.
"""
raise NotImplementedError()
def report_required_pieces_for_defends(self):
"""Returns a list of pieces, where they are needed and their priority.
This method returns a list of tuples, each containing the following values
(in this order):
0. Piece type (as `str`).
1. Destination tile (as `Coordinates`).
2. Improtance (as `int`).
"""
raise NotImplementedError()
def report_required_tiles_for_defends(self):
"""Returns a list of tiles that are required for completing commands.
This mehtod returns a list of tuples, each containing the following values
(in this order):
0. Tile (as `Coordinates`).
1. Importance (as `int`).
"""
raise NotImplementedError()
def esscort_piece_with_defending_piece(self, piece, pieces):
"""Esscort the given `piece` with the defending `pieces`.
When this command is given, each piece in `pieces` should esscort `piece`.
`piece` is a `StrategicPiece`, and `pieces` is a `set` of
`StrategicPiece`s.
This method should return a command ID.
"""
raise NotImplementedError()
# ----------------------------------------------------------------------------
# Intelligence commands.
# ----------------------------------------------------------------------------
def estimate_tile_danger(self, destination):
"""Estimate the danger level of the given destination.
`destination` should be a `Coordinates` object.
The returned value is an `int`.
"""
raise NotImplementedError()
def gather_intelligence(self, pieces, destination, radius):
"""Get intelligence of the area around the destination, using `pieces`.
This method should return a command identifier.
"""
raise NotImplementedError()
def estimate_gathering_time(self, pieces, destination, radius):
"""Estimate the amount of required turns for gathering intelligence.
This method should return an integer, that is the estimated amount of
turns required for gathering intelligence command with the given arguments.
"""
raise NotImplementedError()
def report_gathering_command_status(self, command_id):
"""Given a command identifier, report its status.
The returned value must be of type `CommandStatus`.
"""
raise NotImplementedError()
def report_intelligence_pieces(self):
"""Report the current status of all intelligence pieces.
The returned value should be a dict, mapping from StrategicPiece to its
current command ID that it is executing. Only intelligence pieces should be
included in this report.
"""
raise NotImplementedError()
def report_required_pieces_for_intelligence(self):
"""Returns a list of pieces, where they are needed and their priority.
This method returns a list of tuples, each containing the following values
(in this order):
0. Piece type (as `str`).
1. Destination tile (as `Coordinates`).
2. Improtance (as `int`).
"""
raise NotImplementedError()
def report_required_tiles_for_intelligence(self):
"""Returns a list of tiles that are required for completing commands.
This mehtod returns a list of tuples, each containing the following values
(in this order):
0. Tile (as `Coordinates`).
1. Importance (as `int`).
"""
raise NotImplementedError()
def esscort_piece_with_intelligence_piece(self, piece, pieces):
"""Esscort the given `piece` with the intelligence `pieces`.
When this command is given, each piece in `pieces` should esscort `piece`.
`piece` is a `StrategicPiece`, and `pieces` is a `set` of
`StrategicPiece`s.
This method should return a command ID.
"""
raise NotImplementedError()
# ----------------------------------------------------------------------------
# Building commands.
# ----------------------------------------------------------------------------
def collect_money(self, builder, amount):
"""Collect a certain amount of money by the given `builder`.
`builder` should be a `StrategicPiece` object. `amount` should be an `int`.
This method should return a command ID.
"""
raise NotImplementedError()
def estimate_collection_time(self, builder, amount):
"""Estimate the required amount of turns for collecting money.
This method should return an `int`, that is the estimated amount of turns
required for collecting the given `amount` of money by the given `builder`.
"""
raise NotImplementedError()
def build_piece(self, builder, piece_type):
"""Build a new piece of type `piece_type` using `builder`.
This methos should be interpreted as "Build a new piece using the given
`builder`". If the given `builder` does not posses the required amount of
money for building the required new piece, it should collect it first, and
then build the new piece.
`builder` should be a `StrategicPiece` object. `piece_type` is a `str`.
This method returns a command ID.
"""
raise NotImplementedError()
def estimate_building_time(self, builder, piece_type):
"""Estimate the amount of required turns for building a new piece.
This method should return an integer, that is the estimated amount of
turns required for building a new piece with the given arguments.
"""
raise NotImplementedError()
def report_build_command_status(self, command_id):
"""Given a command identifier, report its status.
The returned value must be of type `CommandStatus`.
"""
raise NotImplementedError()
def get_total_builders_money(self):
"""Returns the total amount of money all the country builders have."""
raise NotImplementedError()
def get_total_country_tiles_money(self):
"""Returns the total amount of money the country has on its tiles."""
raise NotImplementedError()
def report_builders(self):
"""Report the current status of all builders.
The returned value should be a `dict`, mapping from a `StrategicPiece`
objects to a tuple, containing the following values in this order:
0. The current command ID that this builder is executing, if available, or
`None` otherwise.
1. The current amount of money of this builder.
"""
raise NotImplementedError()
def report_missing_intelligence_for_collecting_money(self):
"""Return all coordinates in which we are missing intelligence.
Intelligence from the returned tiles would help in collecting more money.
The returned value should be a set of `Coordinates`s.
"""
raise NotImplementedError()
def set_intelligence_for_builders(self, tiles):
"""Provide the implementation with intelligence for collecting money.
`tiles` is a `dict` mapping a `Coordinates` object into an `int`,
representing the danger level of this tile.
This function does not return any value.
"""
raise NotImplementedError()
def report_required_tiles_for_collecting_money(self):
"""Returns a list of tiles that are required for completing commands.
This mehtod returns a list of tuples, each containing the following values
(in this order):
0. Tile (as `Coordinates`).
1. Importance (as `int`).
"""
raise NotImplementedError()
# ----------------------------------------------------------------------------
# Miscellaneous commands.
# ----------------------------------------------------------------------------
def get_my_country(self):
"""Returns the name of this country."""
raise NotImplementedError()
def get_all_countries(self):
"""Returns the list of all participating countries in the game."""
raise NotImplementedError()
def get_game_width(self):
"""Returns the width of the current game board."""
raise NotImplementedError()
def get_game_height(self):
"""Returns the height of the current game board."""
raise NotImplementedError()
def log(self, log_entry):
"""Logs the given log entry to the main log of this country.
log_entry is expected to be a string, without a trailing new line character.
"""
raise NotImplementedError()
class CommandStatus(object):
"""Represents the status of a command."""
@staticmethod
def failed(command_id):
"""Creates a failed command status."""
return CommandStatus(command_id, failed=True)
@staticmethod
def success(command_id):
"""Creates a successful command status."""
return CommandStatus(command_id, success=True)
@staticmethod
def in_progress(command_id, elapsed_turns, estimated_turns):
"""Create an in-progress command report.
`elapsed_turns` is the amount of turns since the command has been given.
`estimated_turns` is the estimated amount of turns required for completing
the command execution (including `elapsed_turns`).
"""
return CommandStatus(command_id, elapsed_turns=elapsed_turns, estimated_turns=estimated_turns)
def __init__(self, command_id, elapsed_turns=None, estimated_turns=None, failed=None, success=None):
"""Constructor.
Please don't use the constructor directly. Use `CommandStatus.failed`,
`CommandStstus.success` or `CommandStatus.in_progress` instead.
"""
self.command_id = command_id
"""The command ID."""
self.elapsed_turns = elapsed_turns
"""The amount of turns since the command has been given.
This field is meaningful only if `self.is_in_progress()` returns True.
"""
self.estimated_turns = estimated_turns
"""The estimated amount of turns required for completing the command execution.
This field is meaningful only if `self.is_in_progress()` returns True.
"""
self._failed = failed
self._success = success
def is_success(self):
"""Returns True iff this command has succeeded."""
return self._success == True
def is_failed(self):
"""Returns True iff this command has failed."""
return self._failed == True
def is_in_progress(self):
"""Returns True iff this command is still in progress."""
return self.elapsed_turns is not None and self.estimated_turns is not None
class CommandStatus(object):
"""Represents the status of a command."""
@staticmethod
def failed(command_id):
"""Creates a failed command status."""
return CommandStatus(command_id, failed=True)
@staticmethod
def success(command_id):
"""Creates a successful command status."""
return CommandStatus(command_id, success=True)
@staticmethod
def in_progress(command_id, elapsed_turns, estimated_turns):
"""Create an in-progress command report.
`elapsed_turns` is the amount of turns since the command has been given.
`estimated_turns` is the estimated amount of turns required for completing
the command execution (including `elapsed_turns`).
"""
return CommandStatus(command_id, elapsed_turns=elapsed_turns, estimated_turns=estimated_turns)
def __init__(self, command_id, elapsed_turns=None, estimated_turns=None, failed=None, success=None):
"""Constructor.
Please don't use the constructor directly. Use `CommandStatus.failed`,
`CommandStstus.success` or `CommandStatus.in_progress` instead.
"""
self.command_id = command_id
"""The command ID."""
self.elapsed_turns = elapsed_turns
"""The amount of turns since the command has been given.
This field is meaningful only if `self.is_in_progress()` returns True.
"""
self.estimated_turns = estimated_turns
"""The estimated amount of turns required for completing the command execution.
This field is meaningful only if `self.is_in_progress()` returns True.
"""
self._failed = failed
self._success = success
def is_success(self):
"""Returns True iff this command has succeeded."""
return self._success == True
def is_failed(self):
"""Returns True iff this command has failed."""
return self._failed == True
def is_in_progress(self):
"""Returns True iff this command is still in progress."""
return self.elapsed_turns is not None and self.estimated_turns is not None
class StrategicPiece:
def __init__(self, id, type):
self.id = id
self.type = type