Browse Source

various enhancements

olinox 6 năm trước cách đây
mục cha
commit
748623a8c9
1 tập tin đã thay đổi với 124 bổ sung84 xóa
  1. 124 84
      carribean/script.py

+ 124 - 84
carribean/script.py

@@ -8,10 +8,12 @@ import sys
 
 # TODO:
 # * add an esquive manoeuvre / try to avoid cannonballs
-# * consider targeting rum barrels if an ennemy is nearer
+# * consider firing at rum barrels if an ennemy is nearer
 # * compute first and second target instead of only one to anticipate the next move
 # * if an enemy is near a mine, shoot the mine instead of the ship
-# * compute the probabilities of presence of an ennemy on dirrefent coords at next turn
+# * compute the probabilities of presence of an ennemy on different coords at next turn
+# * find a way to change direction without slowing down if possible
+# * avoid getting blocked by a side-by-side with an ennemy
 
 debug = True
 
@@ -95,9 +97,7 @@ class GetBarrel(BaseObjective):
 
 class Attack(BaseObjective):
     def _compute_interest(self):
-        self.interest = 7 * self.distance + 3 * self.alignment - 20 * self.target.blocked_since - 10 * self.target.same_traject_since
-
-
+        self.interest = 7 * self.distance + 3 * self.alignment + self.target.stock // 4 - 20 * self.target.blocked_since
 
 class PathNode(tuple):
     def __new__(self, x, y, parent=None):
@@ -185,7 +185,7 @@ class Grid(Base):
             
             for b in self.barrels:
                 obj = GetBarrel(b)
-                obj.eval(s.next_pos, s.orientation)
+                obj.eval(s.next_pos if s.speed else s.prow, s.orientation)
                 s.objectives.put(obj)
                 
             for e in self.ennemy_ships:
@@ -268,7 +268,7 @@ class Grid(Base):
                 interest += 10
             
             # priorize spots at distance 5 from active ship
-            interest -= 10 * abs(5 - self.manhattan((x, y), ship.pos))
+            interest -= 20 * abs(5 - self.manhattan((x, y), ship.pos))
             
             shooting_spots.put((x, y), interest)
 
@@ -352,6 +352,13 @@ class Grid(Base):
             d -= 6
         return d
     
+    @staticmethod
+    def next_cell(x, y, d, repeat=1):
+        for _ in range(repeat):
+            dx, dy = Grid.directions(y)[d]
+            x, y = x + dx, y + dy
+        return x, y
+    
     @staticmethod
     def symetry(d):
         return d + 3 if d < 3 else d - 3
@@ -392,7 +399,6 @@ class Grid(Base):
         nodes = Queue()
         break_on, iteration = limit, 0
         
-        
         origin = PathNode(*origin)
         origin.orientation = orientat0
         
@@ -422,7 +428,7 @@ class Grid(Base):
                 if break_on > 0 and iteration >= break_on:
                     return None
                 
-                moving_cost = moving_costs[(x, y)]
+                moving_cost = moving_costs.get((x, y), 1000)
                 if moving_cost >= 1000:
                     continue
                 
@@ -432,10 +438,14 @@ class Grid(Base):
                     # change direction one degree at a time
                     continue
                     
+                if any(moving_costs.get(c, 1000) >= 1000 for c in Ship.get_area(x, y, d)):
+                    continue
+                    
                 cost = current.cost + moving_cost + diff * 10
-                if diff != 0 and any(moving_costs[c] >= 1000 for c in neighbors):
-                    # a direction change here is dangerous
-                    cost += 50
+#                 if diff != 0 and any(moving_costs.get(c, 1000) >= 1000 for c in neighbors):
+#                     # a direction change here is dangerous
+#                     cost += 100
+                
                 
                 priority = cost + 10 * Grid.manhattan((x, y), target)
 
@@ -514,6 +524,8 @@ class Ship(Entity):
         self.objective = None
         self.objective_next = None
         self.target_ennemy = None
+        
+        self.goto = None
         self.path = []
         
         self.area = Ship.get_area(self.x, self.y, self.orientation)
@@ -588,29 +600,56 @@ class Ship(Entity):
         
         # slow down
         if self.speed > 0:
-            area = self.get_area(*self.get_pos_in(self.pos, self.speed + 1, self.orientation), self.orientation)
+            area = self.get_area(*self.get_pos_in(self.pos, self.speed - 1, self.orientation), self.orientation)
             for c in area:
                 proba[c] = proba.get(c, 0) + 10
             
         for c in proba:
             proba[c] -= self.moving_cost(*c)
 
+        for c in self.area:
+            proba[c] = proba.get(c, 0) + 50 * self.blocked_since
+
         best = max(proba.items(), key=lambda x: x[1])
 
         return best[0]
     
     def get_next_cell(self, in_=1):
