11 de septiembre de 2026 · En Daily Challenge
El cliente nunca manda un número
Un juego con tabla de puntuaciones en el navegador es un formulario abierto a quien sepa abrir la consola. La salida no fue ofuscar: fue dejar de creerle al cliente.
Daily Challenge publica un reto distinto cada día y un top 10 a medianoche. Si el navegador mandara «hice 24 680 puntos», cualquiera cambiaría ese número en dos segundos, y una tabla que se puede falsear no vale nada: el juego entero deja de tener sentido.
Lo que sube el navegador no es el puntaje, es el registro de teclas: qué se pulsó y en qué tick. El servidor vuelve a correr la partida con ese registro y calcula el puntaje él mismo. Para que eso funcione, la simulación tiene que ser determinista: física en enteros, nada de números al azar sin semilla, y el mismo código corriendo en los dos lados.
// public/arcade/verify.js — el mismo módulo que usa el navegador
export function verify(juego, mapa, semilla, log) {
const estado = crear(juego, mapa, semilla); // misma semilla, mismo mundo
for (const tick of log) avanzar(estado, tick);
return estado.puntaje; // esto es lo que vale
}El determinismo no se cuida solo, así que hay una prueba que lo vigila: un bot aleatorio juega los veinticuatro minijuegos y comprueba que reproducir el registro da exactamente el mismo puntaje. Si alguien mete un `Math.random()` suelto o una física con decimales, la prueba se cae antes de llegar a producción.
La misma idea sirvió para dos cosas más. La cámara fantasma —ver la partida de otro mientras esperas— no manda vídeo: manda los mismos inputs por un canal en tiempo real y cada espectador re-simula. Y el versus se juega en lockstep: el anfitrión reparte los inputs de todos cada seis ticks, así que nadie diverge, y al final el servidor re-simula la partida conjunta. Un solo mecanismo bien hecho pagó tres funciones.