|
@@ -9,15 +9,10 @@ import time
|
|
|
|
|
|
|
|
# TODO:
|
|
# TODO:
|
|
|
# * find a way to change direction without slowing down if possible
|
|
# * find a way to change direction without slowing down if possible
|
|
|
-# * avoid getting blocked by a side-by-side with an ennemy
|
|
|
|
|
-# * Fix: do not target a barrel that an ennemy is going to take
|
|
|
|
|
-# * Try to interger extra steps into the path algo, instead of adding independents paths
|
|
|
|
|
-# Check if cannonballs with countdown 0 can be ignored in the plan_next_move algo ?
|
|
|
|
|
-# Fix: do not shoot a mine if we are close to it
|
|
|
|
|
-# Fix: if every move leads to collision, avoid those whop hit the center of the ship
|
|
|
|
|
|
|
+# * Try to integer extra steps into the path algo, instead of adding independents paths
|
|
|
|
|
+# * Increase the shooting rate in the second part of the game (no barrels left)
|
|
|
|
|
+# * get_shooting_spots: try to intercept ennemy
|
|
|
|
|
|
|
|
-# Notes:
|
|
|
|
|
-# * Fix: Do not target a barrel that is in the dead angle -> barrels are estimated from the prow
|
|
|
|
|
|
|
|
|
|
debug = True
|
|
debug = True
|
|
|
|
|
|
|
@@ -45,6 +40,11 @@ class Queue():
|
|
|
def put(self, item, priority):
|
|
def put(self, item, priority):
|
|
|
heapq.heappush(self.items, (priority, item))
|
|
heapq.heappush(self.items, (priority, item))
|
|
|
|
|
|
|
|
|
|
+ def fput(self, item, priority):
|
|
|
|
|
+ while priority in [p for p, _ in self.items]:
|
|
|
|
|
+ priority += 1
|
|
|
|
|
+ self.put(item, priority)
|
|
|
|
|
+
|
|
|
def get(self):
|
|
def get(self):
|
|
|
return heapq.heappop(self.items)[1]
|
|
return heapq.heappop(self.items)[1]
|
|
|
|
|
|
|
@@ -99,20 +99,28 @@ class BaseObjective(Base):
|
|
|
def __repr__(self):
|
|
def __repr__(self):
|
|
|
return f"<{self.__class__.__name__}: target={self.target.id};int={self.interest})>"
|
|
return f"<{self.__class__.__name__}: target={self.target.id};int={self.interest})>"
|
|
|
|
|
|
|
|
- def eval(self, pos = None, d = None):
|
|
|
|
|
|
|
+ def _pre_eval(self, pos = None, d = None):
|
|
|
self.distance = Grid.manhattan(pos, self.target.pos) if pos is not None else 0
|
|
self.distance = Grid.manhattan(pos, self.target.pos) if pos is not None else 0
|
|
|
self.alignment = abs(Grid.diff_directions(Grid.direction_to(*pos, *self.target.pos), d)) if d is not None else 0
|
|
self.alignment = abs(Grid.diff_directions(Grid.direction_to(*pos, *self.target.pos), d)) if d is not None else 0
|
|
|
|
|
+
|
|
|
|
|
+ def eval(self, pos = None, d = None):
|
|
|
|
|
+ self._pre_eval(pos, d)
|
|
|
self._compute_interest()
|
|
self._compute_interest()
|
|
|
|
|
|
|
|
def _compute_interest(self):
|
|
def _compute_interest(self):
|
|
|
self.interest = 7 * self.distance + 3 * self.alignment
|
|
self.interest = 7 * self.distance + 3 * self.alignment
|
|
|
|
|
|
|
|
class GetBarrel(BaseObjective):
|
|
class GetBarrel(BaseObjective):
|
|
|
|
|
+
|
|
|
|
|
+ def _pre_eval(self, pos = None, d = None):
|
|
|
|
|
+ super()._pre_eval(pos, d)
|
|
|
|
|
+ self.ennemy_near = any(Grid.manhattan(e.next_pos, self.target.pos) < self.distance for e in grid.ennemy_ships)
|
|
|
|
|
+
|
|
|
def _compute_interest(self):
|
|
def _compute_interest(self):
|
|
|
- self.interest = 6 * self.distance + 9 * self.alignment + 3 * self.target.dispersal + self.target.mine_threat * 2 + 12 * self.target.ennemy_near
|
|
|
|
|
|
|
+ self.interest = 6 * self.distance + 9 * self.alignment + 3 * self.target.dispersal + self.target.mine_threat * 2 + 12 * self.ennemy_near
|
|
|
if self.distance <= 2 and self.alignment > 1:
|
|
if self.distance <= 2 and self.alignment > 1:
|
|
|
# dead angle
|
|
# dead angle
|
|
|
- self.interest -= 18
|
|
|
|
|
|
|
+ self.interest += 36
|
|
|
|
|
|
|
|
class Attack(BaseObjective):
|
|
class Attack(BaseObjective):
|
|
|
def _compute_interest(self):
|
|
def _compute_interest(self):
|
|
@@ -188,6 +196,8 @@ class Grid(Base):
|
|
|
self.mines = []
|
|
self.mines = []
|
|
|
self.cannonballs = []
|
|
self.cannonballs = []
|
|
|
|
|
|
|
|
|
|
+ self.threat = {}
|
|
|
|
|
+
|
|
|
for e in list(entities.values()) + ghost_mines:
|
|
for e in list(entities.values()) + ghost_mines:
|
|
|
self.index[e.pos] = e
|
|
self.index[e.pos] = e
|
|
|
type_ = type(e)
|
|
type_ = type(e)
|
|
@@ -207,6 +217,8 @@ class Grid(Base):
|
|
|
|
|
|
|
|
elif type_ is Cannonball:
|
|
elif type_ is Cannonball:
|
|
|
self.cannonballs.append(e)
|
|
self.cannonballs.append(e)
|
|
|
|
|
+ if e.pos not in self.threat or self.threat[e.pos] > e.countdown:
|
|
|
|
|
+ self.threat = {e.pos: e.countdown}
|
|
|
|
|
|
|
|
for s in self.owned_ships:
|
|
for s in self.owned_ships:
|
|
|
s.allies = [other for other in self.owned_ships if other is not s]
|
|
s.allies = [other for other in self.owned_ships if other is not s]
|
|
@@ -232,7 +244,6 @@ class Grid(Base):
|
|
|
for b in self.barrels:
|
|
for b in self.barrels:
|
|
|
b.dispersal = Grid.manhattan(grav_center, b.pos) if grav_center != None else 0
|
|
b.dispersal = Grid.manhattan(grav_center, b.pos) if grav_center != None else 0
|
|
|
b.mine_threat = any(type(self.at(*c)) is Mine for c in self.neighbors(*b.pos))
|
|
b.mine_threat = any(type(self.at(*c)) is Mine for c in self.neighbors(*b.pos))
|
|
|
- b.ennemy_near = any(b.pos in e.next_area for e in self.ennemy_ships)
|
|
|
|
|
|
|
|
|
|
for s in self.owned_ships:
|
|
for s in self.owned_ships:
|
|
|
|
|
|
|
@@ -252,7 +263,6 @@ class Grid(Base):
|
|
|
obj = Attack(e)
|
|
obj = Attack(e)
|
|
|
obj.eval(s.pos, s.orientation)
|
|
obj.eval(s.pos, s.orientation)
|
|
|
s.ennemies.put(obj)
|
|
s.ennemies.put(obj)
|
|
|
-
|
|
|
|
|
|
|
|
|
|
def at(self, x, y):
|
|
def at(self, x, y):
|
|
|
try:
|
|
try:
|
|
@@ -294,26 +304,37 @@ class Grid(Base):
|
|
|
base_costs[c] += 30
|
|
base_costs[c] += 30
|
|
|
for m in self.mines:
|
|
for m in self.mines:
|
|
|
base_costs[m.pos] += 1000
|
|
base_costs[m.pos] += 1000
|
|
|
|
|
+
|
|
|
|
|
+ if m.pos in self.threat:
|
|
|
|
|
+ if self.threat[m.pos] <= 2:
|
|
|
|
|
+ # avoid the area of a mines going to explode
|
|
|
|
|
+ for n in self.neighbors(*m.pos):
|
|
|
|
|
+ base_costs[n] += 1000
|
|
|
|
|
+
|
|
|
for c in self.cannonballs:
|
|
for c in self.cannonballs:
|
|
|
- base_costs[c.pos] += (150 + (6 - c.countdown) * 200)
|
|
|
|
|
-
|
|
|
|
|
|
|
+ if 0 < c.countdown <= 2:
|
|
|
|
|
+ base_costs[c.pos] += 1000
|
|
|
|
|
+
|
|
|
for ship in self.ships:
|
|
for ship in self.ships:
|
|
|
ship._moving_costs = {}
|
|
ship._moving_costs = {}
|
|
|
ship._moving_costs.update(base_costs)
|
|
ship._moving_costs.update(base_costs)
|
|
|
|
|
+ played_before = True
|
|
|
for other in self.ships:
|
|
for other in self.ships:
|
|
|
if other is ship:
|
|
if other is ship:
|
|
|
|
|
+ played_before = False
|
|
|
continue
|
|
continue
|
|
|
dist = self.manhattan(ship.pos, other.pos)
|
|
dist = self.manhattan(ship.pos, other.pos)
|
|
|
if dist > 6:
|
|
if dist > 6:
|
|
|
continue
|
|
continue
|
|
|
for c in self.zone(other.pos, 3):
|
|
for c in self.zone(other.pos, 3):
|
|
|
ship._moving_costs[c] += 25
|
|
ship._moving_costs[c] += 25
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
next_positions = other.next_pos_proba()
|
|
next_positions = other.next_pos_proba()
|
|
|
- for c, proba in next_positions[1].items():
|
|
|
|
|
- ship._moving_costs[c] = ship._moving_costs.get(c, 0) + 10 * proba
|
|
|
|
|
|
|
+ for c, proba in next_positions[1 if played_before else 0].items():
|
|
|
|
|
+ if proba >= 20:
|
|
|
|
|
+ ship._moving_costs[c] = ship._moving_costs.get(c, 0) + 13 * proba
|
|
|
|
|
|
|
|
- def shooting_spot(self, ship, target):
|
|
|
|
|
|
|
+ def shooting_spot(self, ship, target, current=None):
|
|
|
shooting_spots = Queue()
|
|
shooting_spots = Queue()
|
|
|
target_pos = target.next_pos if type(target) is Ship else target.pos
|
|
target_pos = target.next_pos if type(target) is Ship else target.pos
|
|
|
|
|
|
|
@@ -325,6 +346,9 @@ class Grid(Base):
|
|
|
|
|
|
|
|
interest = 0 # the lower the better
|
|
interest = 0 # the lower the better
|
|
|
|
|
|
|
|
|
|
+ if (x, y) == current:
|
|
|
|
|
+ interest -= 20
|
|
|
|
|
+
|
|
|
interest += ship.moving_cost(x, y)
|
|
interest += ship.moving_cost(x, y)
|
|
|
|
|
|
|
|
# avoid cells too close from borders
|
|
# avoid cells too close from borders
|
|
@@ -333,13 +357,15 @@ class Grid(Base):
|
|
|
if not 3 <= y < (self.h - 3):
|
|
if not 3 <= y < (self.h - 3):
|
|
|
interest += 50
|
|
interest += 50
|
|
|
|
|
|
|
|
- diff = abs(Grid.direction_to(*ship.prow, x, y))
|
|
|
|
|
- if diff > 1:
|
|
|
|
|
- interest += 15 * abs(diff)
|
|
|
|
|
|
|
+ # priorize cells in the current direction
|
|
|
|
|
+ diff = abs(Grid.diff_directions(ship.orientation, Grid.direction_to(*ship.prow, x, y)))
|
|
|
|
|
+ interest += 10 * abs(diff)
|
|
|
|
|
|
|
|
- # priorize spots at distance 5 from active ship
|
|
|
|
|
- interest += (10 * abs(5 - self.manhattan((x, y), ship.pos)))
|
|
|
|
|
|
|
+ # priorize spots at distance 6 from active ship
|
|
|
|
|
+ interest += (10 * abs(6 - self.manhattan((x, y), ship.pos)))
|
|
|
|
|
|
|
|
|
|
+ # priorize spots at distance 6 from targetted ship
|
|
|
|
|
+ interest += (10 * abs(6 - self.manhattan((x, y), target.pos)))
|
|
|
|
|
|
|
|
shooting_spots.put((x, y), interest)
|
|
shooting_spots.put((x, y), interest)
|
|
|
return shooting_spots.get()
|
|
return shooting_spots.get()
|
|
@@ -483,19 +509,19 @@ class Grid(Base):
|
|
|
return result
|
|
return result
|
|
|
|
|
|
|
|
# pathfinding
|
|
# pathfinding
|
|
|
- def path(self, start, d0, target, moving_costs={}, inertia=0, incl_start=False, limit=10000):
|
|
|
|
|
|
|
+ def path(self, start, start_d, target, moving_costs={}, inertia=0, incl_start=False, limit=10000):
|
|
|
nodes = Queue()
|
|
nodes = Queue()
|
|
|
break_on, iteration = limit, 0
|
|
break_on, iteration = limit, 0
|
|
|
broken = False
|
|
broken = False
|
|
|
|
|
|
|
|
effective_start = start
|
|
effective_start = start
|
|
|
- for _ in range(inertia):
|
|
|
|
|
- effective_start = self.next_cell(*effective_start, d0)
|
|
|
|
|
- n = PathNode(*effective_start)
|
|
|
|
|
- n.orientation = d0
|
|
|
|
|
-
|
|
|
|
|
origin = PathNode(*effective_start)
|
|
origin = PathNode(*effective_start)
|
|
|
- origin.orientation = d0
|
|
|
|
|
|
|
+ origin.orientation = start_d
|
|
|
|
|
+
|
|
|
|
|
+ for _ in range(inertia):
|
|
|
|
|
+ effective_start = self.next_cell(*effective_start, start_d)
|
|
|
|
|
+ origin = PathNode(*effective_start, origin)
|
|
|
|
|
+ origin.orientation = start_d
|
|
|
|
|
|
|
|
nodes.put(origin, 0)
|
|
nodes.put(origin, 0)
|
|
|
neighbors = []
|
|
neighbors = []
|
|
@@ -503,7 +529,8 @@ class Grid(Base):
|
|
|
while nodes:
|
|
while nodes:
|
|
|
current = nodes.get()
|
|
current = nodes.get()
|
|
|
|
|
|
|
|
- if current == target or broken:
|
|
|
|
|
|
|
+ if broken or current == target:
|
|
|
|
|
+
|
|
|
path = []
|
|
path = []
|
|
|
previous = current
|
|
previous = current
|
|
|
while previous:
|
|
while previous:
|
|
@@ -537,12 +564,16 @@ class Grid(Base):
|
|
|
if any((moving_costs.get(c, 1000) >= 1000 and not Grid.is_border(*c)) for c in area):
|
|
if any((moving_costs.get(c, 1000) >= 1000 and not Grid.is_border(*c)) for c in area):
|
|
|
continue
|
|
continue
|
|
|
|
|
|
|
|
- cost = current.cost + moving_cost + diff * 10
|
|
|
|
|
|
|
+ cost = current.cost + moving_cost + diff * 20
|
|
|
|
|
|
|
|
- if (x, y) == effective_start and d == d0:
|
|
|
|
|
- # prefer to go right at start
|
|
|
|
|
|
|
+ if (x, y) == start and d == start_d:
|
|
|
|
|
+ # prefer to go right at start (if not speed)
|
|
|
cost -= 10
|
|
cost -= 10
|
|
|
|
|
|
|
|
|
|
+# if diff and current.parent and current.orientation != current.parent.orientation:
|
|
|
|
|
+# # avoid consecutives direction changes
|
|
|
|
|
+# cost += 20
|
|
|
|
|
+
|
|
|
priority = cost + 10 * Grid.manhattan((x, y), target)
|
|
priority = cost + 10 * Grid.manhattan((x, y), target)
|
|
|
|
|
|
|
|
node = PathNode(x, y, current)
|
|
node = PathNode(x, y, current)
|
|
@@ -814,6 +845,10 @@ class Ship(Entity):
|
|
|
|
|
|
|
|
def plan_next_move(self):
|
|
def plan_next_move(self):
|
|
|
|
|
|
|
|
|
|
+ if self.speed and any(self.front in s.area for s in grid.ships if s is not self):
|
|
|
|
|
+ log("Blocked: speed 0")
|
|
|
|
|
+ self.speed = 0
|
|
|
|
|
+
|
|
|
if self.path:
|
|
if self.path:
|
|
|
planned = self._follow_path(self.path)
|
|
planned = self._follow_path(self.path)
|
|
|
|
|
|
|
@@ -832,7 +867,8 @@ class Ship(Entity):
|
|
|
available[Ship.TURN_RIGHT] = 0
|
|
available[Ship.TURN_RIGHT] = 0
|
|
|
|
|
|
|
|
for m in available:
|
|
for m in available:
|
|
|
- available[m] = sum([self.moving_cost(*c) for c in self.area_after_moving(m)])
|
|
|
|
|
|
|
+ new_area = self.area_after_moving(m)
|
|
|
|
|
+ available[m] = 2 * self.moving_cost(*new_area[0]) + 2 * self.moving_cost(*new_area[1]) + self.moving_cost(*new_area[2])
|
|
|
|
|
|
|
|
planned = min(available.items(), key=lambda x: x[1])[0]
|
|
planned = min(available.items(), key=lambda x: x[1])[0]
|
|
|
log(f"(!) broken: automove ({Ship.COMMANDS[planned]})")
|
|
log(f"(!) broken: automove ({Ship.COMMANDS[planned]})")
|
|
@@ -843,21 +879,43 @@ class Ship(Entity):
|
|
|
elif not self.path:
|
|
elif not self.path:
|
|
|
return False
|
|
return False
|
|
|
|
|
|
|
|
- next_move = planned
|
|
|
|
|
- available_moves = [next_move] + [m for m in Ship.MOVES if m != planned]
|
|
|
|
|
|
|
+ next_move = None
|
|
|
|
|
+ available_moves = [planned] + [m for m in Ship.MOVES if m != planned]
|
|
|
|
|
+ risk = Queue()
|
|
|
|
|
|
|
|
for move in available_moves:
|
|
for move in available_moves:
|
|
|
new_area = self.area_after_moving(move)
|
|
new_area = self.area_after_moving(move)
|
|
|
|
|
+ r = 0
|
|
|
|
|
|
|
|
- # 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 ({new_area})")
|
|
|
|
|
|
|
+ for i, c in enumerate(new_area):
|
|
|
|
|
+ mc = self.moving_cost(*c)
|
|
|
|
|
+
|
|
|
|
|
+ if mc >= 1000 and c in grid: # special: extra-grid cells are not consider as collisions since a part of the ship can go there
|
|
|
|
|
+ if grid.threat.get(c, 0) > 1 and mc < 2000:
|
|
|
|
|
+ r += 10
|
|
|
|
|
+ else:
|
|
|
|
|
+ if i == 1:
|
|
|
|
|
+ # the center of the ship is threaten
|
|
|
|
|
+ r += 50
|
|
|
|
|
+ else:
|
|
|
|
|
+ r += 25
|
|
|
|
|
+
|
|
|
|
|
+ risk.fput(move, r)
|
|
|
|
|
+ if r:
|
|
|
|
|
+ log(f"/!\ Danger: planned move <{Ship.COMMANDS[move]}> could lead to collision (risk={r}, area={new_area})")
|
|
|
else:
|
|
else:
|
|
|
|
|
+ log(f"Safe move: {move}")
|
|
|
next_move = move
|
|
next_move = move
|
|
|
break
|
|
break
|
|
|
|
|
+
|
|
|
else:
|
|
else:
|
|
|
- log("* No collision-free move was found, go to the initial one")
|
|
|
|
|
-
|
|
|
|
|
|
|
+ try:
|
|
|
|
|
+ next_move = risk.get()
|
|
|
|
|
+ log(f"* No collision-free move was found, go to the less risky: {next_move}")
|
|
|
|
|
+ except IndexError:
|
|
|
|
|
+ next_move = planned
|
|
|
|
|
+ log("* No collision-free move was found, go to the initial one: {next_move}")
|
|
|
|
|
+
|
|
|
self.next_move = next_move
|
|
self.next_move = next_move
|
|
|
self.next_area = new_area
|
|
self.next_area = new_area
|
|
|
return True
|
|
return True
|
|
@@ -865,7 +923,7 @@ class Ship(Entity):
|
|
|
def _follow_path(self, path):
|
|
def _follow_path(self, path):
|
|
|
|
|
|
|
|
# flags represent direction changes or end of the path
|
|
# flags represent direction changes or end of the path
|
|
|
- last_flag = len(path) - 1
|
|
|
|
|
|
|
+ last_flag = len(path)
|
|
|
next_flag = next((i for i, n in enumerate(path) if n.orientation != self.orientation), 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)
|
|
afternext_flag = next((i for i, n in enumerate(path[next_flag:]) if n.orientation != path[next_flag].orientation), last_flag)
|
|
|
|
|
|
|
@@ -889,21 +947,24 @@ class Ship(Entity):
|
|
|
|
|
|
|
|
elif self.speed == self.MAX_SPEED:
|
|
elif self.speed == self.MAX_SPEED:
|
|
|
|
|
|
|
|
- if self.speed == next_flag and afternext_flag >= (next_flag + 2): # there is at least one straight cell after this drift
|
|
|
|
|
- # drift
|
|
|
|
|
- diff = Grid.diff_directions(self.orientation, path[next_flag].orientation)
|
|
|
|
|
- if diff > 0:
|
|
|
|
|
- return Ship.TURN_LEFT
|
|
|
|
|
- elif diff < 0:
|
|
|
|
|
- return Ship.TURN_RIGHT
|
|
|
|
|
-
|
|
|
|
|
- if (self.speed + 1) >= next_flag:
|
|
|
|
|
|
|
+ if next_flag <= self.speed:
|
|
|
|
|
+ if afternext_flag >= (next_flag + 2): # there is at least one straight cell after this drift
|
|
|
|
|
+ # drift
|
|
|
|
|
+ diff = Grid.diff_directions(self.orientation, path[next_flag].orientation)
|
|
|
|
|
+ if diff > 0:
|
|
|
|
|
+ return Ship.TURN_LEFT
|
|
|
|
|
+ elif diff < 0:
|
|
|
|
|
+ return Ship.TURN_RIGHT
|
|
|
|
|
+ else:
|
|
|
|
|
+ return Ship.SLOW_DOWN
|
|
|
|
|
+
|
|
|
|
|
+ if next_flag <= self.speed + 1:
|
|
|
# next direction change or target will be passed at current speed
|
|
# next direction change or target will be passed at current speed
|
|
|
return Ship.SLOW_DOWN
|
|
return Ship.SLOW_DOWN
|
|
|
|
|
|
|
|
elif self.speed == 1:
|
|
elif self.speed == 1:
|
|
|
|
|
|
|
|
- if self.speed == next_flag:
|
|
|
|
|
|
|
+ if next_flag <= 1:
|
|
|
diff = Grid.diff_directions(self.orientation, path[next_flag].orientation)
|
|
diff = Grid.diff_directions(self.orientation, path[next_flag].orientation)
|
|
|
if diff > 0:
|
|
if diff > 0:
|
|
|
return Ship.TURN_LEFT
|
|
return Ship.TURN_LEFT
|
|
@@ -912,7 +973,7 @@ class Ship(Entity):
|
|
|
|
|
|
|
|
elif next_flag >= 4:
|
|
elif next_flag >= 4:
|
|
|
return Ship.SPEED_UP
|
|
return Ship.SPEED_UP
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return None
|
|
return None
|
|
|
|
|
|
|
|
def move(self):
|
|
def move(self):
|
|
@@ -940,7 +1001,11 @@ class Ship(Entity):
|
|
|
avoid += ship.next_area
|
|
avoid += ship.next_area
|
|
|
|
|
|
|
|
next_positions = target.next_pos_proba(4)
|
|
next_positions = target.next_pos_proba(4)
|
|
|
- barrels = [b.pos for b in grid.barrels if not any(Grid.manhattan(ally.pos, b.pos) <= Grid.manhattan(target.pos, b.pos) for ally in self.allies)]
|
|
|
|
|
|
|
+ barrels = [b.pos for b in grid.barrels]
|
|
|
|
|
+
|
|
|
|
|
+ for bpos in barrels:
|
|
|
|
|
+ if any(Grid.manhattan(ship.pos, bpos) <= Grid.manhattan(target.pos, bpos) for ship in grid.owned_ships):
|
|
|
|
|
+ avoid.append(bpos)
|
|
|
|
|
|
|
|
for t, probas in next_positions.items():
|
|
for t, probas in next_positions.items():
|
|
|
|
|
|
|
@@ -949,8 +1014,13 @@ class Ship(Entity):
|
|
|
for c, proba in probas.items():
|
|
for c, proba in probas.items():
|
|
|
if c in grid.next_to_mine:
|
|
if c in grid.next_to_mine:
|
|
|
mpos = grid.next_to_mine[c].pos
|
|
mpos = grid.next_to_mine[c].pos
|
|
|
- if Grid.manhattan(self.next_pos, mpos) <= 2:
|
|
|
|
|
|
|
+ dist = Grid.manhattan(self.next_pos, mpos)
|
|
|
|
|
+ if dist <= 2:
|
|
|
continue
|
|
continue
|
|
|
|
|
+ alignment = abs(Grid.diff_directions(self.orientation, Grid.direction_to(*self.pos, *mpos)))
|
|
|
|
|
+ if alignment <= 1:
|
|
|
|
|
+ continue
|
|
|
|
|
+
|
|
|
mines_next[mpos] = mines_next.get(mpos, 1) + proba
|
|
mines_next[mpos] = mines_next.get(mpos, 1) + proba
|
|
|
probas.update(mines_next)
|
|
probas.update(mines_next)
|
|
|
|
|
|
|
@@ -989,7 +1059,7 @@ class Ship(Entity):
|
|
|
|
|
|
|
|
def mine_maybe(self):
|
|
def mine_maybe(self):
|
|
|
if self.can_mine():
|
|
if self.can_mine():
|
|
|
- if not any(Grid.manhattan(self.pos, ally.pos) <= 5 for ally in self.allies):
|
|
|
|
|
|
|
+ if not any(Grid.manhattan(self.prow, ally.next_pos) <= 5 for ally in self.allies):
|
|
|
self.mine()
|
|
self.mine()
|
|
|
return True
|
|
return True
|
|
|
return False
|
|
return False
|
|
@@ -1123,7 +1193,7 @@ while True:
|
|
|
for ship in grid.owned_ships:
|
|
for ship in grid.owned_ships:
|
|
|
log(f"---- ship {ship.id} ---")
|
|
log(f"---- ship {ship.id} ---")
|
|
|
log(f"ship: {ship}")
|
|
log(f"ship: {ship}")
|
|
|
- log(f"obj: {ship.objective}; next: {ship.objectives_next}")
|
|
|
|
|
|
|
+
|
|
|
log(f"target: {ship.target_ennemy}")
|
|
log(f"target: {ship.target_ennemy}")
|
|
|
|
|
|
|
|
it_consumed = 0
|
|
it_consumed = 0
|
|
@@ -1131,7 +1201,7 @@ while True:
|
|
|
if ship.objective:
|
|
if ship.objective:
|
|
|
ship.goto = ship.objective.target.pos
|
|
ship.goto = ship.objective.target.pos
|
|
|
elif ship.target_ennemy:
|
|
elif ship.target_ennemy:
|
|
|
- ship.goto = grid.shooting_spot(ship, ship.target_ennemy.target)
|
|
|
|
|
|
|
+ ship.goto = grid.shooting_spot(ship, ship.target_ennemy.target, current=ship.goto)
|
|
|
else:
|
|
else:
|
|
|
log("ERROR: No target")
|
|
log("ERROR: No target")
|
|
|
continue
|
|
continue
|
|
@@ -1147,7 +1217,7 @@ while True:
|
|
|
it_consumed += its
|
|
it_consumed += its
|
|
|
|
|
|
|
|
if ship.objective and ship.path and ship.path[-1] == ship.goto:
|
|
if ship.objective and ship.path and ship.path[-1] == ship.goto:
|
|
|
- while ship.objectives and len(ship.path) < 10:
|
|
|
|
|
|
|
+ while ship.objectives and len(ship.path) < 15:
|
|
|
pos, d = ship.path[-1], ship.path[-1].orientation
|
|
pos, d = ship.path[-1], ship.path[-1].orientation
|
|
|
|
|
|
|
|
ship.objectives = ObjectivesQueue.re_eval(ship.objectives, pos, d)
|
|
ship.objectives = ObjectivesQueue.re_eval(ship.objectives, pos, d)
|
|
@@ -1157,7 +1227,7 @@ while True:
|
|
|
|
|
|
|
|
new_path, its = grid.path(pos, d,
|
|
new_path, its = grid.path(pos, d,
|
|
|
current_obj.target.pos,
|
|
current_obj.target.pos,
|
|
|
- ship._moving_costs,
|
|
|
|
|
|
|
+ moving_costs=ship._moving_costs,
|
|
|
limit=(max_it - it_consumed))
|
|
limit=(max_it - it_consumed))
|
|
|
|
|
|
|
|
it_consumed += its
|
|
it_consumed += its
|
|
@@ -1169,6 +1239,7 @@ while True:
|
|
|
|
|
|
|
|
ship.plan_next_move()
|
|
ship.plan_next_move()
|
|
|
|
|
|
|
|
|
|
+ log(f"obj: {ship.objective}; next: {ship.objectives_next}")
|
|
|
log(f"path: {ship.path}")
|
|
log(f"path: {ship.path}")
|
|
|
log(f"next_move: {Ship.COMMANDS[ship.next_move]}")
|
|
log(f"next_move: {Ship.COMMANDS[ship.next_move]}")
|
|
|
|
|
|
|
@@ -1194,3 +1265,28 @@ while True:
|
|
|
|
|
|
|
|
log("ERROR: Did not act, wait")
|
|
log("ERROR: Did not act, wait")
|
|
|
ship.wait()
|
|
ship.wait()
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+# Changelog:
|
|
|
|
|
+# 2019-04-17
|
|
|
|
|
+# * if no available move, takes the less risky
|
|
|
|
|
+# * add the ennemy_near evaluation to the pre_eval method of GetBarrel and update it
|
|
|
|
|
+# * ignore probas < 20 in the moving cost calc (about ennemy next positions)
|
|
|
|
|
+# * get_shooting_spots: discurage direction changes
|
|
|
|
|
+# * increase shooting_spots distance from 5 to 7
|
|
|
|
|
+# * fire on mines, do not shoot mines that are in front of the ship
|
|
|
|
|
+# * increase the weight of a dead angle in GetBarrel.eval() from 18 to 36 <=> the weight of a distance of 6 needed to turn
|
|
|
|
|
+# * mines: increase moving_cost of neighbors if a cannon ball is going to hit the mine
|
|
|
|
|
+# * Improve the _follow_path algo
|
|
|
|
|
+# * anticipate the speed at 0 when blocked
|
|
|
|
|
+# * coeff 13 instead of 10 for the presence probability, making it impassable from env. 77% instead of 100%
|
|
|
|
|
+# * moving cost takes now in account the order of play of the ships
|
|
|
|
|
+# * increase the max length of the path from 10 to 15 when seeking for next objectives
|
|
|
|
|
+# * minor improvement to automove
|
|
|
|
|
+# * Avoid shooting barrels unless ennemy is nearest
|
|
|
|
|
+# * include distance to ennemy in the eval of the shooting spot
|
|
|
|
|
+# * (disactivated because of below) avoid consecutives direction changes
|
|
|
|
|
+# * path: direction change moving cost changed from 10 to 20 because of the slowing effect
|
|
|
|
|
+
|