ソースを参照

various fixes

olinox 6 年 前
コミット
86cb3f4347
3 ファイル変更256 行追加29 行削除
  1. 45 29
      i_n_f/script.py
  2. 47 0
      i_n_f/temp.py
  3. 164 0
      i_n_f/test_pivot.py

+ 45 - 29
i_n_f/script.py

@@ -8,7 +8,11 @@ import sys
 import time
 
 # 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!
+# * 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
@@ -133,6 +137,9 @@ class Position(BasePosition):
         # distance to the ennemy HQ
         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
         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)
         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):
         self.pre_eval()
         self.interest = 100 \
-                        - 10 * self.threat\
+                        - 10 * self.threat \
                         - self.covers // 5 \
-                        - 10 * self.pivot \
-                        - 50 * self.emergency
+                        - 5 * self.pivot \
+                        - 20 * self.emergency * (22 - self.dist_to_hq)
         
 class Attack(Position):
     def eval(self):
@@ -449,13 +460,14 @@ class Grid(Base):
                                           units_ix.get((x, y), None), 
                                           buildings_ix.get((x, y), None))
 
+        self.update_pivots()
         self.update_state()
+        
 
     def update_state(self):
         self.update_tower_areas()
         self.update_frontlines()
         self.update_depth_map()
-        self.update_pivots()
         self.update_threats()
 
     @staticmethod
@@ -531,21 +543,19 @@ class Grid(Base):
         
         buffer = [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:
             new_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
-                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])
                         nodes.add(new_node)
                         new_buffer.append(new_node)
-            
             buffer = new_buffer
         
         paths_to = {}
@@ -585,7 +595,10 @@ class Grid(Base):
         for p, occ in occurrences.items():
             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):
         self.update_pivot_for(ME)
@@ -593,7 +606,7 @@ class Grid(Base):
     
     def update_threats(self):
         # 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 \
                            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
             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:
             new_cell = action.cell
@@ -750,14 +764,16 @@ class Grid(Base):
                 new_cell.building = None
             
             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:
             new_cell = action.cell
@@ -930,7 +946,7 @@ while True:
         
         objective = q.get()
         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)
                 
             else:

+ 47 - 0
i_n_f/temp.py

@@ -0,0 +1,47 @@
+from collections import Counter
+
+
+class Grid():
+    dim = 12
+    
+    def __init__(self):
+        self.cells = [(x, y) for x in range(Grid.dim) for y in range(Grid.dim)]
+
+    def neighbors(self, x, y, diags=False):
+        neighs = [(x, y - 1), (x - 1, y), (x + 1, y), (x, y + 1)]
+        if diags:
+            neighs += [(x - 1, y - 1), (x + 1, y - 1), (x - 1, y + 1), (x + 1, y + 1)]
+        return [(x, y) for x, y in neighs if 0 <= x < Grid.dim and 0 <= y < Grid.dim]
+    
+    def _active_owned(self, pos):
+        return pos in [(9, 9), (8, 9), (10, 9), (10, 10), (7, 9), 
+                       (9, 11), (11, 10), (10, 11), (11, 9), (11, 11), 
+                       (8, 11), (7, 11), (6, 11), (5, 11)]
+        
+
+    def update_pivot_for(self):
+        start = (11,11)
+        buffer = [start]
+        visited_from = {start: []}
+
+        while buffer:
+            new_buffer = []
+            for p in buffer:
+                for n in self.neighbors(*p):
+                    if self._active_owned(n):
+                        if not n in visited_from:
+                            new_buffer.append(n)
+                        if not n in visited_from:
+                            visited_from[n] = [p]
+                        else:
+                            visited_from[n].append(p)
+            buffer = new_buffer
+            
+        
+            
+        return visited_from
+        
+grid = Grid()
+c = grid.update_pivot_for()
+
+print("\n".join([f"{k}: {v}" for k, v in c.items()]))

+ 164 - 0
i_n_f/test_pivot.py

@@ -0,0 +1,164 @@
+'''
+
+@author: olivier.massot, 2019
+'''
+from collections import Counter
+import time
+
+
+class Node():
+    def __init__(self, pos, path=[]):
+        self.pos = pos
+        self.path = path
+
+class Grid():
+    dim = 12
+    owned = 3
+    def __init__(self):
+        
+        self.cells = [(x, y) for x in range(Grid.dim) for y in range(Grid.dim)]
+
+    def print_grid(self):
+        grid = [["" for _ in range(Grid.dim)] for _ in range(Grid.dim)]
+        for x, y in self.cells:
+            grid[y][x] = f"({x:02d}, {y:02d})" if self._active_owned((x, y), 0) else "________"
+        return "\n".join(["".join([c for c in row]) for row in grid])
+    
+    @staticmethod
+    def manhattan(from_, to_):
+        xa, ya = from_
+        xb, yb = to_
+        return abs(xa - xb) + abs(ya - yb) 
+    
+    def neighbors(self, x, y, diags=False):
+        neighs = [(x, y - 1), (x - 1, y), (x + 1, y), (x, y + 1)]
+        if diags:
+            neighs += [(x - 1, y - 1), (x + 1, y - 1), (x - 1, y + 1), (x + 1, y + 1)]
+        return [(x, y) for x, y in neighs if 0 <= x < Grid.dim and 0 <= y < Grid.dim]
+        
+    def oriented_neighbors(self, x, y, orient):
+        return [(x + 1, y), (x, y + 1)] if orient > 0 else [(x - 1, y), (x, y - 1)]
+    
+    def update_frontlines(self):
+        self.frontline = []
+        
+        for p in self.cells:
+            if self._active_owned(p, 0):
+                if any(not self._active_owned(n, 0) for n in self.neighbors(*p)):
+#                     cell.update_threat()
+                    self.frontline.append(p)
+    
+    def _active_owned(self, pos, player_id):
+        return pos in [(11,11), (10,11), (9,11), (8,11), (7,11), (6,11), (5,11), (4,11),
+                       (11,10), (10,10), (9,10), (8,10), (7,10), (6,10), (5,10), (4,10),
+                       (11,9),  (10,9),  (9,9),  (8,9),  (7,9),  (6,9),  (5,9),
+                                                         (7,8),  (6,8),  (5,8),  (4,8),
+                                                         (7,7),                  (4,7)]
+        
+    def __active_owned(self, pos, player_id):
+        return pos[0] < 12 and pos[1] < 12
+
+    def update_pivot_for(self, player_id):
+#         start = self.get_hq(player_id).pos
+        start = (11,11)
+        start_node = Node(start)
+        
+        buffer = [start_node]
+        nodes = {start_node}
+        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:
+            new_buffer = []
+            for node in buffer:
+                neighbors = [p for p in self.neighbors(*node.pos) if self._active_owned(p, player_id)]
+                if node.pos in ignored:
+                    continue
+                for n in neighbors:
+                    if not n in node.path:
+                        new_node = Node(n, node.path + [node.pos])
+                        nodes.add(new_node)
+                        new_buffer.append(new_node)
+            
+            buffer = new_buffer
+        
+        paths_to = {}
+        
+        for node in nodes:
+            if not node.pos in paths_to:
+                paths_to[node.pos] = []
+            paths_to[node.pos].append(node.path)
+        print(paths_to)
+    
+        pivots = {}
+        
+        for candidate in paths_to:
+            if candidate == start:
+                continue
+            for p, paths in paths_to.items():
+                if not paths or not paths[0] or p in ignored:
+                    continue
+                if all(candidate in path for path in paths):
+                    if not candidate in pivots:
+                        pivots[candidate] = []
+                    pivots[candidate].append(p)
+        
+        occurrences = Counter(sum(sum(paths_to.values(), []), []))
+
+        while ignored:
+            new_ignored = []
+            for p in ignored:
+                occured_neighbors = [occurrences[n] for n in self.neighbors(*p) if n in occurrences]
+                if not occured_neighbors:
+                    new_ignored.append(p)
+                    continue
+                occurrences[p] = 2 * sum(occured_neighbors) // len(occured_neighbors)
+            ignored = new_ignored
+        
+        print(occurrences)
+
+        return pivots
+
+
+    def __update_pivot_for(self, player_id):
+#         start = self.get_hq(player_id).pos
+        start = (11,11)
+        orient = 1
+        buffer = [(None, start)]
+        bounds = []
+        
+        while buffer:
+            new_buffer = []
+            for o, p in buffer:
+                for n in self.oriented_neighbors(*p, orient):
+                    if self._active_owned(n, player_id) and not (p, n) in bounds and n != o:
+                        bounds.append((p, n))
+                        new_buffer.append((p, n))
+            buffer = new_buffer
+        
+        print(bounds)
+        
+        parents_number = Counter()
+        for parent, child in bounds:
+            parents_number[child] += 1
+        print(parents_number)
+            
+
+        pivots = set()
+        for parent, child in bounds:
+            if parent == start:
+                continue
+            if parents_number[child] == 1:
+                pivots |= {parent}
+                
+        return pivots
+    
+grid = Grid()
+Grid.owned = 5
+print(grid.print_grid())
+print()
+
+t0 = time.time()
+a = grid.update_pivot_for(0)
+print(a)
+print(time.time() - t0)
+