Browse Source

update fall2022

olinox14 3 years ago
parent
commit
48e3b5e236
1 changed files with 88 additions and 28 deletions
  1. 88 28
      fall2022/fall2022.py

+ 88 - 28
fall2022/fall2022.py

@@ -6,13 +6,14 @@ debug = True
 
 t0 = time.time()
 
+
 # Debugger : il y a des mouvements qui ne se font pas, faut tout vérifier
 # Faire des zones à l'intérieur des contigs, pour attirer le mouvement vers les zones à coloniser
 # Limiter les constructions agressives en fonction de ces zones
 # penser les recycleurs comme des obstacles!
 # Identifier le moment où la situation est "verrouillée" (plus d'accès entre alliés et ennemis)
 #     et cesser les construction de recycleurs
-
+# Limiter la consommation de ressources des mouvements
 
 def log(*msg):
     if debug:
@@ -65,11 +66,17 @@ class Player(BaseClass):
     OPPONENT = 0
     NONE = -1
 
+    SIDE_WEST = -1
+    SIDE_EAST = 1
+
     def __init__(self, id_):
         self.id = id_
         self.matter = 0
         self.territory = 0
 
+        self.side = None
+
+
 class Cell(BaseClass):
     def __init__(self, x, y):
         self.x = x
@@ -154,6 +161,7 @@ class RobotGroup(BaseClass):
     def has_played(self):
         return self.amount_played >= self.initial_amount
 
+
 class Recycler(BaseClass):
     COST = 10
 
@@ -285,6 +293,7 @@ class Grid(BaseClass):
         self._distance_cache = {}
         self.index_contigs = {}
         self.index_tensions = {}
+        self.index_threats = {}
         self.index_nearest_enemy = {}
 
     @property
@@ -314,7 +323,7 @@ class Grid(BaseClass):
         n = [(x, y - 1), (x - 1, y), (x + 1, y), (x, y + 1)]
         if diags:
             n += [(x - 1, y - 1), (x + 1, y - 1), (x - 1, y + 1), (x + 1, y + 1)]
