浏览代码

fix line algo and update priorities

Olivier Massot 3 年之前
父节点
当前提交
9ff7ce8357
共有 4 个文件被更改,包括 146 次插入45 次删除
  1. 1 1
      .idea/cig.iml
  2. 1 1
      .idea/misc.xml
  3. 104 0
      cultist_war/bresenham.py
  4. 40 43
      cultist_war/main.py

+ 1 - 1
.idea/cig.iml

@@ -2,7 +2,7 @@
 <module type="PYTHON_MODULE" version="4">
   <component name="NewModuleRootManager">
     <content url="file://$MODULE_DIR$" />
-    <orderEntry type="jdk" jdkName="Python 3.9" jdkType="Python SDK" />
+    <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
   </component>
 </module>

+ 1 - 1
.idea/misc.xml

@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
-  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (clonedb)" project-jdk-type="Python SDK" />
 </project>

+ 104 - 0
cultist_war/bresenham.py

@@ -0,0 +1,104 @@
+import time
+
+t0 = time.time()
+
+
+def log(*msg):
+    print("{} - ".format(str(time.time() - t0)[:5]), *msg)
+
+
+obstacles = [(1, 0), (1, 1)]
+
+
+# Version serveur
+def can_see_trough(pos):
+    return pos not in obstacles
+
+
+def line(start, target, strict=True):
+    """
+    adapted from https://github.com/fragkakis/bresenham/blob/master/src/main/java/org/fragkakis/Bresenham.java
+    if strict is true, None is return if an obstacle interrupted the line; else a partial line is returned (from start to obstacle)
+    """
+    line = []
+
+    x0, y0 = start
+    x1, y1 = target
+
+    dx = abs(x1 - x0)
+    dy = abs(y1 - y0)
+
+    sx = 1 if x0 < x1 else -1
+    sy = 1 if y0 < y1 else -1
+
+    err = dx - dy
+    x, y = x0, y0
+
+    while 1:
+        line.append((x, y))
+
+        if x == x1 and y == y1:
+            break
+
+        e2 = 2 * err
+        if e2 > (-1 * dy):
+            err -= dy
+            x += sx
+
+        if e2 < dx:
+            err += dx
+            y += sy
+
+        if not can_see_trough((x, y)):
+            return None if strict else line
+
+    return line
+
+
+log(line((0, 2), (4, 3)))  # test droite / bas
+log(line((0, 5), (4, 3)))  # test droite / haut
+log(line((8, 1), (4, 3)))  # test gauche / bas
+log(line((8, 5), (4, 3)))  # test gauche / haut
+
+#
+# def bresenhamForward(start, target):
+#     x0, y0 = start
+#     x1, y1 = target
+#
+#     dx = abs(x1 - x0)
+#     dy = abs(y1 - y0)
+#
+#     sx = 1 if x0 < x1 else -1
+#     sy = 1 if y0 < y1 else -1
+#
+#     err = dx - dy
+#     x, y = x0, y0
+#
+#     while 1:
+#         e2 = 2 * err
+#         if e2 > (-1 * dy):
+#             err -= dy
+#             x += sx
+#
+#         if e2 < dx:
+#             err += dx
+#             y += sy
+#
+#         if x == x1 and y == y1:
+#             break
+#
+#         if can_see_trough((x, y)):
+#             return []
+#
+#     return []
+#
+#
+# def bresenhamBackward(start, target):
+#     pass
+#
+#
+# def checkBulletPath(start, target):
+#     if start[1] > target[1]:
+#         return bresenhamForward(start, target)
+#     else:
+#         return bresenhamBackward(start, target)

+ 40 - 43
cultist_war/main.py

@@ -345,9 +345,9 @@ class Grid(BaseClass):
 
         k_convert_number = -10
         k_convert_distance = 10
-        k_convert_danger = 30
-        k_shoot_opponent_cultist = 10
-        k_shoot_opponent_cult_leader = 5
+        k_convert_danger = 20
+        k_shoot_opponent_cultist = 15
+        k_shoot_opponent_cult_leader = 10
         k0_protect_cult_leader = 30
         k_protect_threat_level = -5
         k_cover_threat = 10
@@ -372,12 +372,11 @@ class Grid(BaseClass):
                 key=(lambda pos: pos in self.index and self.index[pos].neutral),
                 limit=min(4, len(self.neutrals()))
             )
-            # log(conversion_path)
+            log(conversion_path)
 
         # Conversion des neutres
         if cult_leader and conversion_path:
             path = conversion_path.next_candidate()
-            log(path)
             if path:
                 targets = [self.index[c] for c in path[-1].candidates]
 
@@ -392,17 +391,18 @@ class Grid(BaseClass):
                     action = ActionMove(cult_leader, path[1].pos, f'go convert {",".join([str(t.id) for t in targets])}')
                 actions.put(priority, action)
 
