Translate this page

Battlesnake Bot Competition 🔗

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).

Code Walk 🔗

Board Creation 🔗

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

Adjacent Squares 🔗

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

Distance And Movement To All Destinations 🔗

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))

Move To Particular Position 🔗

def move_to_pos(self, x, y, moves):
  res = moves[y][x]
  print (
    'move_to_pos', 'x', x, 'y', y,
    'res', res)
  return res

Move To Position With The Most Space 🔗

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

Move To Closest Food That Has A Path To Tail 🔗

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

Move to Food, Tail or Max 🔗

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)

Subscribe to my mailing list and get a free email course

* indicates required

Interests


Translate this page

Updated on 2019 Mar 9.

DISCLAIMER: This is not professional advice. The ideas and opinions presented here are my own, not necessarily those of my employer.