Skip to content

battle-snake/battle_snake

 
 

Repository files navigation

CircleCI

Example Game Animation

Table of Contents

Competitors' Guide

Game Rules

Avoid Walls

If a snake leaves the last tile of the board, they will die.

Eat Food

Eating a food pellet will make snakes one segment longer. Snakes grow out of their tail: new tail segment will appear in the same square that the tail was in the previous turn.

Eating a food pellet will restore snakes' health-points to 100.

The amount of food can vary from game to game, but within the same game it will always stay the same. As soon as a piece of food is eaten, it will respawn at a random, unoccupied location on the next turn.

Don't Starve

Every turn snakes will loose one health-point. Health-points serve like the snake's hunger bar, and if it reaches zero, the snake will starve and die. Eating food will restore snake's health to one-hundred points on the next turn.

Don't Collide with Snakes' Tails

If a snake collides with itself or any other snakes' tails, it dies.

Head on Collisions

Head-to-head collisions follow different rules than the previously mentioned tail collisions.

In head-on collisions, the longer snake will survive.

But if both snakes are the same size, they both die. Note that in the below scenario, the food remains (collisions are resolved before food is eaten).

Testing Your Snake

If you have a game server running locally you can visit /test, plug your snake's URL in and a number of tests will be run against your server, checking if it follows all the basic game rules.

API Webhooks

All interactions with the game are implemented as HTTP POST webhooks. Once the game has begun your server will receive a request to your /start endpoint, and then on each turn a request to the /move endpoint.

POST /start

URL /start
Method POST
request body JSON StartRequest object
expected response JSON StartResponse object

The StartRequest Object

interface StartRequest {
  game_id: string;
}

The StartResponse Object

interface StartResponse {
  /**
   * What color your snake should be on the board.
   * Accepts any valid CSS color.
   * https://developer.mozilla.org/en-US/docs/Web/CSS/color
   */
  color: string;
  name: string;
  /**
   * URL of the image to display as your avatar.
   */
  head_url: string;
  taunt: string;
  head_type: HeadType;
  tail_type: TailType;
  secondary_color: string;
}

The HeadType Type

String referring to what head image should be used for your snake.

Renders one of the matching images in this directory.

type HeadType = 
  | 'bendr'
  | 'dead'
  | 'fang'
  | 'pixel'
  | 'regular'
  | 'safe'
  | 'sand-worm'
  | 'shades'
  | 'smile'
  | 'tongue';

The TailType Type

String referring to what tail image should be used for your snake.

Renders one of the matching images in this directory.

type TailType = 
  | 'block-bum'
  | 'curled'
  | 'fat-rattle'
  | 'freckled'
  | 'pixel'
  | 'regular'
  | 'round-bum'
  | 'skinny'
  | 'small-rattle'

Example Request

{
  "game_id": "b1dadee8-a112-4e0e-afa2-2845cd1f21aa"
}

Example Response

{
    "color": "#FF0000",
    "secondary_color": "#00FF00",
    "head_url": "http://placecage.com/c/100/100",
    "name": "Cage Snake",
    "taunt": "OH GOD NOT THE BEES",
    "head_type": "pixel",
    "tail_type": "pixel"
}

POST /move

A request including all the current game information will be issued to this endpoint on each turn. The game server expects a JSON response within 200ms.

URL /move
Method POST
request body JSON World object
expected response JSON Response object

The MoveResponse Object

interface MoveResponse {
  move: Move;
}

The Move type

type Move = 'up' | 'down' | 'left' | 'right';

The World object

interface World {
  object: 'world';
  id: number;
  you: Snake;
  snakes: List<Snake>;
  height: number;
  width: number;
  turn: number;
  food: List<Point>;
}

The Snake object

interface Snake {
  body: List<Point>;
  health: number;
  id: string;
  length: number;
  name: string;
  object: 'snake';
  taunt: string;
}

The List object

interface List<T> {
  object: 'list';
  data: T[];
}

The Point object

interface Point {
  object: 'point';
  x: number;
  y: number;
}

Example Request

{
  "food": {
    "data": [
      {
        "object": "point",
        "x": 0,
        "y": 9
      }
    ],
    "object": "list"
  },
  "height": 20,
  "id": 1,
  "object": "world",
  "snakes": {
    "data": [
      {
        "body": {
          "data": [
            {
              "object": "point",
              "x": 13,
              "y": 19
            },
            {
              "object": "point",
              "x": 13,
              "y": 19
            },
            {
              "object": "point",
              "x": 13,
              "y": 19
            }
          ],
          "object": "list"
        },
        "health": 100,
        "id": "58a0142f-4cd7-4d35-9b17-815ec8ff8e70",
        "length": 3,
        "name": "Sonic Snake",
        "object": "snake",
        "taunt": "Gotta go fast"
      },
      {
        "body": {
          "data": [
            {
              "object": "point",
              "x": 8,
              "y": 15
            },
            {
              "object": "point",
              "x": 8,
              "y": 15
            },
            {
              "object": "point",
              "x": 8,
              "y": 15
            }
          ],
          "object": "list"
        },
        "health": 100,
        "id": "48ca23a2-dde8-4d0f-b03a-61cc9780427e",
        "length": 3,
        "name": "Typescript Snake",
        "object": "snake",
        "taunt": ""
      }
    ],
    "object": "list"
  },
  "turn": 0,
  "width": 20,
  "you": {
    "body": {
      "data": [
        {
          "object": "point",
          "x": 8,
          "y": 15
        },
        {
          "object": "point",
          "x": 8,
          "y": 15
        },
        {
          "object": "point",
          "x": 8,
          "y": 15
        }
      ],
      "object": "list"
    },
    "health": 100,
    "id": "48ca23a2-dde8-4d0f-b03a-61cc9780427e",
    "length": 3,
    "name": "Typescript Snake",
    "object": "snake",
    "taunt": ""
  }
}

Example Response

{
  "move": "up"
}

Development

Running with Docker

docker pull battlesnake/battle_snake
docker run -it -p 3000:3000 battlesnake/battle_snake

You should be able to view the game server at http://localhost:3000.

Networking issues

If you are running your snake on localhost, you won't be able to reference it as localhost because the container runs on its own network. If you're running Docker For Mac you can reference localhost:5678 with http://docker.for.mac.localhost:5678/, otherwise use your full ip address on your network to reference your localhost (192.168.1.xxx or whatever your subnet is configured for, use ifconfig to find out).

Compiling From Source

Dependencies

MacOSX

brew update && brew install erlang elixir nodejs yarn

Linux

I suggest installing Erlang through evm and Elixir through kiex.

git clone git@github.com:battle-snake/battle_snake.git`
cd battle_snake
yarn install
mix do local.hex --force, local.rebar
mix do deps.get, deps.compile
mix do ecto.create, ecto.migrate
mix phx.server

Testing

End to End Tests

yarn cypress:open

Unit Tests

mix test

Spotted an inaccuracy in the document, think they suck, or have a suggestion on how to make it better? Open an issue, or even better submit a PR!

License

Copyright 2016-2018 Dylan Kendal

Licensed under the GNU Affero General Public License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

https://www.gnu.org/licenses/agpl-3.0.txt

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Packages

No packages published

Languages

  • Elixir 69.5%
  • Elm 18.4%
  • TypeScript 7.5%
  • HTML 2.0%
  • JavaScript 1.8%
  • Shell 0.4%
  • Other 0.4%