Ver Fonte

improve moving and firing algos

olinox há 6 anos atrás
pai
commit
7c5e075213
1 ficheiros alterados com 74 adições e 48 exclusões
  1. 74 48
      carribean/script.py

+ 74 - 48
carribean/script.py

@@ -184,6 +184,8 @@ class Grid(Base):
                 
         for s in self.owned_ships:
             s.allies = [other for other in self.owned_ships if other is not s]
+        for s in self.ennemy_ships:
+            s.allies = [other for other in self.ennemy_ships if other is not s]
 
         self.update_moving_costs()
         
@@ -513,6 +515,12 @@ class Ship(Entity):
     MAX_SPEED = 2
     SCOPE = 10
     
+    SLOW_DOWN = 1
+    SPEED_UP = 2
+    TURN_LEFT = 3
+    TURN_RIGHT = 4
+    MOVES = [SLOW_DOWN, SPEED_UP, TURN_LEFT, TURN_RIGHT]
+    
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.x, self.y = 0, 0
@@ -621,8 +629,6 @@ class Ship(Entity):
             positions[i + 1] = []
             
             for p in positions[i]:
-                if self.moving_cost(*p.pos) >= 1000:
-                    continue
                 
                 pos, d, speed = p.pos, p.d, p.speed
                 
@@ -643,15 +649,20 @@ class Ship(Entity):
                     positions[i + 1].append(Position(Grid.next_cell(*pos, d, repeat=speed + 1), d, speed + 1))
                 
                 # slow down
-                if speed > 0:
+                if speed > 1:
                     positions[i + 1].append(Position(Grid.next_cell(*pos, d, repeat=speed - 1), d, speed - 1))
         
+                # we voluntary ignore the case where a ship at speed 1 would slow down, 
+                # as it is not expected to be a standard behaviour for a ship
+        
         # agregate
         proba = {}
         for i, plst in positions.items():
             proba[i] = {}
             for p in plst:
                 for c in Ship.get_area(*p.pos, p.d):
+                    if self.moving_cost(*c) >= 1000:
+                        continue
                     proba[i][c] = proba[i].get(c, 0) + 10
         
         # involve the moving cost
@@ -662,7 +673,7 @@ class Ship(Entity):
             # if ship is blocked, current area is more accurate
             for c in self.area:
                 proba[i][c] = proba[i].get(c, 0) + 40 * self.blocked_since
-            
+        
         return proba
     
     def guess_next_positions(self, in_=3):
@@ -693,53 +704,75 @@ class Ship(Entity):
     def can_move(self):
         return self.can_move_fwd() or self.can_turn_left() or self.can_turn_left()
         
-    def move(self, *args, **kwargs):
-        try:
-            self._move(*args, **kwargs)
-            return True
-        except DidNotAct:
-            return False
-
-    def _move(self, path):
-        
+    def move(self, path):
+            
         if path is None:
             if self.can_move():
                 log(f"(!) broken: automove to {self.goto}")
                 self.auto_move(*self.goto)
-                return
+                return True
             else:
-                raise DidNotAct()
+                return False
         elif not path:
-            raise DidNotAct()
+            return False
+            
+        planned = self._plan_move(path)
         
-        # flags represent direction changes of end of the path
+        if planned is None:
+            future_pos = self.get_next_cell()
+            future_d = self.orientation
+        else:
+            new_speed = self.speed
+            if planned == Ship.SPEED_UP:
+                new_speed += 1
+            elif planned == Ship.SLOW_DOWN:
+                new_speed -= 1
+            future_pos = path[new_speed]
+            future_d = path[new_speed].orientation
+        
+        future_area = self.get_area(*future_pos, future_d)
+        if any(self.moving_cost(*c) >= 1000 for c in future_area):
+            log("/!\ Danger: planned move would lead to collision")
+
+        if planned == Ship.SPEED_UP:
+            self.speed_up()
+        elif planned == Ship.SLOW_DOWN:
+            self.slow_down()
+        elif planned == Ship.TURN_LEFT:
+            self.turn_left()
+        elif planned == Ship.TURN_RIGHT:
+            self.turn_right()
+        else:
+            return False
+
+        return True
+
+    def _plan_move(self, path):
+        
+        # flags represent direction changes or end of the path
         last_flag = len(path) - 1