-        
+
         neighbors = [
             (x, y)
             for x, y in n
@@ -331,6 +340,7 @@ class Grid(BaseClass):
         return Grid(w, h, me, opponent)
 
     def update(self):
+        self.round += 1
         my_matter, opp_matter = [int(i) for i in input().split()]
 
         self.me.matter = my_matter
@@ -343,6 +353,11 @@ class Grid(BaseClass):
                 self.cells[(x, y)].update(scrap_amount, owner, units, recycler, can_build, can_spawn,
                                           in_range_of_recycler)
 
+                if owner == Player.ME and self.me.side is None:
+                    self.me.side = Player.SIDE_WEST if x <= (self.width // 2) else Player.SIDE_EAST
+                if owner == Player.OPPONENT and self.opponent.side is None:
+                    self.opponent.side = Player.SIDE_WEST if x <= (self.width // 2) else Player.SIDE_EAST
+
         log('update')
 
         # update robots
@@ -363,6 +378,7 @@ class Grid(BaseClass):
         self.update_possessions()
         self.update_contigs()
         self.update_tension_map()
+        self.update_threat_map()
         self.update_nearest_enemy()
 
     def owned_units(self):
@@ -380,6 +396,9 @@ class Grid(BaseClass):
     def tension(self, cell):
         return self.index_tensions.get(cell.pos, 0)
 
+    def threat(self, cell):
+        return self.index_threats.get(cell.pos, 0)
+
     def current_winner(self):
         if self.me.territory > self.opponent.territory:
             return Player.ME
@@ -464,6 +483,17 @@ class Grid(BaseClass):
             tension = k * c.units
             self.index_tensions[c.pos] = self.index_tensions.get(c.pos, 0) + tension
 
+    def update_threat_map(self):
+        self.index_threats = {}
+
+        for c in self.cells.values():
+            if not c.is_opponents or not c.units:
+                continue
+
+            threat = c.units
+            for n in self.neighbors(*c.pos):
+                self.index_threats[n] = self.index_threats.get(n, 0) + threat
+
     def update_nearest_enemy(self):
         self.index_nearest_enemy = {pos: 0 for pos in self.cells}
 
@@ -554,6 +584,7 @@ class Grid(BaseClass):
         k_aggressive_build = 8000
         k_aggressive_build_for_defense = -6000
         k_aggressive_build_tension = -1000
+        k_first_rounds = 5000  # on décourage le build lors des premiers rounds, il bloque l'avancée
 
         k0_recyclers_owned = k_recyclers_owned * len(self.owned_recyclers())
 
@@ -569,6 +600,9 @@ class Grid(BaseClass):
 
                 k = k0
 
+                if self.round <= 3:
+                    k += (4 - self.round) * k_first_rounds
+
                 area = [place.pos] + self.neighbors(*place.pos)
                 destination = Build.SUPPORT if not any(self.cells[p].is_opponents for p in area) else Build.AGGRESSIVE
                 k0_already_exploited = 0
@@ -616,12 +650,12 @@ class Grid(BaseClass):
         k_opportunities = -1000
         k_conquest = -3000
         k_tension = -1000
+        k_tension_bridgehead = -1000
+        k_tension_around = -300
+        k_tension_around_bridgehead = -300
         k_dist_to_enemy = 400
         k_bridgehead = -6000
         k_reinforcement = 500
-
-        amount_default = 1
-        amount_bridgehead = 3
         ki = 0  # little hack to avoid the while in queue.put
 
         for contig in self.contigs:
@@ -635,7 +669,6 @@ class Grid(BaseClass):
 
             for p in contig.area:
                 place = self.cells[p]
-                amount = amount_default
 
                 if not place.owned or not place.is_movable or place.unmovable_next_round:
                     continue
@@ -643,10 +676,12 @@ class Grid(BaseClass):
                 k = k0 + ki
                 ki += 1
 
+                is_bridgehead = sum(self.cells[n].is_opponents for n in self.neighbors(p[0], p[1], True)) > 5
+
                 tension = self.index_tensions.get(place.pos, 0)
                 for pos in self.neighbors(place.pos[0], place.pos[1], True):
                     tension += self.index_tensions.get(pos, 0)
-                k += k_tension * tension
+                k += k_tension * tension + k_tension_bridgehead * is_bridgehead
 
                 for pos in self.neighbors(*place.pos):
                     n = self.cells[pos]
@@ -658,11 +693,9 @@ class Grid(BaseClass):
                     elif n.is_opponents:
                         k += k_conquest
 
-                k += k_dist_to_enemy * self.index_nearest_enemy[p]
+                    k += k_tension_around * self.tension(n) + k_tension_around_bridgehead * is_bridgehead
 
-                if sum(self.cells[n].is_opponents for n in self.neighbors(p[0], p[1], True)) > 5:
-                    k += k_bridgehead
-                    amount = amount_bridgehead
+                k += k_dist_to_enemy * self.index_nearest_enemy[p]
 
                 amount = max(sum([self.index_tensions.get(n, 0) for n in self.neighbors(*p)]), 1)
 
@@ -674,7 +707,8 @@ class Grid(BaseClass):
                     build_actions.put(k, action)
                     k += k_reinforcement
 
-        # for action in build_actions.items[:8]:
+        # log('---')
+        # for action in sorted([a for a in build_actions.values() if type(a) is Spawn], key=lambda x: x.priority)[:10]:
         #     log(action)
 
         if not build_actions:
@@ -692,6 +726,8 @@ class Grid(BaseClass):
             for pos in area:
                 self.cells[pos].in_range_of_recycler = True
 
+            self.update_contigs()
+
         if type(action) is Spawn:
             place.units += action.amount
 
@@ -712,11 +748,14 @@ class Grid(BaseClass):
         move_actions = []
 
         k0_position = 60000
-        k_position_distance = 2000
+        k_position_distance = 3000
         k_position_opponents = -5000
         k_position_destroy = -3000
         k_dist_to_enemy = 1000
+        k_colonize = -3000
         k_expand = -800
+        k_threat = -1500
+        ki = 0  # little hack to avoid the while in queue.put
 
         for contig in self.contigs:
             orders = []
@@ -726,39 +765,49 @@ class Grid(BaseClass):
                 # nothing to do
                 continue
 
-            # list destinations
+            # on ne conserve que les cases voisines ou limitrophes du territoire
+            move_area = []
             for pos in contig.area:
+                owned_neighbor, not_owned_neighbor = False, False
+                for n in self.neighbors(*pos):
+                    owned = self.cells[n].owned
+                    if owned:
+                        owned_neighbor = True
+                    else:
+                        not_owned_neighbor = True
+
+                    if owned_neighbor and not_owned_neighbor:
+                        move_area.append(pos)
+                        break
+
+            # list destinations
+            for pos in move_area:
                 c = self.cells[pos]
-                priority = k0_position
+                k = k0_position + ki
+                ki += 1
 
                 if c.owned or not c.is_movable:
                     continue
 
-                if not any((self.cells[n].owned and not self.cells[n].recycler) for n in self.neighbors(*pos)):
-                    # on ne conserve que les cases voisines du territoire allié
-                    continue
-
                 amount_needed = 1
 
                 if c.is_opponents:
-                    priority += k_position_opponents
+                    k += k_position_opponents
                     if c.units:
-                        priority += k_position_destroy
+                        k += k_position_destroy
                         amount_needed = c.amount
 
-                priority += k_dist_to_enemy * self.index_nearest_enemy[pos]
+                k += k_dist_to_enemy * self.index_nearest_enemy[pos]
+                k += k_threat * self.threat(c)
 
                 for n in self.neighbors(pos[0], pos[1], True):
                     if not self.cells[n].is_grass and not self.cells[n].owned:
-                        priority += k_expand
+                        k += k_expand
 
-                order = MoveOrder(pos, amount_needed, priority)
+                order = MoveOrder(pos, amount_needed, k)
 
                 orders.append(order)
 
-            # for move_order in orders:
-            #     log(move_order)
-
             # Prioritize units per distance
             for pos in contig.area:
                 if pos in self.units:
@@ -776,9 +825,16 @@ class Grid(BaseClass):
                     priority = order.priority
                     priority += k_position_distance * dist
 
+                    if self.me.side == Player.SIDE_WEST and order.pos[0] >= unit.pos[0] \
+                            or self.me.side == Player.SIDE_EAST and order.pos[0] <= unit.pos[0]:
+                        priority += k_colonize
+
                     candidate = MoveOrderCandidate(order, unit, destination)
                     q.put(priority, candidate)
 
+            for priority, candidate in sorted(q.items, key=lambda x: x[0])[:18]:
+                log(f"{candidate.unit.pos} -> {candidate.order.pos}, p:{priority}, a:{candidate.order.amount}")
+
             # affect orders
             while q:
                 k, candidate = q.get_items()
@@ -792,6 +848,10 @@ class Grid(BaseClass):
 
                 from_, to_ = candidate.unit.pos, candidate.destination
 
+                if from_ == to_:
+                    # already there
+                    continue
+
                 action = Move(from_, to_, amount, k)
 
                 candidate.unit.amount_played += amount
@@ -853,6 +913,6 @@ while True:
 
     # for contig in grid.contigs:
     #     log(contig)
-    # grid.print(lambda x: f"{grid.tension(x):02d}")
+    grid.print(lambda x: f"{grid.threat(x):02d}")
 
     grid.act()