- Add bitboard-accelerated Prism and versioned Supreme snake implementations. - Add database-backed move benchmarks and focused strategy tests. - Normalize gameplay storage while preserving replay compatibility. - Add deterministic game quality scoring and replay retention tiers. - Add backup-first SQLite cleanup, verification, and replacement tooling. - Add safe compact-plus-delta database merging with conflict detection. - Extend SQLite and PostgreSQL schemas for replay and quality metadata. - Add PostgreSQL development service and pytest import configuration. - Update gameplay documentation and the quart_common submodule revision.
Battlesnake Python Starter Project
An official Battlesnake template written in Python. Get started at play.battlesnake.com.
This project is a great starting point for anyone wanting to program their first Battlesnake in Python. It can be run locally or easily deployed to a cloud provider of your choosing. See the Battlesnake API Docs for more detail.
Technologies Used
This project uses Python 3 and Flask. It also comes with an optional Dockerfile to help with deployment.
Run Your Battlesnake
Install dependencies using pip
pip install -r requirements.txt
Start your Battlesnake
python main.py
You should see the following output once it is running
Running your Battlesnake at http://0.0.0.0:8000
* Serving Flask app 'My Battlesnake'
* Debug mode: off
Open localhost:8000 in your browser and you should see
{"apiversion":"1","author":"","color":"#888888","head":"default","tail":"default"}
Play a Game Locally
Install the Battlesnake CLI
- You can download compiled binaries here
- or install as a go package (requires Go 1.18 or higher)
Command to run a local game
battlesnake play -W 11 -H 11 --name 'Python Starter Project' --url http://localhost:8000 -g solo --browser
Next Steps
Continue with the Battlesnake Quickstart Guide to customize and improve your Battlesnake's behavior.
Included Competitive Snake
This repo now includes snakes/BestBattleSnake.py, a stronger default snake that combines:
- collision and head-to-head risk checks
- flood-fill space evaluation to avoid traps
- food routing that gets more aggressive as health drops
- tail access checks for better long-term survival
Run it explicitly with:
SNAKE=BestBattleSnake python main.py
Optional duel tuning (when only 2 snakes are alive):
BATTLE_SNAKE_DUEL_STYLE=balanced python main.py
Allowed values: safe, balanced, aggressive.
PrismBattleSnake_GPT_5_6_Sol
PrismBattleSnake_GPT_5_6_Sol is a separate snake that keeps Apex's strategy while
accelerating hot spatial operations with a Python-integer bitboard engine. Its
filename, class, and registry key include the model name, while its public
Battlesnake API name remains PrismBattleSnake.
Run it with:
SNAKE=PrismBattleSnake_GPT_5_6_Sol python main.py
Benchmark Apex and Prism against sampled positions from a gameplay database:
python scripts/benchmark_snakes_from_db.py \
--database /path/to/gameplay.sqlite3 \
--samples 100
The benchmark opens SQLite read-only and reports mean, median, p95, and maximum
move latency. Increase --samples for a broader but slower comparison.
Compact gameplay database
New gameplay turns use normalized storage: the turn row stores food, hazards,
move, and thinking data once; snake identity is stored once per game in
game_snakes; and changing snake state/body data lives in snake_turns. Replay
loading rebuilds the normal Battlesnake board payload.
Create and verify a separate compact copy of an existing SQLite database. By
default, replay-heavy rows are retained for games rated medium or high by
structural completeness, valid moves, thinking coverage, game length, move
diversity, opponent data, and terminal outcome. All game-result rows remain
stored, so historical win/loss rates stay persistent when low-quality replay
data is removed.
python scripts/migrate_gameplay_database.py \
--source /path/to/gameplay.sqlite3 \
--destination /path/to/gameplay.compact.sqlite3 \
--minimum-quality medium
After reviewing the compact copy, --replace renames the original to a
timestamped backup and puts the verified compact database at the original path.
Stop all writers before using it:
python scripts/migrate_gameplay_database.py \
--source /path/to/gameplay.sqlite3 \
--replace
The migration never modifies the source in place. It verifies row counts and
runs SQLite's integrity_check before any replacement.
Record new games while cleanup runs
Point the running server at a temporary delta database while the old database is being compacted. After stopping the writer and flushing the delta database, merge it into the cleaned copy:
python scripts/merge_gameplay_databases.py \
--base /path/to/gameplay.compact.sqlite3 \
--delta /path/to/gameplay.delta.sqlite3 \
--destination /path/to/gameplay.merged.sqlite3 \
--minimum-quality medium
The merger keeps all game results, quality-rates delta games, regenerates
numeric turn IDs, and verifies row counts, foreign keys, and database integrity.
Identical game IDs are skipped; conflicting duplicates abort the merge. After
reviewing the result, --replace-base backs up and replaces the cleaned base.
Stop the delta writer before the final merge and file swap.
Export Training Dataset
Game saves now include a dataset section with labeled move samples.
Export all stored samples to JSONL:
python -m server.DatasetExporter --input data --output data/dataset/good_moves.jsonl
Or with just:
just export-dataset
Curate a high-quality training subset (single file):
python -m server.DatasetCurator --input good_moves-2026-04-03.jsonl --output data/dataset/best_moves.jsonl
Curate from multiple JSONL sources (repeat --input):
python -m server.DatasetCurator \
--input good_moves-2026-04-03.jsonl \
--input good_moves-2026-04-04.jsonl \
--output data/dataset/best_moves.jsonl
Curate from folder or glob:
python -m server.DatasetCurator --input data/dataset --output data/dataset/best_moves.jsonl
python -m server.DatasetCurator --input "good_moves-*.jsonl" --output data/dataset/best_moves.jsonl
Append mode (keeps existing curated rows and deduplicates against them):
python -m server.DatasetCurator --input "good_moves-*.jsonl" --output data/dataset/best_moves.jsonl --append
Archive processed input files after curation:
python -m server.DatasetCurator --input "good_moves-*.jsonl" --output data/dataset/best_moves.jsonl --append --archive-input
python -m server.DatasetCurator --input "good_moves-*.jsonl" --output data/dataset/best_moves.jsonl --append --archive-input --archive-dir data/dataset/archive
Or with just:
just curate-dataset
just curate-dataset append=true
just curate-dataset append=true archive=true archive_dir=data/dataset/archive
Analyze dataset quality overall and by day (best game overall/day included):
python -m server.DatasetStats --input "good_moves-*.jsonl"
python -m server.DatasetStats --input data/dataset --output data/dataset/stats-report.json
The stats report now includes both:
best_game(survival/length focused)best_pressure_game(high-pressure quality focused: fewer safe options + strong survival)
Or with just:
just analyze-dataset
just analyze-dataset input=data/dataset output=data/dataset/stats-report.json
To store compact dataset-only records (JSONL) and skip full per-game JSON files:
STORE_DATASET_ONLY=true DATASET_JSONL_PATH=data/dataset/good_moves.jsonl python main.py
Optional compact storage tuning:
DATASET_ROTATE_DAILY=truecreates one JSONL file per day (default:true)DATASET_JSONL_MAX_MB=50rotates when file reaches max size in MB (default:50)DATASET_COMPRESS_ROTATED=truegzip-compresses rotated/old JSONL files (default:true)
Note: To play games on play.battlesnake.com you'll need to deploy your Battlesnake to a live web server OR use a port forwarding tool like ngrok to access your server locally.
