See competition on link.
See some games my bot won by colliding (one, two), starving (one) and blocking (one, two, three). It got to 7th place at the overall leaderboard: link.
See my source code on github (source, commits).
data = bottle.request.json
board_data = data['board']
self.height = board_data['height']
self.width = board_data['width']
self.board = [
[0 for _ in range(self.width)]
for _ in range(self.height)]
snakes = board_data['snakes']
for snake in snakes:
for part in snake['body'][:-1]:
self.board[part['y']][part['x']] = 1
if exclude_heads_of_other_snakes:
if (snake['id'] != self.id
and len(snake['body']) >= len(body)):
head = snake['body'][0]
for (_, nx, ny) in self.adjacent(
head['x'], head['y']):
self.board[ny][nx] = 1
DIRECTIONS = ['up', 'down', 'left', 'right']
DELTAS = {
'up' : { 'x': 0, 'y': -1, },
'down' : { 'x': 0, 'y': +1, },
'left' : { 'x': -1, 'y': 0, },
'right': { 'x': +1, 'y': 0, },
}
def adjacent(self, x, y):
res = []
for direction in DIRECTIONS:
delta = DELTAS[direction]
nx = x + delta['x']
ny = y + delta['y']
if (nx >= 0 and nx < self.width and
ny >= 0 and ny < self.height and
self.board[ny][nx] == 0):
res.append((direction, nx, ny))
return res
NO_DISTANCE = -1
NO_MOVE = '?'
def distances(self, x, y):
res = [
[NO_DISTANCE for _ in range(self.width)]
for _ in range(self.height)]
move = [
[NO_MOVE for _ in range(self.width)]
for _ in range(self.height)]
move_debug = [
[NO_MOVE for _ in range(self.width)]
for _ in range(self.height)]
# Flood fill.
res[y][x] = 0
deque = collections.deque()
for (m, nx, ny) in self.adjacent(x, y):
deque.append((nx, ny, 1, m))
while deque:
(x, y, d, m) = deque.popleft()
if res[y][x] != NO_DISTANCE:
continue
res[y][x] = d
move[y][x] = m
move_debug[y][x] = m[0]
for (_, nx, ny) in self.adjacent(x, y):
if res[ny][nx] == NO_DISTANCE:
deque.append((nx, ny, d + 1, m))
def move_to_pos(self, x, y, moves):
res = moves[y][x]
print (
'move_to_pos', 'x', x, 'y', y,
'res', res)
return res
def move_to_max(self, distances, moves):
maxdist = -1
res = NO_MOVE
for x in range(self.width):
for y in range(self.height):
if distances[y][x] > maxdist:
maxdist = distances[y][x]
res = moves[y][x]
print (
'move_to_max', 'maxdist', maxdist,
'res', res)
return res
def move_to_food(
self, distances, moves, tail_distances):
res = NO_MOVE
mindist = sys.maxint
for food in self.food:
x = food['x']
y = food['y']
dist = distances[y][x]
if (dist != NO_DISTANCE and
dist < mindist and (
(tail_distances[y][x] != NO_DISTANCE
and tail_distances[y][x] >= 2)
or self.health <= 25)):
mindist = dist
res = moves[y][x]
print (
'move_to_food', 'mindist', mindist,
'res', res)
return res
def run(data, exclude_heads_of_other_snakes):
game = Game(
data, exclude_heads_of_other_snakes)
distances, moves, moves_debug = (
game.distances(
game.head['x'], game.head['y']))
tail_distances, _, _ = game.distances(
game.tail['x'], game.tail['y'])
tails = (
[(_, game.tail['x'], game.tail['y'])] +
game.adjacent(
game.tail['x'], game.tail['y']))
for (_, x, y) in tails:
direction = game.move_to_pos(x, y, moves)
if direction != NO_MOVE:
break
if direction == NO_MOVE:
direction = game.move_to_max(
distances, moves)
if game.health <= get_min_health(
game.name):
food_direction = game.move_to_food(
distances, moves, tail_distances)
if food_direction != NO_MOVE:
direction = food_direction
return direction
@bottle.post('/move')
def move():
data = bottle.request.json
direction = run(
data, exclude_heads_of_other_snakes=True)
if direction == NO_MOVE:
direction = run(
data,
exclude_heads_of_other_snakes=False)
return move_response(direction)