Portal de Desarrolladores AJE v1
Aprende a construir, certificar y conectar tu motor de juego HTTP a la plataforma AleFraJav Engine Arena.
Un minuto: de cero a competir
Sin sonido — se explica con texto en pantalla. También disponible en inglés.
1. Especificaciones del Protocolo AJE v1
Tu motor debe exponer un endpoint HTTP POST en la ruta de tu elección (ejemplo: /aje/move). La Arena le enviará la posición del juego en notación PDN / FEN y el tiempo restante, y tu motor debe responder con un objeto JSON. El plazo de cada petición es el reloj que te queda más 3 segundos de margen de red.
Las cadenas de capturas se mandan enteras, con todas sus casillas: 9x18x27, no 9x27. También puedes mandar un salto por vez y se te volverá a preguntar. Es lo que más se confunde al empezar.
Petición POST recibida por tu motor (AjeMoveRequest):
{
"protocolo": 1,
"juego": "checkers-8x8",
"reglas": "checkers-8x8@1.0.0",
"posicion": "B:W21,22,23,24,25,26,27,28,29,30,31,32:B1,2,3,4,5,6,7,8,9,10,11,12",
"msRestantes": 60000,
"msIncremento": 0,
"movimientoNumero": 1,
"partidaId": "match-1700000000"
}Respuesta devuelta por tu motor (AjeMoveResponse):
{
"jugada": "11-15",
"msPensados": 45,
"info": "Evaluación: +0.20 depth=6"
}2. De cero a competir, en cuatro pasos
Las plantillas de abajo no son un esqueleto: son motores que compiten de verdad. Traen el protocolo resuelto y un generador de jugadas legales completo —captura obligatoria, cadenas, coronación— y eligen al azar entre las legales. Ganan poco, pero juegan desde el primer minuto. No necesitan ninguna dependencia: solo Python 3 o Node.
1. Descarga una plantilla
Y si prefieres empezar por un motor que ya piensa en vez de uno que elige al azar, descarga este: busca con minimax y poda alfa-beta. Está partido para que solo tengas que tocar dos funciones —
evaluar, que dice cuánto vale una posición, ybuscar, que dice cuánto se mira hacia adelante.Va deliberadamente frenado a dos jugadas de profundidad. Medido en series de cuatro partidas contra los motores de la casa: pierde con el Veterano, con Imperium y con Bastión, empata con el Maestro, y solo le gana al Aprendiz. Subir esa profundidad es la primera mejora que harás, y se nota enseguida — es tu punto de partida, no tu rival.
🧠 motor_ejemplo.py — minimax con alfa-beta2. Arráncala
python3 bot_template.py # escucha en el puerto 5000 node bot_template.js # escucha en el puerto 5001
3. Compruébala en tu máquina, antes de registrar nada
curl -X POST http://127.0.0.1:5000/aje/move \ -H 'Content-Type: application/json' \ -d '{"protocolo":1,"juego":"checkers-8x8", "posicion":"B:W21,22,23,24,25,26,27,28,29,30,31,32:B1,2,3,4,5,6,7,8,9,10,11,12", "msRestantes":60000,"msIncremento":0,"movimientoNumero":1,"partidaId":"prueba"}'Debe contestar algo como
{"jugada":"11-15","msPensados":0,…}. Esa posición es la inicial, y sus únicas jugadas legales son9-13 · 9-14 · 10-14 · 10-15 · 11-15 · 11-16 · 12-16.4. Hazla alcanzable desde internet y regístrala
La Arena llama a tu servidor, así que necesita una URL pública. Si tu motor corre en tu ordenador, lo más rápido es un túnel —
cloudflared,ngrokossh -R— y registrar la URL que te dé, terminada en/aje/move.Al registrarlo se le pasa una certificación de cinco comprobaciones. Las plantillas las pasan las cinco: si alguna falla, es por lo que hayas cambiado tú, y el informe te dice cuál.
➕ Registrar mi motor
Lo que más se confunde al empezar. Una cadena de capturas se manda entera y con todas sus casillas: 9x18x27, no 9x27 — con dos piezas comibles a la vez, el destino final no basta para saber por dónde fue la pieza. También vale mandar un salto por vez y se te vuelve a preguntar. Y ojo con dos reglas que sorprenden: una pieza normal no captura hacia atrás, y coronar termina el turnoaunque quedara algo por comer.
La forma de los mensajes, en corto
Estos dos recortes enseñan solo la forma de la respuesta. Devuelven una jugada fija, que es legal en la posición inicial y ilegal en cuanto avanza la partida: para competir, usa las plantillas de arriba, que calculan las jugadas legales de verdad.
🐍 Plantilla en Python (Flask)
# ejemplo-motor.py — Servidor AJE v1 en Python (Flask)
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/aje/move', methods=['POST'])
def handle_move():
data = request.get_json()
posicion = data.get('posicion') # FEN / PDN
# Lógica del motor (ej. selección de jugada legal)
jugada_elegida = "11-15"
return jsonify({
"jugada": jugada_elegida,
"msPensados": 45,
"info": "Motor Python AJE v1 v1.0"
})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
⚡ Plantilla en TypeScript / Node.js
// ejemplo-motor.ts — Servidor AJE v1 en Node.js / Express
import express from 'express';
const app = express();
app.use(express.json());
app.post('/aje/move', (req, res) => {
const { posicion, msRestantes } = req.body;
// Lógica del motor
const jugada = "11-15";
res.json({
jugada,
msPensados: 30,
info: "Motor Node.js AJE v1"
});
});
app.listen(4000, () => console.log('Motor AJE escuchando en puerto 4000'));
3. Una partida real, paso a paso
Esto no es un ejemplo inventado: son cuatro intercambios copiados de una partida de verdad entre motor_ejemplo.py y la plantilla que juega al azar. Se ven las tres situaciones que decide tu motor.
Jugada 1 — la salida
La Arena manda la posición inicial. Le tocan las negras.
→ POST /aje/move
{ "protocolo": 1, "juego": "checkers-8x8", "reglas": "checkers-8x8@1.0.0",
"posicion": "B:W21,22,23,24,25,26,27,28,29,30,31,32:B1,2,3,4,5,6,7,8,9,10,11,12",
"msRestantes": 20000, "msIncremento": 0, "movimientoNumero": 1, "partidaId": "…" }
← 200 OK
{ "jugada": "9-14", "msPensados": 600, "info": "profundidad 6" }Pensó 600 ms —el 3 % de su reloj— y miró 6 jugadas hacia adelante. Lo que descuenta el reloj es tu msPensados, no lo que tardó la petición: así la distancia a la que esté tu servidor no decide campeonatos.
Jugada 5 — capturar es obligatorio
Las blancas se pusieron en 17 y ahora la pieza negra de 14 tiene que comer. No hay elección.
→ "posicion": "B:W17,20,22,23,25,26,27,28,29,30,31,32:B1,2,3,4,5,7,8,9,10,11,12,14"
← { "jugada": "14x21", "msPensados": 0, "info": "profundidad 0" }Contestó en 0 ms y sin buscar nada: cuando solo hay una jugada legal, pensarla es tirar reloj. Si tu motor devuelve aquí cualquier otra cosa, pierde la partida — una jugada ilegal no se reintenta.
Jugada 31 — la cadena, entera
La pieza de 12 come dos veces seguidas: salta a 19 y sigue hasta 26.
→ "posicion": "B:W16,23,24,28,32:B1,2,3,4,10,12,14,20,K21,22,25"
← { "jugada": "12x19x26", "msPensados": 429, "info": "profundidad 7" }Con la casilla intermedia. 12x26 se rechaza: con dos piezas comibles a la vez, el destino final no dice por dónde fue la pieza, y el árbitro no adivina. También vale mandar solo 12x19 y se te vuelve a preguntar, porque el turno no ha cambiado.
La K21 de esa posición es una dama coronada. Fíjate en que coronar termina el turno: aunque desde la casilla de coronación hubiera otra captura, ahí se para.
Cómo terminó
Sin piezas blancas, en 41 jugadas — comiéndose todas las piezas, no por incomparecencia ni por reloj. La diferencia entre los dos son las dos funciones quemotor_ejemplo.py te invita a cambiar: evaluar ybuscar.
4. API Pública v1 para Investigadores
Ofrecemos endpoints JSON públicos para integrar clasificaciones y datos de motores en investigaciones universitarias:
Devuelve la tabla de clasificación ordenada por ELO con hardware declarado.
Devuelve el catálogo general de motores registrados y metadatos.