-        flags = (i for i, n in enumerate(path) if n.orientation != self.orientation)
-        next_flag = next(flags, last_flag)
-        afternext_flag = next(flags, last_flag)
+        next_flag = next((i for i, n in enumerate(path) if n.orientation != self.orientation), last_flag)
+        afternext_flag = next((i for i, n in enumerate(path[next_flag:]) if n.orientation != path[next_flag].orientation), last_flag)
         
         if not self.speed:
             diff = Grid.diff_directions(self.orientation, path[0].orientation)
             
             if diff > 0 and self.last_action == "STARBOARD" or diff < 0 and self.last_action == "PORT":
                 # special: avoid the starting hesitation
-                self.speed_up()
+                return Ship.SPEED_UP
             
             if diff and next_flag == 0:
                 # start, with a direction change
                 if diff > 0:
                     if self.can_turn_left():
-                        self.turn_left()
-                        return
+                        return Ship.TURN_LEFT
                 elif diff < 0:
                     if self.can_turn_right():
-                        self.turn_right()
-                        return
+                        return Ship.TURN_RIGHT
             else:
                 # start straight
                 if self.can_move_fwd():
-                    self.speed_up()
-                    return
+                    return Ship.SPEED_UP
         
         elif self.speed == self.MAX_SPEED:
             
@@ -747,33 +780,27 @@ class Ship(Entity):
                 # drift
                 diff = Grid.diff_directions(self.orientation, path[next_flag].orientation)
                 if diff > 0:
-                    self.turn_left()
-                    return
+                    return Ship.TURN_LEFT
                 elif diff < 0:
-                    self.turn_right()
-                    return
+                    return Ship.TURN_RIGHT
             
             if (self.speed + 1) >= next_flag:
                 # next direction change or target will be passed at current speed
-                self.slow_down()
-                return
+                return Ship.SLOW_DOWN
 
         elif self.speed == 1:
             
             if self.speed == next_flag:
                 diff = Grid.diff_directions(self.orientation, path[next_flag].orientation)
                 if diff > 0:
-                    self.turn_left()
-                    return
+                    return Ship.TURN_LEFT
                 elif diff < 0:
-                    self.turn_right()
-                    return
+                    return Ship.TURN_RIGHT
             
             elif next_flag > 3 or (next_flag > 2 and afternext_flag >= (next_flag + 2)):
-                self.speed_up()
-                return
+                return Ship.SPEED_UP
         
-        raise DidNotAct()
+        return None
            
     def fire_at_will(self, *args, **kwargs):
         try:
@@ -792,7 +819,7 @@ class Ship(Entity):
         for ally in allies:
             avoid += ally.mobility_zone
         
-        next_positions = target.guess_next_positions(in_=3)
+        next_positions = target.guess_next_positions(in_=4)
         for t, next_pos in next_positions.items():
             dist = Grid.manhattan(self.prow, next_pos)
             if dist > self.SCOPE:
@@ -800,10 +827,10 @@ class Ship(Entity):
             if next_pos in avoid:
                 continue
             
-            dt = (1 + round(dist / 3)) # time for tha cannonball to reach this pos
+            dt = 1 + (1 + round(dist / 3)) # time for the cannonball to reach this pos (including fire turn)
             
-            if (dt + 1) == t:
-                log(f"precise shoot: {next_pos}")
+            if dt == t:
+                log(f"[x] precise shoot: dt={dt}, pos={next_pos}")
                 ship.fire(*next_pos)
                 return
             
@@ -982,14 +1009,13 @@ while True:
                 if new_path:
                     ship.path += new_path
                 else:
-                    break     
-                                
+                    break
  
     for ship in grid.owned_ships:
         log(f"---- ship {ship.id} ---")
         log(f"ship: {ship}")
-        log(f"obj: {ship.objective}; next: {ship.objectives_next}; target: {ship.target_ennemy}")
-        log(f"goto: {ship.goto}")
+        log(f"obj: {ship.objective}; next: {ship.objectives_next}")
+        log(f"target: {ship.target_ennemy}")
         log(f"path: {ship.path}")
         
     ### Process