-        # Attaque d'unités ennemies
+        # Tire sur une unités ennemies
         targets = self.opponent_cultists()
         if opponent_cult_leader:
             targets.append(opponent_cult_leader)
 
-        advantage = sum([t.hp for t in targets]) < sum([u.hp for u in self.owned_units()])
+        has_advantage = sum([t.hp for t in targets]) < sum([u.hp for u in self.owned_units()])
 
         for a in self.allied_cultists():
             for u in targets:
                 shooting_distance = self.shooting_distance(a.pos, u.pos)
-                log(f"{a.id} - {u.id} - {self.line(a.pos, u.pos)[1:]}")
+                if a.id == 4 and u.id == 1:
+                    log(self.line_of_sight(a.pos, u.pos))
                 if shooting_distance and shooting_distance < u.SHOOTING_RANGE:
                     action = ActionShoot(a, u)
 
@@ -440,9 +440,9 @@ class Grid(BaseClass):
                 covers = [n for n in self.neighbors(*cult_leader.pos) if self.can_move_on(cult_leader, n)]
 
                 for pos in covers:
-                    action = ActionMove(cult_leader, pos, 'take cover')
+                    action = ActionMove(cult_leader, pos, f'take cover (t: {current_threat})')
 
-                    interest = conversion_path and conversion_path.steps and conversion_path.steps[0].pos == pos
+                    interest = conversion_path and conversion_path.steps and pos in [s.pos for s in conversion_path.steps]
 
                     priority = k0_protect_cult_leader
                     priority += k_protect_threat_level * current_threat
@@ -492,44 +492,41 @@ class Grid(BaseClass):
         return zone
 
     @classmethod
-    def line(cls, from_, to_):
-        """ Implementation of bresenham's algorithm """
-        xa, ya = from_
-        xb, yb = to_
+    def line(cls, start, target):
+        """
+        adapted from https://github.com/fragkakis/bresenham/blob/master/src/main/java/org/fragkakis/Bresenham.java
+        if strict is true, None is return if an obstacle interrupted the line; else a partial line is returned (from start to obstacle)
+        """
+        line = []
 
-        if (xa, ya) == (xb, yb):
-            return [(xa, ya)]
+        x0, y0 = start
+        x1, y1 = target
 
-        # diagonal symmetry
-        vertically_oriented = (abs(yb - ya) > abs(xb - xa))
-        if vertically_oriented:
-            ya, xa, yb, xb = xa, ya, xb, yb
+        dx = abs(x1 - x0)
+        dy = abs(y1 - y0)
 
-        # horizontal symmetry
-        reversed_sym = (xa > xb)
-        if reversed_sym:
-            xb, yb, xa, ya = xa, ya, xb, yb
+        sx = 1 if x0 < x1 else -1
+        sy = 1 if y0 < y1 else -1
 
-        # angle
-        dx, dy = xb - xa, yb - ya
-        alpha = (abs(dy) / dx)
+        err = dx - dy
+        x, y = x0, y0
 
-        offset = 0.0
-        step = 1 if dy > 0 else -1
+        while 1:
+            line.append((x, y))
+
+            if x == x1 and y == y1:
+                break
 
-        result = []
-        y_ = ya
-        for x_ in range(xa, xb + 1):
-            result.append((y_, x_) if vertically_oriented else (x_, y_))
+            e2 = 2 * err
+            if e2 > (-1 * dy):
+                err -= dy
+                x += sx
 
-            offset += alpha
-            if offset > 0.51:
-                y_ += step
-                offset -= 1.0
+            if e2 < dx:
+                err += dx
+                y += sy
 
-        if reversed_sym:
-            result.reverse()
-        return result
+        return line
 
     def line_of_sight(self, from_, to_):
         line = self.line(from_, to_)[1:]
@@ -687,6 +684,7 @@ class Grid(BaseClass):
         return ConversionPath.make_from_discovery_node(best_node)
 
     def _repr_cell(self, pos):
+        return f"{self.threat[pos]}"
         # return f"{self.control[pos]}/{self.threat[pos]}"
         # return self.heat_map[pos]
 
@@ -724,7 +722,6 @@ while 1:
     # TODO: ajouter une action "s'interposer" où une unité s'interpose entre le leader et un ennemi ; à mettre en balance avec le 'take cover'
     # TODO: remplacer le discover par un algo qui cherche le plus court chemin pour relier tous les neutres les uns après les autres
 
-
     GRID.reinit_round()
     for _ in range(int(input())):
         GRID.update_unit(*[int(j) for j in input().split()])
@@ -734,11 +731,11 @@ while 1:
 
     actions = GRID.list_actions()
 
+    print("\n" + GRID.graph(), file=sys.stderr)
+
     for action in actions.items:
         log(f"* {action}")
 
-    # print("\n" + GRID.graph(), file=sys.stderr)
-
     try:
         action = actions.get()
     except IndexError: