|
|
@@ -11,9 +11,9 @@ import sys
|
|
|
# * if an enemy is near a mine, shoot the mine instead of the ship
|
|
|
# * 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
|
|
|
+# * why do mines explode when turning around?
|
|
|
|
|
|
debug = True
|
|
|
|
|
|
@@ -23,7 +23,7 @@ def log(*msg):
|
|
|
|
|
|
current_turn = 0
|
|
|
|
|
|
-class DidNotAct(Exception):
|
|
|
+class CollisionAlert(Exception):
|
|
|
pass
|
|
|
|
|
|
class Queue():
|
|
|
@@ -232,6 +232,7 @@ class Grid(Base):
|
|
|
|
|
|
def update_moving_costs(self):
|
|
|
base_costs = {}
|
|
|
+ self.collisions = []
|
|
|
|
|
|
for x in range(-1, self.w + 1):
|
|
|
for y in range(-1, self.h + 1):
|
|
|
@@ -276,7 +277,7 @@ class Grid(Base):
|
|
|
for x, y in self.zone(target_pos, 10):
|
|
|
if ship.moving_cost(x, y) > 100:
|
|
|
continue
|
|
|
- if self.manhattan((x, y), target_pos) <= 1:
|
|
|
+ if self.manhattan((x, y), target_pos) <= 2:
|
|
|
continue
|
|
|
|
|
|
interest = 0 # the lower the better
|
|
|
@@ -284,17 +285,20 @@ class Grid(Base):
|
|
|
interest += ship.moving_cost(x, y)
|
|
|
|
|
|
# avoid cells too close from borders
|
|
|
- if not (3 <= x <= (self.w - 3) and 3 <= y < (self.h - 3)):
|
|
|
- interest += 30
|
|
|
+ if not 3 < x < (self.w - 3):
|
|
|
+ interest += 50
|
|
|
+ if not 3 <= y < (self.h - 3):
|
|
|
+ interest += 50
|
|
|
|
|
|
- diff = Grid.direction_to(*ship.prow, x, y)
|
|
|
- interest += 10 * abs(diff)
|
|
|
+ diff = abs(Grid.direction_to(*ship.prow, x, y))
|
|
|
+ if diff > 1:
|
|
|
+ interest += 15 * abs(diff)
|
|
|
|
|
|
# priorize spots at distance 5 from active ship
|
|
|
interest += (10 * abs(5 - self.manhattan((x, y), ship.pos)))
|
|
|
|
|
|
- shooting_spots.put((x, y), interest)
|
|
|
|
|
|
+ shooting_spots.put((x, y), interest)
|
|
|
return shooting_spots.get()
|
|
|
|
|
|
# geometrical algorithms
|
|
|
@@ -520,6 +524,7 @@ class Ship(Entity):
|
|
|
TURN_LEFT = 3
|
|
|
TURN_RIGHT = 4
|
|
|
MOVES = [SLOW_DOWN, SPEED_UP, TURN_LEFT, TURN_RIGHT]
|
|
|
+ COMMANDS = {SLOW_DOWN: "SLOWER", SPEED_UP: "FASTER", TURN_LEFT: "PORT", TURN_RIGHT: "STARBOARD"}
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
super().__init__(*args, **kwargs)
|
|
|
@@ -703,7 +708,7 @@ 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, path):
|
|
|
|
|
|
if path is None:
|
|
|
@@ -715,32 +720,43 @@ class Ship(Entity):
|
|
|
return False
|
|
|
elif not path:
|
|
|
return False
|
|
|
-
|
|
|
+
|
|
|
planned = self._plan_move(path)
|
|
|
+ next_move = planned
|
|
|
+ available_moves = [next_move] + [m for m in Ship.MOVES if m != planned]
|
|
|
|
|
|
- if planned is None:
|
|
|
- future_pos = self.get_next_cell()
|
|
|
- future_d = self.orientation
|
|
|
- else:
|
|
|
+ for move in available_moves:
|
|
|
+
|
|
|
new_speed = self.speed
|
|
|
- if planned == Ship.SPEED_UP:
|
|
|
+ new_orientation = self.orientation
|
|
|
+ if move == Ship.SPEED_UP:
|
|
|
new_speed += 1
|
|
|
- elif planned == Ship.SLOW_DOWN:
|
|
|
+ elif move == 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:
|
|
|
+ elif move == Ship.TURN_LEFT:
|
|
|
+ new_orientation = Grid.add_directions(self.orientation, 1)
|
|
|
+ elif move == Ship.TURN_RIGHT:
|
|
|
+ new_orientation = Grid.add_directions(self.orientation, -1)
|
|
|
+
|
|
|
+ new_pos = self.get_next_cell(new_speed)
|
|
|
+ new_area = self.get_area(*new_pos, new_orientation)
|
|
|
+
|
|
|
+ # 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")
|
|
|
+ else:
|
|
|
+ next_move = move
|
|
|
+ break
|
|
|
+ else:
|
|
|
+ log("* No collision-free move was found, go to the initial one")
|
|
|
+
|
|
|
+ if next_move == Ship.SPEED_UP:
|
|
|
self.speed_up()
|
|
|
- elif planned == Ship.SLOW_DOWN:
|
|
|
+ elif next_move == Ship.SLOW_DOWN:
|
|
|
self.slow_down()
|
|
|
- elif planned == Ship.TURN_LEFT:
|
|
|
+ elif next_move == Ship.TURN_LEFT:
|
|
|
self.turn_left()
|
|
|
- elif planned == Ship.TURN_RIGHT:
|
|
|
+ elif next_move == Ship.TURN_RIGHT:
|
|
|
self.turn_right()
|
|
|
else:
|
|
|
return False
|
|
|
@@ -754,9 +770,13 @@ class Ship(Entity):
|
|
|
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)
|
|
|
|
|
|
+ log(self.id, self.speed, self.can_move_fwd(), self.can_turn_left(), self.can_turn_right())
|
|
|
+
|
|
|
if diff > 0 and self.last_action == "STARBOARD" or diff < 0 and self.last_action == "PORT":
|
|
|
# special: avoid the starting hesitation
|
|
|
return Ship.SPEED_UP
|
|
|
@@ -769,10 +789,10 @@ class Ship(Entity):
|
|
|
elif diff < 0:
|
|
|
if self.can_turn_right():
|
|
|
return Ship.TURN_RIGHT
|
|
|
- else:
|
|
|
- # start straight
|
|
|
- if self.can_move_fwd():
|
|
|
- return Ship.SPEED_UP
|
|
|
+
|
|
|
+ # start straight
|
|
|
+ if self.can_move_fwd():
|
|
|
+ return Ship.SPEED_UP
|
|
|
|
|
|
elif self.speed == self.MAX_SPEED:
|
|
|
|
|
|
@@ -803,15 +823,11 @@ class Ship(Entity):
|
|
|
return None
|
|
|
|
|
|
def fire_at_will(self, *args, **kwargs):
|
|
|
- try:
|
|
|
- self._fire_at_will(*args, **kwargs)
|
|
|
- return True
|
|
|
- except DidNotAct:
|
|
|
- return False
|
|
|
+ return self._fire_at_will(*args, **kwargs)
|
|
|
|
|
|
def _fire_at_will(self, target, allies = []):
|
|
|
if not self.can_fire():
|
|
|
- raise DidNotAct()
|
|
|
+ return False
|
|
|
|
|
|
avoid = []
|
|
|
if not self in allies:
|
|
|
@@ -832,7 +848,7 @@ class Ship(Entity):
|
|
|
if dt == t:
|
|
|
log(f"[x] precise shoot: dt={dt}, pos={next_pos}")
|
|
|
ship.fire(*next_pos)
|
|
|
- return
|
|
|
+ return True
|
|
|
|
|
|
# give a try
|
|
|
next_pos = next_positions[2]
|
|
|
@@ -840,9 +856,9 @@ class Ship(Entity):
|
|
|
dist_p = Grid.manhattan(self.prow, next_pos)
|
|
|
if dist_p <= self.SCOPE:
|
|
|
ship.fire(*next_pos)
|
|
|
- return
|
|
|
+ return True
|
|
|
|
|
|
- raise DidNotAct()
|
|
|
+ return False
|
|
|
|
|
|
def can_mine(self):
|
|
|
return self.last_mining is None or (current_turn - self.last_mining) >= 4
|
|
|
@@ -949,9 +965,8 @@ while True:
|
|
|
log(f"Barrels: {grid.barrels}")
|
|
|
# log(f"Mines: {grid.mines}")
|
|
|
log(f"Cannonballs: {grid.cannonballs}")
|
|
|
-
|
|
|
|
|
|
- max_it = 9000 // len(grid.owned_ships)
|
|
|
+ max_it = 6000 // len(grid.owned_ships)
|
|
|
|
|
|
### Acquire
|
|
|
log("# Acquiring")
|
|
|
@@ -1016,6 +1031,7 @@ while True:
|
|
|
log(f"ship: {ship}")
|
|
|
log(f"obj: {ship.objective}; next: {ship.objectives_next}")
|
|
|
log(f"target: {ship.target_ennemy}")
|
|
|
+ log(f"goto: {ship.goto}")
|
|
|
log(f"path: {ship.path}")
|
|
|
|
|
|
### Process
|