olinox 6 лет назад
Родитель
Сommit
696148ca49
1 измененных файлов с 86 добавлено и 72 удалено
  1. 86 72
      carribean/script.py

+ 86 - 72
carribean/script.py

@@ -12,6 +12,8 @@ import sys
 # * find a way to change direction without slowing down if possible
 # * avoid getting blocked by a side-by-side with an ennemy
 # * priorize targetting blocked ennemies
+# * improve the 'avoid' part of the 'fire_at_will' method
+# * use a queue to choose the best shoot instead of a strict equality
 
 debug = True
 
@@ -279,7 +281,6 @@ class Grid(Base):
             
             shooting_spots.put((x, y), interest)
             
-        log(shooting_spots.items)
         return shooting_spots.get()
     
     # geometrical algorithms
@@ -345,9 +346,9 @@ class Grid(Base):
     @staticmethod
     def add_directions(d1, d2):
         d = d2 + d1
-        if d <= -3:
+        if d < 0:
             d += 6
-        elif d > 3:
+        elif d > 5:
             d -= 6
         return d
     
@@ -490,6 +491,12 @@ class Entity(Base):
         return self.id < other.id
     
     
+class Position(Base):
+    def __init__(self, pos, d, speed):
+        self.pos = pos
+        self.d = d
+        self.speed = speed
+    
 class Ship(Entity):
     MAX_SPEED = 2
     SCOPE = 10
@@ -592,45 +599,67 @@ class Ship(Entity):
     def get_next_pos(self, in_=1):
         return self.get_pos_in(self.pos, self.speed, self.orientation, in_)
     
-    def guess_next_pos(self):
-        proba = {}
-        
-        # wait (or fire or mine)
-        for c in self.next_area:
-            proba[c] = proba.get(c, 10)
+    def next_pos_proba(self, in_=1):
+
+        # guess next positions
+        positions = {0: [Position(self.pos, self.orientation, self.speed)]}
         
-        # turn left
-        area = self.get_area(*self.pos, Grid.add_directions(self.orientation, 1))
-        for c in area:
-            proba[c] = proba.get(c, 0) + 10
+        for i in range(in_):
             
-        # turn right
-        area = self.get_area(*self.pos, Grid.add_directions(self.orientation, -1))
-        for c in area:
-            proba[c] = proba.get(c, 0) + 10
+            positions[i + 1] = []
             
-        # speed up
-        if self.speed < self.MAX_SPEED:
-            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
-        
-        # slow down
-        if self.speed > 0:
-            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 p in positions[i]:
+                if self.moving_cost(*p.pos) >= 1000:
+                    continue
+                
+                pos, d, speed = p.pos, p.d, p.speed
+                
+                # next pos with inertia
+                inertia = Grid.next_cell(*pos, d, repeat=speed)
+                
+                # wait (or fire or mine)
+                positions[i + 1].append(Position(inertia, d, speed))
+                
+                # turn left
+                positions[i + 1].append(Position(inertia, Grid.add_directions(d, 1), speed))
+                    
+                # turn right
+                positions[i + 1].append(Position(inertia, Grid.add_directions(d, -1), speed))
+                    
+                # speed up
+                if speed < self.MAX_SPEED:
+                    positions[i + 1].append(Position(Grid.next_cell(*pos, d, repeat=speed + 1), d, speed + 1))
+                
+                # slow down
+                if speed > 0:
+                    positions[i + 1].append(Position(Grid.next_cell(*pos, d, repeat=speed - 1), d, speed - 1))
+        
+        # agregate
+        proba = {}
+        for i, plst in positions.items():
+            proba[i] = {}
+            for p in plst:
+                for c in Ship.get_area(*p.pos, p.d):
+                    proba[i][c] = proba[i].get(c, 0) + 10
+        
+        # involve the moving cost
+        for i in proba:
+            for c in proba[i]:
+                proba[i][c] -= (self.moving_cost(*c) // 2)
+        
+            # 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):
+        proba = self.next_pos_proba(in_)
+        best = {}
+        for i in proba:
+            best[i] = max(proba[i].items(), key=lambda x: x[1])[0]
+        return best
             
-        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):
         return Grid.next_cell(self.x, self.y, self.orientation, repeat=in_)
 
@@ -661,8 +690,6 @@ class Ship(Entity):
 
     def _move(self, path):
         
-        log(self._can_move, self.can_turn_left(), self.can_turn_right(), self.can_move_fwd())
-        
         if path is None:
             if self.can_move():
                 log(f"(!) broken: automove to {self.goto}")
@@ -753,41 +780,30 @@ class Ship(Entity):
         for ally in allies:
             avoid += ally.mobility_zone
         
-        dist = Grid.manhattan(self.prow, target.next_pos)
-        if dist <= 4:
-            # precise algo
-            shoot_at = target.guess_next_pos()
-            log(f"most probable position: {shoot_at}")
-            ship.fire(*shoot_at)
+        next_positions = target.guess_next_positions(in_=3)
+        for t, next_pos in next_positions.items():
+            dist = Grid.manhattan(self.prow, next_pos)
+            if dist > self.SCOPE:
+                continue
+            if next_pos in avoid:
+                continue
             
-        elif dist <= self.SCOPE:
-
-            # anticipate            
-            next_positions = [target.get_next_pos(i) for i in range(1, 3)]
-            for i, p in enumerate(next_positions):
-                turn = i + 1
-                
-                if p in avoid:
-                    continue
-                
-                dist_p = Grid.manhattan(self.prow, p)
-                
-                if dist_p > self.SCOPE:
-                    continue
-                
-                if (1 + round(dist_p / 3)) == turn:
-                    log(f"Precision: {p}, {dist_p}, {turn}")
-                    ship.fire(*p)
-                    return
+            dt = (1 + round(dist / 3)) # time for tha cannonball to reach this pos
             
-            # give a try
-            next_pos = next_positions[0]
+            if dt == t:
+                log(f"precise shoot: {next_pos}")
+                ship.fire(*next_pos)
+                return
+            
+        # give a try
+        next_pos = next_positions[2]
+        if not next_pos in avoid:
             dist_p = Grid.manhattan(self.prow, next_pos)
             if dist_p <= self.SCOPE:
-                ship.fire(*p)
+                ship.fire(*next_pos)
+                return
             
-        else:
-            raise DidNotAct()
+        raise DidNotAct()
         
     def can_mine(self):
         return self.last_mining is None or (current_turn - self.last_mining) >= 4
@@ -961,8 +977,6 @@ while True:
         log(f"goto: {ship.goto}")
         log(f"path: {ship.path}")
         
-        
-        
     ### Process
     log("# Processing")