Student Guide β Game URL: https://snake.abc123xyz.info
You build a small HTTP server (your bot). Every 500 ms the game calls your bot with the current game state and asks: "which direction?". Your bot replies. That's the whole job.
Game server ββPOST /moveβββΆ YOUR BOT
βββ { direction } ββ
The server handles walls, self-collisions, scoring, and rendering. You only need to decide strategy.
The game sends a POST /move with this JSON body every tick:
{
"snake": {
"body": [{"x": 5, "y": 9}, {"x": 4, "y": 9}],
"dir": "RIGHT",
"alive": true,
"score": 2
},
"opponent": {
"alive": true,
"head": {"x": 15, "y": 9},
"body": [{"x": 15, "y": 9}, {"x": 16, "y": 9}]
},
"foods": [{"x": 10, "y": 5}, {"x": 3, "y": 14}],
"grid": {"width": 20, "height": 20},
"tick": 42,
"safe_moves": ["UP", "RIGHT", "DOWN"],
"rules": {"warMode": false}
}
| Field | Meaning |
|---|---|
snake.body[0] | Your head position (x, y) |
safe_moves | Moves that won't immediately kill you β start here |
foods | All food positions on the board |
opponent.head | Opponent head position |
opponent.body | Full opponent body (in full-info mode) |
rules.warMode | If true, hitting opponent body cuts and scores |
{"direction": "RIGHT"}
One of: "UP" "DOWN" "LEFT" "RIGHT"
Pick any language. Copy, run, then improve.
from flask import Flask, request, jsonify
import random
app = Flask(__name__)
@app.route('/move', methods=['POST'])
def move():
data = request.json
safe = data.get('safe_moves', ['UP'])
# ββ your strategy here ββ
direction = random.choice(safe)
return jsonify({'direction': direction})
if __name__ == '__main__':
app.run(port=8000)
pip install flask
python bot.py
const express = require('express')
const app = express()
app.use(express.json())
app.post('/move', (req, res) => {
const safe = req.body.safe_moves || ['UP']
// ββ your strategy here ββ
const direction = safe[Math.floor(Math.random() * safe.length)]
res.json({ direction })
})
app.listen(8000, () => console.log('Bot ready on :8000'))
npm init -y && npm install express
node bot.js
package main
import (
"encoding/json"
"math/rand"
"net/http"
)
type Payload struct {
SafeMoves []string `json:"safe_moves"`
}
func main() {
http.HandleFunc("/move", func(w http.ResponseWriter, r *http.Request) {
var p Payload
json.NewDecoder(r.Body).Decode(&p)
safe := p.SafeMoves
if len(safe) == 0 { safe = []string{"UP"} }
json.NewEncoder(w).Encode(map[string]string{
"direction": safe[rand.Intn(len(safe))],
})
})
http.ListenAndServe(":8000", nil)
}
go run main.go
Run this curl command β your bot should reply with a direction:
curl -X POST http://localhost:8000/move \
-H "Content-Type: application/json" \
-d '{
"snake": {"body":[{"x":5,"y":9},{"x":4,"y":9}],"dir":"RIGHT","alive":true,"score":0},
"opponent": {"alive":true,"head":{"x":15,"y":9}},
"foods": [{"x":10,"y":5}],
"grid": {"width":20,"height":20},
"tick": 1,
"safe_moves": ["UP","RIGHT","DOWN"],
"rules": {"warMode":false}
}'
Expected: {"direction":"RIGHT"}
The game server needs to reach your bot over the internet. No domain needed β pick the option that fits you:
Everything in the browser. No installs. No account setup beyond signing up.
https://botname.username.repl.cohttps://botname.username.repl.co/moveRun your bot locally and expose it instantly. Requires Node.js installed.
# Terminal 1 β start your bot
python bot.py # or: node bot.js
# Terminal 2 β expose it (no account needed)
npx localtunnel --port 8000
You get a URL like https://loud-mango-42.loca.lt β use that as your bot URL with /move appended.
More reliable than localtunnel. One command, no sign-up.
# Terminal 1 β start your bot
python bot.py # or: node bot.js
# Terminal 2 β expose it
npx cloudflared tunnel --url http://localhost:8000
You get a URL like https://abc-def-123.trycloudflare.com β append /move as your bot URL.
Free account required. Stable URLs on paid plan, random URL on free.
ngrok http 8000
# Copy the https://β¦.ngrok-free.app URL β add /move
| Option | Account needed? | Runs where? | Best for |
|---|---|---|---|
| β Replit | Free signup | Cloud (browser) | Beginners, no local setup |
| β‘ localtunnel | None | Your machine | Quickest local tunnel |
| π Cloudflare Tunnel | None | Your machine | Reliable local tunnel |
| ngrok | Free signup | Your machine | Familiar tool |
| Level | Strategy |
|---|---|
| π’ Beginner | Pick a random safe_move β you'll never die from walls or yourself |
| π‘ Intermediate | Always move toward the nearest food |
| π Advanced | Flood-fill: avoid moves that trap you in small spaces |
| π΄ Expert | Race for food before opponent, cut opponent body in War mode |
safe_moves already removes wall and self-collision moves. You don't need to check those β just focus on which safe move is strategically best.@app.route('/move', methods=['POST'])
def move():
data = request.json
head = data['snake']['body'][0]
safe = data.get('safe_moves', ['UP'])
foods = data.get('foods', [])
if not foods:
return jsonify({'direction': safe[0]})
# nearest food by Manhattan distance
target = min(foods, key=lambda f: abs(f['x']-head['x']) + abs(f['y']-head['y']))
vectors = {'UP':(0,-1), 'DOWN':(0,1), 'LEFT':(-1,0), 'RIGHT':(1,0)}
best = min(safe, key=lambda d: (
abs((head['x'] + vectors[d][0]) - target['x']) +
abs((head['y'] + vectors[d][1]) - target['y'])
))
return jsonify({'direction': best})
When the match creator enables War Mode:
| Item | Value |
|---|---|
| Game URL | https://snake.abc123xyz.info |
| Bot endpoint | POST /move on your server |
| Response | {"direction": "UP|DOWN|LEFT|RIGHT"} |
| Timeout per tick | 5 seconds |
| Default grid | 20Γ20 |
| Default tick speed | 500 ms |
Good luck! π