فهرست منبع

improve fire algo

olinox 6 سال پیش
والد
کامیت
46bbc7d35c
1فایلهای تغییر یافته به همراه73 افزوده شده و 51 حذف شده
  1. 73 51
      carribean/script.py

+ 73 - 51
carribean/script.py

@@ -8,10 +8,9 @@ import time
 
 
 # TODO:
-# * if an enemy is near a mine, shoot the mine instead of the ship
+# * improve the probability next pos
 # * find a way to change direction without slowing down if possible
 # * avoid getting blocked by a side-by-side with an ennemy
-# * use a queue to choose the best shoot instead of a strict equality
 
 debug = True
 
@@ -207,6 +206,16 @@ class Grid(Base):
         for s in self.ships:
             s.next_pos_proba(2)
 
+        self.next_to_mine = {}
+        for m in self.mines:
+            for n in self.neighbors(*m.pos):
+                self.next_to_mine[n] = m
+
+        self.next_to_barrel = {}
+        for b in self.barrels:
+            for n in self.neighbors(*b.pos):
+                self.next_to_barrel[n] = b
+
         self.update_moving_costs()
         
         grav_center = self.barrels_gravity_center()
@@ -271,13 +280,12 @@ class Grid(Base):
             elif x in (0, self.w - 1) or y in (0, self.h - 1):
                 base_costs[(x, y)] = 15 # borders are a little more expensive     
         
-        for m in self.mines:
-            for n in self.neighbors(*m.pos):
-                base_costs[n] += 30
+        for c in self.next_to_mine:
+            base_costs[c] += 30
         for m in self.mines:
             base_costs[m.pos] += 1000
         for c in self.cannonballs:
-            base_costs[c.pos] += (200 + (6 - c.countdown) * 200)
+            base_costs[c.pos] += (150 + (6 - c.countdown) * 200)
         
         for ship in self.ships:
             ship._moving_costs = {}
@@ -706,8 +714,7 @@ class Ship(Entity):
                 p = Position(inertia, d, speed, 30)
                 if self.moving_cost(*p.pos) >= 1000:
                     p.weight = 10
-                positions[i + 1].append(p)
-                
+                    
                 # turn left
                 p = Position(inertia, Grid.add_directions(d, 1), speed)
                 if not self.moving_cost(*p.pos) >= 1000:
@@ -730,7 +737,6 @@ class Ship(Entity):
                     if not self.moving_cost(*p.pos) >= 1000:
                         positions[i + 1].append(p)
         
-        
                 # 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
         
@@ -738,16 +744,15 @@ class Ship(Entity):
         proba = {}
         for i, plst in positions.items():
             proba[i] = {}
+            weights = {}
+            total_weight = sum([p.weight for p in plst])
             for p in plst:
                 for c in p.area:
-                    proba[i][c] = proba[i].get(c, 0) + p.weight
-             
-        # if ship is blocked, current area is more accurate       
-        if self.blocked_since:
-            for i in proba:
-                for c in self.area:
-                    proba[i][c] = proba[i].get(c, 0) + 30 * self.blocked_since
-                
+                    weights[c] = weights.get(c, 0) + p.weight
+            
+            for c in weights:
+                proba[i][c] = 100 * weights[c] // total_weight
+
         self.cached_next_pos_proba = proba
                 
         return proba
@@ -835,10 +840,10 @@ class Ship(Entity):
         
         for move in available_moves:
             new_area = self.area_after_moving(move)
-
+            
             # special: extra-grid cells are not consider as collisions since a part of the ship can go there
             if any((self.moving_cost(*c) >= 1000 and c in grid) for c in new_area):
-                log(f"/!\ Danger: planned move <{Ship.COMMANDS[move]}> would lead to collision")
+                log(f"/!\ Danger: planned move <{Ship.COMMANDS[move]}> would lead to collision ({new_area})")
             else:
                 next_move = move
                 break
@@ -848,20 +853,6 @@ class Ship(Entity):
         self.next_move = next_move
         self.next_area = new_area
         return True
-        
-        
-    def move(self):
-        if self.next_move == Ship.SPEED_UP:
-            self.speed_up()
-        elif self.next_move == Ship.SLOW_DOWN:
-            self.slow_down()
-        elif self.next_move == Ship.TURN_LEFT:
-            self.turn_left()
-        elif self.next_move == Ship.TURN_RIGHT:
-            self.turn_right()
-        else:
-            return False
-        return True
 
     def _follow_path(self, path):
         
@@ -918,6 +909,19 @@ class Ship(Entity):
         
         return None
            
+    def move(self):
+        if self.next_move == Ship.SPEED_UP:
+            self.speed_up()
+        elif self.next_move == Ship.SLOW_DOWN:
+            self.slow_down()
+        elif self.next_move == Ship.TURN_LEFT:
+            self.turn_left()
+        elif self.next_move == Ship.TURN_RIGHT:
+            self.turn_right()
+        else:
+            return False
+        return True
+           
     def fire_at_will(self, *args, **kwargs):
         return self._fire_at_will(*args, **kwargs)
            
@@ -930,27 +934,45 @@ class Ship(Entity):
             avoid += ally.next_area
         
         next_positions = target.next_pos_proba(4)
-        best_shots = Queue()
-        for t, cells in next_positions.items():
-            for c, proba in cells.items():
+        
+        for t, probas in next_positions.items():
+            
+            # include mines and barrels
+            mines_next = {}
+            for c, proba in probas.items():
+                if c in grid.next_to_mine:
+                    mpos = grid.next_to_mine[c].pos
+                    mines_next[mpos] = mines_next.get(mpos, 1) + proba
+            probas.update(mines_next)
+                    
+            barrels = [b.pos for b in grid.barrels]
+            for c in probas:
+                if c in barrels:
+                    probas[c] += 20
+            
+            shots = sorted(probas.items(), key=lambda x: x[1], reverse=True)
+            log(t, shots)
+            
+            for c, proba in shots:
                 if c in avoid:
                     continue
+                if proba < 20:
+                    continue
                 dist = Grid.manhattan(self.prow, c)
                 if dist > self.SCOPE:
                     continue
-    
-                dt = 1 + (1 + round(dist / 3)) # time for the cannonball to reach this pos (including fire turn)
                 
-                interest = 30 * abs(dt - t) - proba # the lower the better
-                best_shots.put(c, interest)
-            
-        try:
-            shoot_at = best_shots.get()
-            log(f"[x] precise shoot: pos={shoot_at}")
-            ship.fire(*shoot_at)
-            return True
-        except IndexError:
-            return False
+                # time for the cannonball to reach this pos (including fire turn)
+                delay = 1 + (1 + round(dist / 3)) 
+                
+                if delay != t:
+                    continue
+                
+                log(f"[x] precise shoot: pos={c}")
+                ship.fire(*c)
+                return True
+                
+        return False
         
     def can_mine(self):
         return self.last_mining is None or (current_turn - self.last_mining) >= 4
@@ -1092,6 +1114,9 @@ while True:
     log("# Planning")
     
     for ship in grid.owned_ships:
+        log(f"---- ship {ship.id} ---")
+        log(f"ship: {ship}")
+        
         it_consumed = 0
         
         if ship.objective:
@@ -1133,9 +1158,6 @@ while True:
  
         ship.plan_next_move()
  
-    for ship in grid.owned_ships:
-        log(f"---- ship {ship.id} ---")
-        log(f"ship: {ship}")
         log(f"obj: {ship.objective}; next: {ship.objectives_next}")
         log(f"target: {ship.target_ennemy}")
         log(f"goto: {ship.goto}")