Documentation

Getting Started

Welcome to the Chess Bot Battle Platform! This guide will help you get started with registering and competing with your chess bot.

Platform Overview

  • Language: JavaScript only for fair competition
  • Time Control: 20 seconds per move
  • Matchmaking: Soft meritocracy with ELO ratings
  • Draw Tiebreaker: Shorter code wins

Quick Start

  1. Register your bot at Register Bot
  2. Wait for automated matchmaking (runs every 10 minutes)
  3. Check your bot's performance on the leaderboard
  4. Update your bot code to improve rankings

API Reference

Bot Management

POST /api/register

Register a new bot

{
  "botName": "My Bot",
  "authorName": "Your Name",
  "botCode": "function makeMove(board, timeRemaining, reportMove) { ... }"
}
GET /api/bots/:botId

Get bot details and statistics

PUT /api/bots/:botId/update

Update bot code (requires auth code)

Matches & Leaderboard

GET /api/leaderboard

Get ranked list of bots

GET /api/matches/recent

Get recent match results

AI Specs

GET /bot-specs.json

Machine-readable platform specifications

Bot Development

Required Function

Every bot must implement this exact function signature:

function makeMove(board, timeRemaining, reportMove) {
    // Your bot logic here
    // Must call reportMove() at least once
    reportMove('e2e4');
}

Chess.js Board API

  • board.moves() - Get all legal moves
  • board.moves({verbose: true}) - Get moves with details
  • board.fen() - Current position in FEN
  • board.turn() - 'w' or 'b'
  • board.move('e4') - Make a move
  • board.undo() - Undo last move
  • board.game_over() - Check if game ended

Code Constraints

  • 50-30,720 bytes (30KB max)
  • No async/await
  • No forbidden APIs (eval, fetch, etc.)
  • Call reportMove() with legal moves only

Move Reporting

You can call reportMove() multiple times - the last move before timeout is used:

function makeMove(board, timeRemaining, reportMove) {
    // Quick fallback
    reportMove(board.moves()[0]);

    // Better move after thinking
    if (timeRemaining > 15000) {
        // Calculate better move...
        reportMove('Nf3');
    }
}

Example Bots

Random Player

function makeMove(board, timeRemaining, reportMove) {
    const moves = board.moves();
    const randomMove = moves[Math.floor(Math.random() * moves.length)];
    reportMove(randomMove);
}

Greedy Capture

function makeMove(board, timeRemaining, reportMove) {
    const moves = board.moves({verbose: true});

    // Quick fallback
    reportMove(moves[0].san);

    // Prefer captures
    const captures = moves.filter(m => m.captured);
    if (captures.length > 0) {
        reportMove(captures[0].san);
    }
}

MiniMax (Basic)

function makeMove(board, timeRemaining, reportMove) {
    const PIECE_VALUES = {p:100, n:320, b:330, r:500, q:900, k:20000};

    function evaluate(b) {
        if (b.in_checkmate()) return b.turn() === 'w' ? -20000 : 20000;
        if (b.in_draw()) return 0;

        let score = 0;
        for (const square of b.SQUARES) {
            const piece = b.get(square);
            if (piece) {
                const value = PIECE_VALUES[piece.type] || 0;
                score += piece.color === 'w' ? value : -value;
            }
        }
        return b.turn() === 'w' ? score : -score;
    }

    function minimax(b, depth, alpha, beta) {
        if (depth === 0 || b.game_over()) return evaluate(b);

        let maxScore = -Infinity;
        for (const move of b.moves()) {
            b.move(move);
            const score = -minimax(b, depth - 1, -beta, -alpha);
            b.undo();

            maxScore = Math.max(maxScore, score);
            alpha = Math.max(alpha, score);
            if (beta <= alpha) break;
        }
        return maxScore;
    }

    const moves = board.moves();
    reportMove(moves[0]); // Fallback

    let bestMove = null;
    let bestScore = -Infinity;

    for (const move of moves) {
        board.move(move);
        const score = -minimax(board, 2, -Infinity, Infinity);
        board.undo();

        if (score > bestScore) {
            bestScore = score;
            bestMove = move;
        }
    }

    if (bestMove) reportMove(bestMove);
}