|
|
@@ -104,6 +104,9 @@ class Action(BaseClass):
|
|
|
|
|
|
|
|
|
class ActionWait(Action):
|
|
|
+ def __repr__(self):
|
|
|
+ return f"<ActionWait>"
|
|
|
+
|
|
|
def exec(self):
|
|
|
print("WAIT")
|
|
|
|
|
|
@@ -113,6 +116,9 @@ class ActionMove(Action):
|
|
|
self.unit = unit
|
|
|
self.pos = pos
|
|
|
|
|
|
+ def __repr__(self):
|
|
|
+ return f"<ActionMove: {self.unit.id} to {self.pos}>"
|
|
|
+
|
|
|
def exec(self):
|
|
|
print(f"{self.unit.id} MOVE {self.pos[0]} {self.pos[1]}")
|
|
|
|
|
|
@@ -122,7 +128,10 @@ class ActionShoot(Action):
|
|
|
self.unit = unit
|
|
|
self.target = target
|
|
|
|
|
|
- def exec(self, id_, target_id):
|
|
|
+ def __repr__(self):
|
|
|
+ return f"<ActionShoot: {self.unit.id} to {self.target.id}>"
|
|
|
+
|
|
|
+ def exec(self):
|
|
|
print(f"{self.unit.id} SHOOT {self.target.id}")
|
|
|
|
|
|
|
|
|
@@ -131,6 +140,9 @@ class ActionConvert(Action):
|
|
|
self.unit = unit
|
|
|
self.target = target
|
|
|
|
|
|
+ def __repr__(self):
|
|
|
+ return f"<ActionConvert: {self.unit.id} to {self.target.id}>"
|
|
|
+
|
|
|
def exec(self):
|
|
|
print(f"{self.unit.id} CONVERT {self.target.id}")
|
|
|
|
|
|
@@ -144,10 +156,11 @@ class Grid(BaseClass):
|
|
|
self.units = {}
|
|
|
self.round = 0
|
|
|
|
|
|
- def update_unit(self, id_, type_, hp, x, y, owner):
|
|
|
- if id_ not in self.units:
|
|
|
- self.units[id_] = Unit(id_) if type_ != Unit.TYPE_CULT_LEADER else CultLeader(id_)
|
|
|
+ def prepare_round(self):
|
|
|
+ self.units = {}
|
|
|
|
|
|
+ def update_unit(self, id_, type_, hp, x, y, owner):
|
|
|
+ self.units[id_] = Unit(id_) if type_ != Unit.TYPE_CULT_LEADER else CultLeader(id_)
|
|
|
unit = self.units[id_]
|
|
|
unit.hp = hp
|
|
|
unit.x = x
|
|
|
@@ -162,14 +175,17 @@ class Grid(BaseClass):
|
|
|
def own_cult_leader(self):
|
|
|
return next(u for u in self.units.values() if type(u) is CultLeader and u.owned)
|
|
|
|
|
|
- def opponent_cult_leader(self):
|
|
|
- return [u for u in self.units.values() if type(u) is CultLeader and not u.owned]
|
|
|
-
|
|
|
def allied_cultists(self):
|
|
|
return [u for u in self.units.values() if type(u) is not CultLeader and u.owned]
|
|
|
|
|
|
+ def opponent_units(self):
|
|
|
+ return [u for u in self.units.values() if u.opponent]
|
|
|
+
|
|
|
+ def opponent_cult_leader(self):
|
|
|
+ return [u for u in self.units.values() if type(u) is CultLeader and not u.owned]
|
|
|
+
|
|
|
def opponent_cultists(self):
|
|
|
- return [u for u in self.units.values() if type(u) is not CultLeader and not u.owned]
|
|
|
+ return [u for u in self.units.values() if type(u) is not CultLeader and u.opponent]
|
|
|
|
|
|
def neutrals(self):
|
|
|
return [u for u in self.units.values() if u.neutral]
|
|
|
@@ -177,12 +193,45 @@ class Grid(BaseClass):
|
|
|
def list_actions(self):
|
|
|
actions = Queue()
|
|
|
|
|
|
+ k_convert_neutrals = 10
|
|
|
+ k_convert_danger = 30
|
|
|
+ k_shoot_opponent_cultist = 20
|
|
|
+ k_shoot_opponent_cult_leader = 10
|
|
|
+
|
|
|
+ k_limit = 200
|
|
|
+
|
|
|
cult_leader = self.own_cult_leader()
|
|
|
|
|
|
for n in self.neutrals():
|
|
|
action = ActionConvert(cult_leader, n)
|
|
|
+
|
|
|
distance = self.manhattan(cult_leader.pos, n.pos)
|
|
|
- actions.put(distance, action)
|
|
|
+ danger = 0
|
|
|
+ for u in self.opponent_cultists():
|
|
|
+ fire_dist = self.fire_dist(cult_leader.pos, u.pos)
|
|
|
+ if fire_dist < u.SHOOTING_RANGE:
|
|
|
+ danger += (u.SHOOTING_MAX_DAMAGE - fire_dist)
|
|
|
+
|
|
|
+ priority = k_convert_neutrals * distance + k_convert_danger * danger
|
|
|
+
|
|
|
+ if priority > k_limit:
|
|
|
+ continue
|
|
|
+
|
|
|
+ actions.put(priority, action)
|
|
|
+
|
|
|
+ for a in self.allied_cultists():
|
|
|
+ for u in self.opponent_cultists():
|
|
|
+ fire_dist = self.fire_dist(a.pos, u.pos)
|
|
|
+ if fire_dist < u.SHOOTING_RANGE:
|
|
|
+ action = ActionShoot(a, u)
|
|
|
+
|
|
|
+ priority = (k_shoot_opponent_cult_leader if type(
|
|
|
+ u) is CultLeader else k_shoot_opponent_cultist) * fire_dist
|
|
|
+
|
|
|
+ if priority > k_limit:
|
|
|
+ continue
|
|
|
+
|
|
|
+ actions.put(priority, action)
|
|
|
|
|
|
return actions
|
|
|
|
|
|
@@ -241,23 +290,35 @@ class Grid(BaseClass):
|
|
|
result.reverse()
|
|
|
return result
|
|
|
|
|
|
+ @classmethod
|
|
|
+ def fire_dist(cls, from_, to_):
|
|
|
+ return len(cls.line(from_, to_))
|
|
|
+
|
|
|
|
|
|
# Create grid
|
|
|
GRID = Grid(*[int(i) for i in input().split()])
|
|
|
GRID.obstacles = [(i, j) for i in range(GRID.height) for j, val in enumerate(input()) if val == 'x']
|
|
|
|
|
|
while 1:
|
|
|
+ # TODO: prendre en compte le terrain dans la ligne de visée et les déplacements
|
|
|
+
|
|
|
+ GRID.prepare_round()
|
|
|
for _ in range(int(input())):
|
|
|
GRID.update_unit(*[int(j) for j in input().split()])
|
|
|
GRID.update_index()
|
|
|
|
|
|
actions = GRID.list_actions()
|
|
|
- log(actions)
|
|
|
+
|
|
|
+ for action in actions.items:
|
|
|
+ log(f"* {action}")
|
|
|
|
|
|
try:
|
|
|
action = actions.get()
|
|
|
except IndexError:
|
|
|
+ log("no action...")
|
|
|
action = ActionWait()
|
|
|
|
|
|
+ log(f"exec : {action}")
|
|
|
+
|
|
|
action.exec()
|
|
|
GRID.round += 1
|