|
@@ -193,6 +193,8 @@ class Grid(Base):
|
|
|
obj.eval(s.next_pos, s.orientation)
|
|
obj.eval(s.next_pos, s.orientation)
|
|
|
s.ennemies.put(obj)
|
|
s.ennemies.put(obj)
|
|
|
|
|
|
|
|
|
|
+ self.update_moving_costs()
|
|
|
|
|
+
|
|
|
|
|
|
|
|
def at(self, x, y):
|
|
def at(self, x, y):
|
|
|
try:
|
|
try:
|
|
@@ -217,12 +219,13 @@ class Grid(Base):
|
|
|
|
|
|
|
|
for x in range(-1, self.w + 1):
|
|
for x in range(-1, self.w + 1):
|
|
|
for y in range(-1, self.h + 1):
|
|
for y in range(-1, self.h + 1):
|
|
|
- if x in (0, self.w) or y in (0, self.h):
|
|
|
|
|
- base_costs[(x, y)] = 15 # borders are a little more expensive
|
|
|
|
|
- elif x in (-1, self.w + 1) or y in (-1, self.h + 1):
|
|
|
|
|
- base_costs[(x, y)] = 1000 # out of the map
|
|
|
|
|
- else:
|
|
|
|
|
- base_costs[(x, y)] = 10 # base moving cost
|
|
|
|
|
|
|
+ base_costs[(x, y)] = 10 # base moving cost
|
|
|
|
|
+
|
|
|
|
|
+ for x, y in base_costs:
|
|
|
|
|
+ if x in (-1, self.w + 1) or y in (-1, self.h):
|
|
|
|
|
+ base_costs[(x, y)] = 1000 # out of the map
|
|
|
|
|
+ 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 m in self.mines:
|
|
|
for n in self.neighbors(*m.pos):
|
|
for n in self.neighbors(*m.pos):
|
|
@@ -233,7 +236,8 @@ class Grid(Base):
|
|
|
base_costs[c.pos] += (100 + (5 - c.countdown) * 200)
|
|
base_costs[c.pos] += (100 + (5 - c.countdown) * 200)
|
|
|
|
|
|
|
|
for ship in self.ships:
|
|
for ship in self.ships:
|
|
|
- ship._moving_costs = base_costs
|
|
|
|
|
|
|
+ ship._moving_costs = {}
|
|
|
|
|
+ ship._moving_costs.update(base_costs)
|
|
|
for other in self.ships:
|
|
for other in self.ships:
|
|
|
if other is ship:
|
|
if other is ship:
|
|
|
continue
|
|
continue
|
|
@@ -328,6 +332,15 @@ class Grid(Base):
|
|
|
else:
|
|
else:
|
|
|
return 1 if y0 % 2 == 0 else 2
|
|
return 1 if y0 % 2 == 0 else 2
|
|
|
|
|
|
|
|
|
|
+ @staticmethod
|
|
|
|
|
+ def add_directions(d1, d2):
|
|
|
|
|
+ d = d2 + d1
|
|
|
|
|
+ if d <= -3:
|
|
|
|
|
+ d += 6
|
|
|
|
|
+ elif d > 3:
|
|
|
|
|
+ d -= 6
|
|
|
|
|
+ return d
|
|
|
|
|
+
|
|
|
@staticmethod
|
|
@staticmethod
|
|
|
def diff_directions(d1, d2):
|
|
def diff_directions(d1, d2):
|
|
|
d = d2 - d1
|
|
d = d2 - d1
|
|
@@ -526,9 +539,18 @@ class Ship(Entity):
|
|
|
def state(self):
|
|
def state(self):
|
|
|
return (self.x, self.y, self.orientation, self.speed)
|
|
return (self.x, self.y, self.orientation, self.speed)
|
|
|
|
|
|
|
|
|
|
+ @classmethod
|
|
|
|
|
+ def get_pos_in(cls, current, speed, orientation, in_=1):
|
|
|
|
|
+ x, y = current
|
|
|
|
|
+ for _ in range(in_):
|
|
|
|
|
+ for _ in range(speed):
|
|
|
|
|
+ dx, dy = Grid.directions(y)[orientation]
|
|
|
|
|
+ x, y = x + dx, y + dy
|
|
|
|
|
+ return x, y
|
|
|
|
|
+
|
|
|
@classmethod
|
|
@classmethod
|
|
|
def get_area(cls, x, y, orientation):
|
|
def get_area(cls, x, y, orientation):
|
|
|
- dx, dy = Grid.directions(y)[((orientation + 3) % 6)]
|
|
|
|
|
|
|
+ dx, dy = Grid.directions(y)[Grid.add_directions(orientation, 3)]
|
|
|
stern = (x + dx, y + dy)
|
|
stern = (x + dx, y + dy)
|
|
|
|
|
|
|
|
dx, dy = Grid.directions(y)[orientation]
|
|
dx, dy = Grid.directions(y)[orientation]
|
|
@@ -537,12 +559,43 @@ class Ship(Entity):
|
|
|
return [prow, (x, y), stern]
|
|
return [prow, (x, y), stern]
|
|
|
|
|
|
|
|
def get_next_pos(self, in_=1):
|
|
def get_next_pos(self, in_=1):
|
|
|
- x, y = self.x, self.y
|
|
|
|
|
- for _ in range(in_):
|
|
|
|
|
- for _ in range(self.speed):
|
|
|
|
|
- dx, dy = Grid.directions(y)[self.orientation]
|
|
|
|
|
- x, y = x + dx, y + dy
|
|
|
|
|
- return x, y
|
|
|
|
|
|
|
+ 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)
|
|
|
|
|
+
|
|
|
|
|
+ # 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
|
|
|
|
|
+
|
|
|
|
|
+ # 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
|
|
|
|
|
+
|
|
|
|
|
+ # 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 c in proba:
|
|
|
|
|
+ proba[c] -= self.moving_cost(*c)
|
|
|
|
|
+
|
|
|
|
|
+ best = max(proba.items(), key=lambda x: x[1])
|
|
|
|
|
+
|
|
|
|
|
+ return best[0]
|
|
|
|
|
|
|
|
def get_next_cell(self, in_=1):
|
|
def get_next_cell(self, in_=1):
|
|
|
x, y = self.x, self.y
|
|
x, y = self.x, self.y
|
|
@@ -629,43 +682,48 @@ class Ship(Entity):
|
|
|
if not self.can_fire():
|
|
if not self.can_fire():
|
|
|
raise DidNotAct()
|
|
raise DidNotAct()
|
|
|
|
|
|
|
|
- log("** fire at will")
|
|
|
|
|
-
|
|
|
|
|
- next_positions = [target.get_next_pos(i) for i in range(1, 3)]
|
|
|
|
|
- log(f"ennemy next pos: {next_positions}")
|
|
|
|
|
-
|
|
|
|
|
avoid = []
|
|
avoid = []
|
|
|
if not self in allies:
|
|
if not self in allies:
|
|
|
allies.append(self)
|
|
allies.append(self)
|
|
|
for ally in allies:
|
|
for ally in allies:
|
|
|
avoid += ally.mobility_zone
|
|
avoid += ally.mobility_zone
|
|
|
-
|
|
|
|
|
- log(f"avoid: {avoid}")
|
|
|
|
|
-
|
|
|
|
|
- for i, p in enumerate(next_positions):
|
|
|
|
|
- turn = i + 1
|
|
|
|
|
-
|
|
|
|
|
- if p in avoid:
|
|
|
|
|
- continue
|
|
|
|
|
-
|
|
|
|
|
- dist_p = Grid.manhattan(self.prow, p)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ 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)
|
|
|
|
|
|
|
|
- if dist_p > self.SCOPE:
|
|
|
|
|
- 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
|
|
|
|
|
|
|
|
- if (1 + round(dist_p / 3)) == turn:
|
|
|
|
|
- log(f"Precision: {p}, {dist_p}, {turn}")
|
|
|
|
|
|
|
+ # give a try
|
|
|
|
|
+ next_pos = next_positions[0]
|
|
|
|
|
+ dist_p = Grid.manhattan(self.prow, next_pos)
|
|
|
|
|
+ if dist_p <= self.SCOPE:
|
|
|
ship.fire(*p)
|
|
ship.fire(*p)
|
|
|
- return
|
|
|
|
|
-
|
|
|
|
|
- next_pos = next_positions[0]
|
|
|
|
|
- dist_p = Grid.manhattan(self.prow, next_pos)
|
|
|
|
|
- if dist_p <= self.SCOPE:
|
|
|
|
|
- ship.fire(*p)
|
|
|
|
|
- return
|
|
|
|
|
-
|
|
|
|
|
- raise DidNotAct()
|
|
|
|
|
|
|
|
|
|
|
|
+ else:
|
|
|
|
|
+ raise DidNotAct()
|
|
|
|
|
+
|
|
|
def can_mine(self):
|
|
def can_mine(self):
|
|
|
return self.last_mining is None or (current_turn - self.last_mining) >= 4
|
|
return self.last_mining is None or (current_turn - self.last_mining) >= 4
|
|
|
|
|
|
|
@@ -781,9 +839,6 @@ while True:
|
|
|
log(f"Cannonballs: {grid.cannonballs}")
|
|
log(f"Cannonballs: {grid.cannonballs}")
|
|
|
|
|
|
|
|
|
|
|
|
|
- ### Evaluate
|
|
|
|
|
- grid.update_moving_costs()
|
|
|
|
|
-
|
|
|
|
|
### Acquire
|
|
### Acquire
|
|
|
log("# Acquiring")
|
|
log("# Acquiring")
|
|
|
|
|
|