-        x, y = self.x, self.y
-        for _ in range(in_):
-            dx, dy = Grid.directions(y)[self.orientation]
-            x, y = x + dx, y + dy
-        return x, y
+        return Grid.next_cell(self.x, self.y, self.orientation, repeat=in_)
 
     def in_current_direction(self, x, y):
         return self.orientation == Grid.direction_to(*self.pos, x, y)
 
     def moving_cost(self, x, y):
-        return self._moving_costs[(x, y)]
+        return self._moving_costs.get((x, y), 1000)
+    
+    def cant_move(self):
+        
+        front = Grid.next_cell(*self.prow, self.orientation)
+        front_left = Grid.next_cell(*self.prow, Grid.add_directions(self.orientation, 1))
+        left = Grid.next_cell(*self.prow, Grid.add_directions(self.orientation, 2))
+        front_right = Grid.next_cell(*self.prow, Grid.add_directions(self.orientation, -1))
+        right = Grid.next_cell(*self.prow, Grid.add_directions(self.orientation, -2))
+        
+        back_left = Grid.next_cell(*self.stern, Grid.add_directions(self.orientation, 2))
+        back_right = Grid.next_cell(*self.stern, Grid.add_directions(self.orientation, -2))
+        
+        blocked = {c: (self.moving_cost(*c) >= 1000) for c in [front, front_left, left,
+                                                                 front_right, right, 
+                                                                 back_left, back_right]}
+        
+        if all(blocked[i] for i in [front, front_left, front_right, left, right]):
+            # surrounded
+            return True
+        elif (blocked[front_left] and blocked[left]) or (blocked[front_right] and blocked[right]):
+            # side by side
+            return True
+        elif blocked[front] and ((blocked[front_left] and blocked[back_right]) or (blocked[front_right] and blocked[back_left])):
+            # cannot go front or turn
+            return True
+        
+        return False
+        
     
     def move(self, *args, **kwargs):
         try:
@@ -619,40 +658,49 @@ class Ship(Entity):
         except DidNotAct:
             return False
 
-    def _move(self, path):
+
+    def _move(self, path, danger=[]):
         
         if path is None:
-            log(f"(!) broken: automove to {goto}")
-            ship.auto_move(*goto)
+            log(f"(!) broken: automove to {self.goto}")
+            self.auto_move(*self.goto)
             return
         elif not path:
             raise DidNotAct()
         
-        # <--- special: avoid blocking situations
-        if current_turn > 1 and self.blocked_since >= 1:
-            dx, dy = Grid.directions(self.y)[((self.orientation + 1) % 6)]
-            if self.moving_cost(self.x + dx, self.y + dy) <= 50:
-                self.turn_left()
-            else:
-                self.turn_right()
-            return
-        # --->
-        
         # speed shall be at 1 when arriving on the "flag"
         next_flag = next((i for i, n in enumerate(path) if n.orientation != self.orientation), None)
         if next_flag is None:
             next_flag = len(path)
         
-        if next_flag < (2 * self.speed):
-            # the end of the path or a direction change is coming
-            diff = Grid.diff_directions(self.orientation, path[0].orientation)
-            
-            # <--- special: avoid the left/right hesitation when stopped
-            if diff and not self.speed and self.last_action in ["STARBOARD",  "PORT"]:
+        diff = Grid.diff_directions(self.orientation, path[0].orientation)
+        
+        if not self.speed:
+            if diff and next_flag == 0:
+                # start, with a direction change
+                if diff > 0:
+                    self.turn_left()
+                    return
+                    
+                elif diff < 0:
+                    self.turn_right()
+                    return
+            else:
+                # start, todo recto
                 self.speed_up()
                 return
-            # --->
-            
+        
+        elif self.speed > 1 and next_flag <= (self.speed + 1):
+            # the end of the path or a direction change is coming
+            self.slow_down()
+            return
+        
+        elif next_flag > self.MAX_SPEED + 1 and self.speed < self.MAX_SPEED:
+            # long path and no direction change coming: speed up
+            self.speed_up()
+            return
+        
+        elif diff:
             if diff > 0:
                 self.turn_left()
                 return
@@ -661,16 +709,6 @@ class Ship(Entity):
                 self.turn_right()
                 return
         
-            elif self.speed > 1:
-                self.slow_down()
-                return
-        
-        else:
-            if not self.speed or (next_flag > (2 * self.speed + 1) and self.speed < self.MAX_SPEED):
-                # long path and no direction change coming: speed up
-                self.speed_up()
-                return
-        
         raise DidNotAct()
            
     def fire_at_will(self, *args, **kwargs):
