Caputchin
Desarrollo de juegos del marketplace

El engine-kit (opcional)

Esta página es opcional. Todo aquí es una forma conveniente de producir un run conforme; puedes ignorar el kit por completo y publicar un run pelado que escribiste a mano. Echa mano de @caputchin/engine-kit cuando prefieras escribir lógica de juego ordinaria y que el determinismo, el bucle de repetición, y la codificación de trazas se gestionen por ti.

El kit re-exporta toda la superficie del contrato de repetición, así que los usuarios del kit tienen un único sitio de import.

npm install @caputchin/engine-kit

La idea: escribe un reducer, obtén un run

El movimiento central del kit es dejarte expresar tu juego como un reducer puro: una función que toma el estado actual y la entrada de un tick y devuelve el siguiente estado. A partir de ese reducer más primitivas deterministas, el adaptador toRun del kit produce un run(seed, config, trace) que se conforma al contrato por construcción.

import { defineEngine, toRun, cap } from "@caputchin/engine-kit";

const engine = defineEngine({
  setup(seed) {
    const rng = cap.rng(seed);          // deterministic, seeded RNG
    return { score: 0, targets: spawn(rng), rng };
  },
  tick(state, input) {
    // pure: same (state, input) always yields the same next state
    return applyInput(state, input);
  },
  result(state) {
    return { passed: state.score >= 3, score: state.score, durationMs: state.elapsed };
  },
});

export const run = toRun(engine);       // a conforming RunFn

Primitivas deterministas

El kit te da las dos cosas que más a menudo rompen el determinismo entre runtimes, ambas sembradas y reproducibles:

  • cap.rng(seed) (y cap.rngFromState) - un PRNG sembrable. Úsalo para cada elección aleatoria en vez de Math.random().
  • cap.math - transcendentales deterministas (sin, cos, ...) que concuerdan entre runtimes, en vez de las del Math de la plataforma que pueden no hacerlo.

Shims opcionales

  • applyShim() - neutraliza los globales no deterministas (el reloj de pared, Math.random) para que una llamada accidental falle ruidosamente en desarrollo en vez de divergir en silencio en la repetición.
  • applyDomShim() - un DOM headless mínimo para el camino de framework, para que un reducer que toca una pequeña superficie de DOM aún se repita en el isolate sin DOM.

Córrelo en local antes de publicar

El harness replay del kit corre una traza a través de tu engine de la misma forma que lo hará el servidor, y selfCheck corre una batería de casos y reporta cualquier no-determinismo antes de que publiques:

import { selfCheck } from "@caputchin/engine-kit";

const report = selfCheck(engine, { cases: myCases });
if (!report.ok) console.error(report.violations);

Un selfCheck local limpio es el mejor predictor de que la autocomprobación de publicación del marketplace pasará (es el mismo estándar de determinismo). El kit también incluye una CLI para correr esto desde scripts de package.json o CI.

Codificación de trazas

encodeTrace / decodeTrace te dan un formato de traza compacto y versionado para que el flujo de entrada que tu juego en vivo emite sea exactamente lo que tu run decodifica en la repetición. Usarlos en ambos lados mantiene los dos al unísono.

Cuándo saltarse el kit

Sáltatelo cuando ya tengas lógica determinista (una simulación de coma fija, un módulo WASM compilado para floats de la spec) o cuando tu juego sea lo bastante simple como para que escribir run a mano sea trivial. La plataforma nunca sabe ni le importa si el kit produjo tu run; solo carga y repite el contrato.

Véase también

En esta página