|
|
@@ -243,8 +243,9 @@ class Grid(Base):
|
|
|
except KeyError:
|
|
|
return None
|
|
|
|
|
|
- def borderline(self, x, y):
|
|
|
- return x == -1 or y == -1 or x == self.w or y == self.h
|
|
|
+ @classmethod
|
|
|
+ def is_border(cls, x, y):
|
|
|
+ return x == -1 or y == -1 or x == cls.w or y == cls.h
|
|
|
|
|
|
def collision_at(self, x, y):
|
|
|
e = self.at(x, y)
|
|
|
@@ -291,12 +292,10 @@ class Grid(Base):
|
|
|
continue
|
|
|
for c in self.zone(other.pos, 3):
|
|
|
ship._moving_costs[c] += 25
|
|
|
+
|
|
|
next_positions = other.next_pos_proba()
|
|
|
for c, proba in next_positions[1].items():
|
|
|
- if proba > 20 and not c in ship.area:
|
|
|
- ship._moving_costs[c] += 1000
|
|
|
- else:
|
|
|
- ship._moving_costs[c] += 100
|
|
|
+ ship._moving_costs[c] = ship._moving_costs.get(c, 0) + 40 * proba
|
|
|
|
|
|
def shooting_spot(self, ship, target):
|
|
|
shooting_spots = Queue()
|
|
|
@@ -521,7 +520,7 @@ class Grid(Base):
|
|
|
continue
|
|
|
|
|
|
area = Ship.get_area(x, y, d)
|
|
|
- if any(moving_costs.get(c, 1000) >= 1000 for c in area):
|
|
|
+ if any((moving_costs.get(c, 1000) >= 1000 and not Grid.is_border(*c)) for c in area):
|
|
|
continue
|
|
|
|
|
|
cost = current.cost + moving_cost + diff * 10
|
|
|
@@ -558,21 +557,24 @@ class Entity(Base):
|
|
|
|
|
|
|
|
|
class Position(Base):
|
|
|
- def __init__(self, pos, d, speed):
|
|
|
+ def __init__(self, pos, d, speed, weight=10):
|
|
|
self.pos = pos
|
|
|
self.d = d
|
|
|
self.speed = speed
|
|
|
+ self.weight = weight
|
|
|
+ self.area = Ship.get_area(*self.pos, self.d)
|
|
|
|
|
|
class Ship(Entity):
|
|
|
MAX_SPEED = 2
|
|
|
SCOPE = 10
|
|
|
|
|
|
+ WAIT = 0
|
|
|
SLOW_DOWN = 1
|
|
|
SPEED_UP = 2
|
|
|
TURN_LEFT = 3
|
|
|
TURN_RIGHT = 4
|
|
|
- MOVES = [SPEED_UP, TURN_LEFT, TURN_RIGHT, SLOW_DOWN]
|
|
|
- COMMANDS = {SLOW_DOWN: "SLOWER", SPEED_UP: "FASTER", TURN_LEFT: "PORT", TURN_RIGHT: "STARBOARD", None: "NONE"}
|
|
|
+ MOVES = [WAIT, SPEED_UP, TURN_LEFT, TURN_RIGHT, SLOW_DOWN]
|
|
|
+ COMMANDS = {SLOW_DOWN: "SLOWER", SPEED_UP: "FASTER", TURN_LEFT: "PORT", TURN_RIGHT: "STARBOARD", WAIT: "WAIT", None: "NONE"}
|
|
|
|
|
|
areas = {}
|
|
|
|
|
|
@@ -593,7 +595,6 @@ class Ship(Entity):
|
|
|
self.last_action = ""
|
|
|
self.allies = []
|
|
|
self._moving_costs = {}
|
|
|
- self.cached_next_pos_proba = {}
|
|
|
|
|
|
self.objectives = ObjectivesQueue()
|
|
|
self.ennemies = ObjectivesQueue()
|
|
|
@@ -610,6 +611,10 @@ class Ship(Entity):
|
|
|
def __repr__(self):
|
|
|
return f"<Ship {self.id}: pos=({self.x}, {self.y}), orientation={self.orientation}, speed={self.speed}, blocked={self.blocked_since}, last_fire={self.last_fire}, next_pos={self.next_pos}, area={self.area}>"
|
|
|
|
|
|
+ @classmethod
|
|
|
+ def abs_area(cls, x, y, d):
|
|
|
+ return [Grid.next_cell(x, y, d), (x, y), Grid.next_cell(x, y, Grid.add_directions(d, 3))]
|
|
|
+
|
|
|
@classmethod
|
|
|
def cache_area(cls, x, y):
|
|
|
for d in range(3):
|
|
|
@@ -622,8 +627,7 @@ class Ship(Entity):
|
|
|
try:
|
|
|
return list(Ship.areas[(x, y, d)])
|
|
|
except KeyError:
|
|
|
- log(f"Error: area key missing {(x, y, d)}")
|
|
|
- return []
|
|
|
+ return cls.abs_area(x, y, d)
|
|
|
|
|
|
def update(self, x, y, *args):
|
|
|
previous_state = self.state()
|
|
|
@@ -641,7 +645,7 @@ class Ship(Entity):
|
|
|
|
|
|
self.goto = None
|
|
|
self.path = []
|
|
|
- self.next_positions = {}
|
|
|
+ self.cached_next_pos_proba = {}
|
|
|
|
|
|
self.area = Ship.get_area(self.x, self.y, self.orientation)
|
|
|
self.prow, _, self.stern = self.area
|
|
|
@@ -702,26 +706,34 @@ class Ship(Entity):
|
|
|
# next pos with inertia
|
|
|
inertia = Grid.next_cell(*pos, d, repeat=speed)
|
|
|
|
|
|
- # wait (doubled)
|
|
|
- positions[i + 1].append(Position(inertia, d, speed))
|
|
|
- positions[i + 1].append(Position(inertia, d, speed))
|
|
|
-
|
|
|
- # fire or mine
|
|
|
- positions[i + 1].append(Position(inertia, d, speed))
|
|
|
+ # wait, fire or mine
|
|
|
+ p = Position(inertia, d, speed, 30)
|
|
|
+ if self.moving_cost(*p.pos) >= 1000:
|
|
|
+ p.weight = 10
|
|
|
+ positions[i + 1].append(p)
|
|
|
|
|
|
# turn left
|
|
|
- positions[i + 1].append(Position(inertia, Grid.add_directions(d, 1), speed))
|
|
|
+ p = Position(inertia, Grid.add_directions(d, 1), speed)
|
|
|
+ if not self.moving_cost(*p.pos) >= 1000:
|
|
|
+ positions[i + 1].append(p)
|
|
|
|
|
|
# turn right
|
|
|
- positions[i + 1].append(Position(inertia, Grid.add_directions(d, -1), speed))
|
|
|
+ p = Position(inertia, Grid.add_directions(d, -1), speed)
|
|
|
+ if not self.moving_cost(*p.pos) >= 1000:
|
|
|
+ positions[i + 1].append(p)
|
|
|
|
|
|
# speed up
|
|
|
if speed < self.MAX_SPEED:
|
|
|
- positions[i + 1].append(Position(Grid.next_cell(*pos, d, repeat=speed + 1), d, speed + 1))
|
|
|
+ p = Position(Grid.next_cell(*pos, d, repeat=speed + 1), d, speed + 1)
|
|
|
+ if not self.moving_cost(*p.pos) >= 1000:
|
|
|
+ positions[i + 1].append(p)
|
|
|
|
|
|
# slow down
|
|
|
if speed > 1:
|
|
|
- positions[i + 1].append(Position(Grid.next_cell(*pos, d, repeat=speed - 1), d, speed - 1))
|
|
|
+ p = Position(Grid.next_cell(*pos, d, repeat=speed - 1), d, speed - 1)
|
|
|
+ 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
|
|
|
@@ -731,19 +743,14 @@ class Ship(Entity):
|
|
|
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
|
|
|
- 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
|
|
|
+ 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) + 40 * self.blocked_since
|
|
|
|
|
|
self.cached_next_pos_proba = proba
|
|
|
|
|
|
@@ -766,12 +773,14 @@ class Ship(Entity):
|
|
|
return self._moving_costs.get((x, y), 1000)
|
|
|
|
|
|
def can_turn_left(self):
|
|
|
- return (self._can_move[self.left] or grid.borderline(*self.left)) \
|
|
|
- and (self._can_move[self.back_right] or grid.borderline(*self.right))
|
|
|
+ return (self._can_move[self.left] or grid.is_border(*self.left)) \
|
|
|
+ and (self._can_move[self.right] or grid.is_border(*self.right)) \
|
|
|
+ and (self._can_move[self.back_right] or grid.is_border(*self.back_right))
|
|
|
|
|
|
def can_turn_right(self):
|
|
|
- return (self._can_move[self.right] or grid.borderline(*self.right)) \
|
|
|
- and (self._can_move[self.back_left] or grid.borderline(*self.back_left))
|
|
|
+ return (self._can_move[self.right] or grid.is_border(*self.right)) \
|
|
|
+ and (self._can_move[self.left] or grid.is_border(*self.left)) \
|
|
|
+ and (self._can_move[self.back_left] or grid.is_border(*self.back_left))
|
|
|
|
|
|
def can_move_fwd(self):
|
|
|
return self._can_move[self.front]
|
|
|
@@ -795,7 +804,6 @@ class Ship(Entity):
|
|
|
return self.get_area(*new_pos, new_orientation)
|
|
|
|
|
|
def move(self, path):
|
|
|
- broken = False
|
|
|
|
|
|
if path:
|
|
|
planned = self._plan_move(path)
|
|
|
@@ -804,9 +812,11 @@ class Ship(Entity):
|
|
|
if self.can_move():
|
|
|
available = {}
|
|
|
|
|
|
- broken = True
|
|
|
- if not self.speed and self.can_move_fwd():
|
|
|
- available[Ship.SPEED_UP] = 0
|
|
|
+ if self.can_move_fwd():
|
|
|
+ if self.speed:
|
|
|
+ available[Ship.WAIT] = 0
|
|
|
+ else:
|
|
|
+ available[Ship.SPEED_UP] = 0
|
|
|
if self.can_turn_left():
|
|
|
available[Ship.TURN_LEFT] = 0
|
|
|
if self.can_turn_right():
|
|
|
@@ -836,11 +846,6 @@ class Ship(Entity):
|
|
|
next_move = move
|
|
|
break
|
|
|
else:
|
|
|
-# if broken:
|
|
|
-# log("* No collision-free move was found, try automove")
|
|
|
-# self.auto_move(*self.goto)
|
|
|
-# return True
|
|
|
-# else:
|
|
|
log("* No collision-free move was found, go to the initial one")
|
|
|
|
|
|
if next_move == Ship.SPEED_UP:
|
|
|
@@ -906,7 +911,7 @@ class Ship(Entity):
|
|
|
elif diff < 0:
|
|
|
return Ship.TURN_RIGHT
|
|
|
|
|
|
- elif next_flag > 3:
|
|
|
+ elif next_flag >= 4:
|
|
|
return Ship.SPEED_UP
|
|
|
|
|
|
return None
|