@@ -733,39 +771,37 @@ class Ship(Entity):
         return self.last_fire is None or (current_turn - self.last_fire) >= 1
             
     # --- Basic commands
+    def _act(self, cmd, *args):
+        self.last_action = cmd
+        output = " ".join([cmd] + [str(a) for a in args])
+        log(f"ship {self.id}: {output}")
+        print(output)
+    
     def auto_move(self, x, y):
-        self.last_action = "MOVE"
-        print(f"MOVE {x} {y}")
+        self._act("MOVE", x, y)
         
     def speed_up(self):
-        self.last_action = "FASTER"
-        print("FASTER")
+        self._act("FASTER")
         
     def slow_down(self):
-        self.last_action = "SLOWER"
-        print("SLOWER")    
+        self._act("SLOWER")    
     
     def turn_right(self):
-        self.last_action = "STARBOARD"
-        print("STARBOARD")
+        self._act("STARBOARD")
     
     def turn_left(self):
-        self.last_action = "PORT"
-        print("PORT")
+        self._act("PORT")
         
     def wait(self):
-        self.last_action = "WAIT"
-        print("WAIT")
+        self._act("WAIT")
         
     def mine(self):
         self.last_mining = current_turn
-        self.last_action = "MINE"
-        print("MINE")
+        self._act("MINE")
         
     def fire(self, x, y):
         self.last_fire = current_turn
-        self.last_action = "FIRE"
-        print(f"FIRE {x} {y}")
+        self._act("FIRE", x, y)
 
 class Barrel(Entity):
     def __init__(self, *args, **kwargs):
@@ -816,18 +852,12 @@ while True:
     
     # <--- get input
     my_ship_count, entity_count = int(input()), int(input())
+    previous_ent, entities = grid.entities, {}
     for _ in range(entity_count):
         ent_id, ent_type, *data = input().split()
         ent_id = int(ent_id)
-        seen.append(ent_id)
-           
-        if not ent_id in entities:
-            entities[ent_id] = map_entity[ent_type](ent_id)
-               
-        ent = entities[ent_id]
-        ent.update(*data)
-     
-    entities = {k: v for k, v in entities.items() if k in seen}
+        entities[ent_id] = grid.entities.get(ent_id, map_entity[ent_type](ent_id))
+        entities[ent_id].update(*data)
     # --->
     
     grid.load_entities(entities)
@@ -860,10 +890,12 @@ while True:
     for s in grid.owned_ships:
         if not s.objective: 
             continue
+        if grid.manhattan(s.pos, s.objective.target.pos) > 5:
+            continue
         after_that = ObjectivesQueue()
-        for b in grid.barrels:
+        for b in [o.target for o in s.objectives.items]:
             obj = GetBarrel(b)
-            obj.eval(s.objective.target.pos)
+            obj.eval(s.objective.target.pos, s.orientation)
             after_that.put(obj)
         if after_that:
             s.objective_next = after_that.get()
@@ -883,20 +915,19 @@ while True:
         log(f"---- ship {ship.id} ---")
         log(f"ship: {ship}")
         
-        if ship.objective:
-            goto = ship.objective.target.pos
+        if ship.objective or (ship.target_ennemy and ship.target_ennemy.interest < 0):
+            ship.goto = ship.objective.target.pos
         elif ship.target_ennemy:
-            goto = grid.shooting_spot(ship, ship.target_ennemy.target)
+            ship.goto = grid.shooting_spot(ship, ship.target_ennemy.target)
         else:
             log("ERROR: No target")
             continue
         
-        log(f"goto: {goto}")
-        
-        ship.path = grid.path(ship.next_pos, ship.orientation, goto, ship._moving_costs, limit=6000 // len(grid.owned_ships))
+        log(f"goto: {ship.goto}")
+        ship.path = grid.path(ship.next_pos, ship.orientation, ship.goto, ship._moving_costs, limit=6000 // len(grid.owned_ships))
         
         if ship.objective_next and ship.path:
-            ship.path += grid.path(goto, 
+            ship.path += grid.path(ship.goto, 
                                    ship.path[-1].orientation, 
                                    ship.objective_next.target.pos, 
                                    ship._moving_costs,
@@ -904,6 +935,10 @@ while True:
         
         log(f"path: {ship.path}")
         
+    ### special: avoid cannonballs
+    danger = [c.pos for c in grid.cannonballs if c.countdown <= 1]
+    
+    
     ### Process
     log("# Processing")
     
@@ -912,6 +947,11 @@ while True:
             log("No target: wait")
             ship.wait()
         
+        if ship.cant_move():
+            log("blocked... fire!")
+            if ship.fire_at_will(ship.target_ennemy.target, allies=grid.owned_ships):
+                continue
+        
         if ship.move(ship.path):
             continue