|
@@ -8,7 +8,11 @@ import sys
|
|
|
import time
|
|
import time
|
|
|
|
|
|
|
|
# TODO
|
|
# TODO
|
|
|
|
|
+# * when building a tower, check that there is not already one, and block the cell for moving
|
|
|
# * do not train a unit of a cell if it is in a threatened pivot zone, especially not a level 3 unit!
|
|
# * do not train a unit of a cell if it is in a threatened pivot zone, especially not a level 3 unit!
|
|
|
|
|
+# * take units and towers in account when computing the threat
|
|
|
|
|
+# * take units and towers in account when computing the strategig value
|
|
|
|
|
+# * review the tower placement in case of threat
|
|
|
|
|
|
|
|
|
|
|
|
|
debug = True
|
|
debug = True
|
|
@@ -133,6 +137,9 @@ class Position(BasePosition):
|
|
|
# distance to the ennemy HQ
|
|
# distance to the ennemy HQ
|
|
|
self.dist_to_goal = Grid.manhattan(self.cell.pos, opponent.hq.pos)
|
|
self.dist_to_goal = Grid.manhattan(self.cell.pos, opponent.hq.pos)
|
|
|
|
|
|
|
|
|
|
+ # distance to the own HQ
|
|
|
|
|
+ self.dist_to_hq = Grid.manhattan(self.cell.pos, player.hq.pos)
|
|
|
|
|
+
|
|
|
# priorize adjacent cells
|
|
# priorize adjacent cells
|
|
|
self.union = len([n for n in self.cell.neighbors if grid[n].active_owned])
|
|
self.union = len([n for n in self.cell.neighbors if grid[n].active_owned])
|
|
|
|
|
|
|
@@ -167,13 +174,17 @@ class Defend(Position):
|
|
|
super().__init__(cell)
|
|
super().__init__(cell)
|
|
|
self.emergency = emergency
|
|
self.emergency = emergency
|
|
|
|
|
|
|
|
|
|
+ def __repr__(self):
|
|
|
|
|
+ detail = [self.threat, self.covers, self.pivot, self.emergency, self.dist_to_hq]
|
|
|
|
|
+ return "<{} {}: {}, {} ({})>".format(self.__class__.__name__, self.pos, self.interest, self.min_level, detail)
|
|
|
|
|
+
|
|
|
def eval(self):
|
|
def eval(self):
|
|
|
self.pre_eval()
|
|
self.pre_eval()
|
|
|
self.interest = 100 \
|
|
self.interest = 100 \
|
|
|
- - 10 * self.threat\
|
|
|
|
|
|
|
+ - 10 * self.threat \
|
|
|
- self.covers // 5 \
|
|
- self.covers // 5 \
|
|
|
- - 10 * self.pivot \
|
|
|
|
|
- - 50 * self.emergency
|
|
|
|
|
|
|
+ - 5 * self.pivot \
|
|
|
|
|
+ - 20 * self.emergency * (22 - self.dist_to_hq)
|
|
|
|
|
|
|
|
class Attack(Position):
|
|
class Attack(Position):
|
|
|
def eval(self):
|
|
def eval(self):
|
|
@@ -449,13 +460,14 @@ class Grid(Base):
|
|
|
units_ix.get((x, y), None),
|
|
units_ix.get((x, y), None),
|
|
|
buildings_ix.get((x, y), None))
|
|
buildings_ix.get((x, y), None))
|
|
|
|
|
|
|
|
|
|
+ self.update_pivots()
|
|
|
self.update_state()
|
|
self.update_state()
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def update_state(self):
|
|
def update_state(self):
|
|
|
self.update_tower_areas()
|
|
self.update_tower_areas()
|
|
|
self.update_frontlines()
|
|
self.update_frontlines()
|
|
|
self.update_depth_map()
|
|
self.update_depth_map()
|
|
|
- self.update_pivots()
|
|
|
|
|
self.update_threats()
|
|
self.update_threats()
|
|
|
|
|
|
|
|
@staticmethod
|
|
@staticmethod
|
|
@@ -531,21 +543,19 @@ class Grid(Base):
|
|
|
|
|
|
|
|
buffer = [start_node]
|
|
buffer = [start_node]
|
|
|
nodes = {start_node}
|
|
nodes = {start_node}
|
|
|
- ignored = set()
|
|
|
|
|
|
|
+
|
|
|
|
|
+ ignored = [p for p in self.cells if len([n for n in self.neighbors(*p, diags=True) if self._active_owned(n, player_id)]) == 8]
|
|
|
|
|
|
|
|
while buffer:
|
|
while buffer:
|
|
|
new_buffer = []
|
|
new_buffer = []
|
|
|
for node in buffer:
|
|
for node in buffer:
|
|
|
- neighbors = [p for p in self.neighbors(*node.pos) if self._active_owned(p, player_id)]
|
|
|
|
|
- if len(neighbors) == 4:
|
|
|
|
|
- ignored.add(node.pos)
|
|
|
|
|
|
|
+ if node.pos in ignored:
|
|
|
continue
|
|
continue
|
|
|
- for n in neighbors:
|
|
|
|
|
- if not n in node.path:
|
|
|
|
|
|
|
+ for n in self.neighbors(*node.pos):
|
|
|
|
|
+ if not n in node.path and self._active_owned(n, player_id):
|
|
|
new_node = Node(n, node.path + [node.pos])
|
|
new_node = Node(n, node.path + [node.pos])
|
|
|
nodes.add(new_node)
|
|
nodes.add(new_node)
|
|
|
new_buffer.append(new_node)
|
|
new_buffer.append(new_node)
|
|
|
-
|
|
|
|
|
buffer = new_buffer
|
|
buffer = new_buffer
|
|
|
|
|
|
|
|
paths_to = {}
|
|
paths_to = {}
|
|
@@ -585,7 +595,10 @@ class Grid(Base):
|
|
|
for p, occ in occurrences.items():
|
|
for p, occ in occurrences.items():
|
|
|
self.cells[p].strategic_value = (100 * occ) // max_occ
|
|
self.cells[p].strategic_value = (100 * occ) // max_occ
|
|
|
|
|
|
|
|
-# log(player_id, {c.pos: (c.strategic_value, len(c.pivot_for)) for c in self.cells.values() if c.owner == player_id})
|
|
|
|
|
|
|
+# if player_id == ME:
|
|
|
|
|
+# log(pivots)
|
|
|
|
|
+# log(occurrences)
|
|
|
|
|
+# log({cell.pos: cell.strategic_value for cell in self.cells.values() if cell.owned})
|
|
|
|
|
|
|
|
def update_pivots(self):
|
|
def update_pivots(self):
|
|
|
self.update_pivot_for(ME)
|
|
self.update_pivot_for(ME)
|
|
@@ -593,7 +606,7 @@ class Grid(Base):
|
|
|
|
|
|
|
|
def update_threats(self):
|
|
def update_threats(self):
|
|
|
# 1 + max number of units opponents can produce in one turn
|
|
# 1 + max number of units opponents can produce in one turn
|
|
|
- self.threat_level = 1 + opponent.training_capacity()
|
|
|
|
|
|
|
+ self.threat_level = 1 + min([(opponent.gold + opponent.income) // Unit.cost[1], opponent.income // Unit.maintenance[1]])
|
|
|
|
|
|
|
|
ennemy_frontier = [c for c in self.cells.values() if c.opponents \
|
|
ennemy_frontier = [c for c in self.cells.values() if c.opponents \
|
|
|
and any(self.cells[n].movable and not self.cells[n].opponents for n in c.neighbors)]
|
|
and any(self.cells[n].movable and not self.cells[n].opponents for n in c.neighbors)]
|
|
@@ -715,14 +728,15 @@ class Grid(Base):
|
|
|
new_cell.unit = action.unit
|
|
new_cell.unit = action.unit
|
|
|
action.unit.has_moved = True
|
|
action.unit.has_moved = True
|
|
|
|
|
|
|
|
- if new_cell.opponents:
|
|
|
|
|
- for p in new_cell.pivot_for:
|
|
|
|
|
- self.cells[p].desactivate()
|
|
|
|
|
- if self.cells[p].unit and self.cells[p].unit.opponents:
|
|
|
|
|
- self.remove_unit_from(self.cells[p])
|
|
|
|
|
- new_cell.take_possession()
|
|
|
|
|
-
|
|
|
|
|
- self.update_state()
|
|
|
|
|
|
|
+ if not new_cell.owned:
|
|
|
|
|
+ if new_cell.opponents:
|
|
|
|
|
+ for p in new_cell.pivot_for:
|
|
|
|
|
+ self.cells[p].desactivate()
|
|
|
|
|
+ if self.cells[p].unit and self.cells[p].unit.opponents:
|
|
|
|
|
+ self.remove_unit_from(self.cells[p])
|
|
|
|
|
+ new_cell.take_possession()
|
|
|
|
|
+
|
|
|
|
|
+ self.update_state()
|
|
|
|
|
|
|
|
elif type(action) is Train:
|
|
elif type(action) is Train:
|
|
|
new_cell = action.cell
|
|
new_cell = action.cell
|
|
@@ -750,14 +764,16 @@ class Grid(Base):
|
|
|
new_cell.building = None
|
|
new_cell.building = None
|
|
|
|
|
|
|
|
new_cell.unit = unit
|
|
new_cell.unit = unit
|
|
|
- if new_cell.opponents:
|
|
|
|
|
- for p in new_cell.pivot_for:
|
|
|
|
|
- self.cells[p].desactivate()
|
|
|
|
|
- if self.cells[p].unit and self.cells[p].unit.opponents:
|
|
|
|
|
- self.remove_unit_from(self.cells[p])
|
|
|
|
|
- new_cell.take_possession()
|
|
|
|
|
|
|
|
|
|
- self.update_state()
|
|
|
|
|
|
|
+ if not new_cell.owned:
|
|
|
|
|
+ if new_cell.opponents:
|
|
|
|
|
+ for p in new_cell.pivot_for:
|
|
|
|
|
+ self.cells[p].desactivate()
|
|
|
|
|
+ if self.cells[p].unit and self.cells[p].unit.opponents:
|
|
|
|
|
+ self.remove_unit_from(self.cells[p])
|
|
|
|
|
+ new_cell.take_possession()
|
|
|
|
|
+
|
|
|
|
|
+ self.update_state()
|
|
|
|
|
|
|
|
elif type(action) is BuildTower:
|
|
elif type(action) is BuildTower:
|
|
|
new_cell = action.cell
|
|
new_cell = action.cell
|
|
@@ -930,7 +946,7 @@ while True:
|
|
|
|
|
|
|
|
objective = q.get()
|
|
objective = q.get()
|
|
|
if type(objective) is Defend:
|
|
if type(objective) is Defend:
|
|
|
- if player.current_gold > Building.cost[Building.TOWER]:
|
|
|
|
|
|
|
+ if player.current_gold > Building.cost[Building.TOWER] and not objective.cell.mine_site:
|
|
|
action = BuildTower(objective.cell)
|
|
action = BuildTower(objective.cell)
|
|
|
|
|
|
|
|
else:
|
|
else:
|