{"_id":"@arcade1v1/strategies","_rev":"5-311498953a73d25a925f9db7920026c6","name":"@arcade1v1/strategies","dist-tags":{"latest":"0.5.1"},"versions":{"0.2.0":{"name":"@arcade1v1/strategies","version":"0.2.0","keywords":["arcade1v1","ai-agents","strategies","deterministic","replay","headless"],"license":"MIT","_id":"@arcade1v1/strategies@0.2.0","maintainers":[{"name":"mediotanque","email":"agustincanosaf@gmail.com"}],"homepage":"https://arcade1v1.com/agents","bugs":{"url":"https://github.com/agustincf/Arcade1v1/issues"},"dist":{"shasum":"ecba467e0778172847feba0bb655cf6f9a527365","tarball":"https://registry.npmjs.org/@arcade1v1/strategies/-/strategies-0.2.0.tgz","fileCount":31,"integrity":"sha512-BMzvnSPzkA3ianbCNidlmOCrVungc82C821XobDmvkQ5fgoU/qSzHaObjOy/ouypxlQy4WHlnpFKEs97VSKbyQ==","signatures":[{"sig":"MEYCIQCcSQ1uvncCayPV/tMgwDdFw8uIeLBIiApR7KAsX+exxwIhAJx9Z8sVQrsBA22ZMrPpIZAQgYEIT/Y+h3e+q5zFrPso","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":63306},"type":"module","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"0b42a908274b4bc1bd4f18219327ee8c13b62855","_npmUser":{"name":"mediotanque","email":"agustincanosaf@gmail.com"},"repository":{"url":"git+https://github.com/agustincf/Arcade1v1.git","type":"git","directory":"packages/strategies"},"_npmVersion":"11.9.0","description":"Parameterized, deterministic strategies for every Arcade1v1 game. Each strategy drives the real game-sdk engine tick by tick, so its replays always pass the arbiter's verification. Powers the no-code agent builder.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","dependencies":{"@arcade1v1/game-sdk":"^0.2.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/strategies_0.2.0_1784317335105_0.21150230622978095","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@arcade1v1/strategies","version":"0.3.0","keywords":["arcade1v1","ai-agents","strategies","deterministic","replay","headless"],"license":"MIT","_id":"@arcade1v1/strategies@0.3.0","maintainers":[{"name":"mediotanque","email":"agustincanosaf@gmail.com"}],"homepage":"https://arcade1v1.com/agents","bugs":{"url":"https://github.com/agustincf/Arcade1v1/issues"},"dist":{"shasum":"075c1b915e0ec4147454e0a173a743ccd2ec9a5d","tarball":"https://registry.npmjs.org/@arcade1v1/strategies/-/strategies-0.3.0.tgz","fileCount":31,"integrity":"sha512-KYhIfRTW73ocyqdQvWogw5eTP9IJU+JK2p5efZ1sBcOEFKVzpO/OC8Bk4SRKzYy+2qEHN8/r2wgnq4bjBTW5CQ==","signatures":[{"sig":"MEUCIC++bfpUEcwBjdhikwPMXQ1ot1+XJIawi+MAFRNjMrPHAiEAjDg9oRTwUjYeKJhFTNdKCPVHGDDRwfcfUZxMEmpz9Os=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":63306},"type":"module","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"b3ea32fe8ed224be23f3b94814ee846d52820b2c","_npmUser":{"name":"mediotanque","email":"agustincanosaf@gmail.com"},"repository":{"url":"git+https://github.com/agustincf/Arcade1v1.git","type":"git","directory":"packages/strategies"},"_npmVersion":"11.9.0","description":"Parameterized, deterministic strategies for every Arcade1v1 game. Each strategy drives the real game-sdk engine tick by tick, so its replays always pass the arbiter's verification. Powers the no-code agent builder.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","dependencies":{"@arcade1v1/game-sdk":"^0.3.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/strategies_0.3.0_1789098814526_0.5196309848699814","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@arcade1v1/strategies","version":"0.4.0","keywords":["arcade1v1","ai-agents","strategies","deterministic","replay","headless"],"license":"MIT","_id":"@arcade1v1/strategies@0.4.0","maintainers":[{"name":"mediotanque","email":"agustincanosaf@gmail.com"}],"homepage":"https://arcade1v1.com/agents","bugs":{"url":"https://github.com/agustincf/Arcade1v1/issues"},"dist":{"shasum":"ca51d9fc2c6c7416edbf668424ed0d4b8193b661","tarball":"https://registry.npmjs.org/@arcade1v1/strategies/-/strategies-0.4.0.tgz","fileCount":31,"integrity":"sha512-tRvMNVdHM49VlPfzDVJIALKG865eOtmC+u6++nndt1TgFAEYZhlBsECyREDa1yFfUFPXEyQB9NdVbc+4cgjcTg==","signatures":[{"sig":"MEUCIQDcizvHm0TFvTWzGcRN9mlj2qvhB7vzEuhTut+9ZRUnCgIgSrCMVRlUBFihs4OzEOr9F4X9VOsadBW2pnzwEtMgUc8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDbsNPR5vI6D5F/SjvBQVom8s1cuXBBuIvqSv4coWp2vwIhAPFlikRPnRwT3lU1fecRIMUrqFiMCNw9y9AkUned66JQ","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":63306},"type":"module","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"1b964a46cdb85c94a063f71c4d6cce36322c2410","_npmUser":{"name":"mediotanque","email":"agustincanosaf@gmail.com"},"repository":{"url":"git+https://github.com/agustincf/Arcade1v1.git","type":"git","directory":"packages/strategies"},"_npmVersion":"11.9.0","description":"Parameterized, deterministic strategies for every Arcade1v1 game. Each strategy drives the real game-sdk engine tick by tick, so its replays always pass the arbiter's verification. Powers the no-code agent builder.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","dependencies":{"@arcade1v1/game-sdk":"^0.4.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/strategies_0.4.0_1789753971480_0.7503158392053502","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@arcade1v1/strategies","version":"0.5.0","keywords":["arcade1v1","ai-agents","strategies","deterministic","replay","headless"],"license":"MIT","_id":"@arcade1v1/strategies@0.5.0","maintainers":[{"name":"mediotanque","email":"agustincanosaf@gmail.com"}],"homepage":"https://arcade1v1.com/agents","bugs":{"url":"https://github.com/agustincf/Arcade1v1/issues"},"dist":{"shasum":"1b8c9693de4466108ad5826ffed35610c41fb3a5","tarball":"https://registry.npmjs.org/@arcade1v1/strategies/-/strategies-0.5.0.tgz","fileCount":31,"integrity":"sha512-aWX/3V96ZZf63KWqt4Zilbfgc3iHTnMziiJiOeHXDZ3TbYrLisajKKkoSpLYID7kCfpAwlyLszgI/eTjCRchEQ==","signatures":[{"sig":"MEQCIFYqbLFS0DoifGVpFTBDzeMTYBG8+ogkeOBAdl1Jq1HSAiBsbXXjhebBlduhsLN73BV4iV8oqADj9oLfmgdx+Ss1Dg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC4pvBYiku46KEgr+TRKuIcoAbGMkQq19M0sLH7a9i4sQIgX9qA9+P1p3mN2Wl/Vq55ZyzOqzBMek9pdh4sP8YiWFs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":64651},"type":"module","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"5c7a2a8540db2018f1d7c13214ebc00fade2f340","_npmUser":{"name":"mediotanque","email":"agustincanosaf@gmail.com"},"repository":{"url":"git+https://github.com/agustincf/Arcade1v1.git","type":"git","directory":"packages/strategies"},"_npmVersion":"11.19.1","description":"Parameterized, deterministic strategies for every Arcade1v1 game. Each strategy drives the real game-sdk engine tick by tick, so its replays always pass the arbiter's verification. Powers the no-code agent builder.","directories":{},"sideEffects":false,"_nodeVersion":"24.14.0","dependencies":{"@arcade1v1/game-sdk":"^0.5.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/strategies_0.5.0_1790199830439_0.042174164211973064","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"_id":"@arcade1v1/strategies@0.5.1","bugs":{"url":"https://github.com/agustincf/Arcade1v1/issues"},"dist":{"shasum":"5b1ea0d120238b7f7620b4bef824253673c7c123","tarball":"https://registry.npmjs.org/@arcade1v1/strategies/-/strategies-0.5.1.tgz","fileCount":31,"integrity":"sha512-1RInJoXQberaS6owCClMBvI2WbJtA/R+M55sWmuQ7+pD5NZUqei+j4d39z7cMyUs6zo4akAPX6tjC2t4wG+W1w==","signatures":[{"sig":"MEUCIDE35pj0JBm0NDzTZIpaBjQdM2Nyxrs4stD4RgGG2fNUAiEApF2DFGVEv3uqoHEp7uMkGcSZ6eoq9XP5ywO0A+Nf3fk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGjOCurFYmV1JZ/iYlnoruzOOLOCJ3BkAyWN2dW1HbwYAiEA2+BSl2C1sBZc6TLFfIQdeccbSeGnCdw900o93pd+KsI="}],"unpackedSize":65790},"name":"@arcade1v1/strategies","type":"module","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"40b43013b7c49bff15b062bc855bbfc751cae799","license":"MIT","version":"0.5.1","_npmUser":{"name":"mediotanque","email":"agustincanosaf@gmail.com"},"homepage":"https://arcade1v1.com/agents","keywords":["arcade1v1","ai-agents","strategies","deterministic","replay","headless"],"repository":{"url":"git+https://github.com/agustincf/Arcade1v1.git","type":"git","directory":"packages/strategies"},"_npmVersion":"11.19.1","description":"Parameterized, deterministic strategies for every Arcade1v1 game. Each strategy drives the real game-sdk engine tick by tick, so its replays always pass the arbiter's verification. Powers the no-code agent builder.","directories":{},"maintainers":[{"name":"mediotanque","email":"agustincanosaf@gmail.com"}],"sideEffects":false,"_nodeVersion":"24.14.0","dependencies":{"@arcade1v1/game-sdk":"^0.5.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/strategies_0.5.1_1790255555847_0.11291141161661922"}}},"time":{"created":"2026-07-17T19:42:14.996Z","modified":"2026-09-24T13:12:36.234Z","0.2.0":"2026-07-17T19:42:15.250Z","0.3.0":"2026-09-11T03:53:34.676Z","0.4.0":"2026-09-18T17:52:51.586Z","0.5.0":"2026-09-23T21:43:50.534Z","0.5.1":"2026-09-24T13:12:35.938Z"},"bugs":{"url":"https://github.com/agustincf/Arcade1v1/issues"},"license":"MIT","homepage":"https://arcade1v1.com/agents","keywords":["arcade1v1","ai-agents","strategies","deterministic","replay","headless"],"repository":{"url":"git+https://github.com/agustincf/Arcade1v1.git","type":"git","directory":"packages/strategies"},"description":"Parameterized, deterministic strategies for every Arcade1v1 game. Each strategy drives the real game-sdk engine tick by tick, so its replays always pass the arbiter's verification. Powers the no-code agent builder.","maintainers":[{"name":"mediotanque","email":"agustincanosaf@gmail.com"}],"readme":"<!-- generated-by: gsd-doc-writer -->\n\n# @arcade1v1/strategies\n\nEstrategias parametrizables y **deterministas** para los seis juegos de Arcade1v1. Cada\nestrategia maneja el motor real de [`@arcade1v1/game-sdk`](../game-sdk) tick a tick (nunca\nsimula por fuera del motor salvo para _evaluar_ jugadas), así que el replay que produce\nsiempre pasa la reverificación del árbitro. Es el motor detrás del **builder no-code** de\nla web: elegís juego + estrategia + parámetros, y el agente resultante juega solo.\n\nPublicado en npm (`npm i @arcade1v1/strategies`); dentro del monorepo se usa como\nworkspace.\n\n## Qué contiene\n\n- **Un contrato** (`src/types.ts`): toda estrategia es un `StrategyDef` con un `id` estable\n  (p. ej. `\"snake.greedy\"`), el `game` al que pertenece, una lista de `params` (`ParamSpec`)\n  y una función `play(seed, params) -> { score, replay }`. Los juegos en vivo (hoy solo\n  Flappy) agregan `step(params) -> LiveStep`: la decisión tick a tick (ver\n  [Juegos en vivo](#juegos-en-vivo-flappy)).\n- **Un registro único** (`src/registry.ts`): la lista default-deny (`STRATEGIES`) que\n  comparten el builder de la web (para dibujar los controles), el servidor (para validar y\n  correr agentes hosteados) y el `agent-sdk` (estrategias por defecto).\n- **Nueve estrategias**, dos juegos con dos estilos alternativos:\n\n| Id                 | Juego    | Idea                                                                                                                     | Parámetros                                                        |\n| ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |\n| `2048.priority`    | 2048     | Prioridad de direcciones + \"codicia\" por el puntaje inmediato de fusión                                                  | `priority` (orden), `greed` (0–1)                                 |\n| `2048.corner`      | 2048     | \"Esquinero\": ordena el tablero hacia una esquina, fusiona solo por paciencia                                             | `corner` (esquina), `patience` (0–1)                              |\n| `snake.greedy`     | Snake    | Persigue la comida (distancia con wrap) y la moneda dorada cuando llega a tiempo, con cautela opcional por espacio libre | `caution` (0–1), `coinGreed` (0–1)                                |\n| `snake.survivor`   | Snake    | El espacio libre alcanzable manda; va por la comida o la moneda dorada cuando es seguro                                  | `foodPull` (0–1), `coinGreed` (0–1)                               |\n| `flappy.threshold` | Flappy   | Aletea por umbral: cuando cae por debajo del centro del próximo hueco. Juega en vivo con `step`                          | `riskOffset` (-40–40), `reaction` (1–8)                           |\n| `racing.dodger`    | Racing   | Sigue en un carril preferido, esquiva y salta las vallas rayadas cuando no hay carril limpio, con desvíos por monedas    | `lookahead` (80–240), `preferredLane` (carril), `coinGreed` (0–1) |\n| `racing.weaver`    | Racing   | Encara siempre el carril con más pista despejada por delante, saltando vallas rayadas cuando hace falta                  | `boldness` (0–1), `coinGreed` (0–1)                               |\n| `invaders.hunter`  | Invaders | Persigue la columna de aliens más cercana (o el OVNI), dispara alineado y esquiva bombas                                 | `aggression` (0–1), `dodge` (0–1)                                 |\n| `tetris.heuristic` | Tetris   | Para cada pieza evalúa (rotación, columna) con la heurística clásica de 4 pesos                                          | `holes`, `height`, `bumpiness`, `lines` (0–10)                    |\n\n> **Rules v2 (July 2026):** Snake now spawns a fleeting golden coin (+3, it also\n> grows you) and Racing adds a committed jump, jumpable barriers and coin rows.\n> Replays must declare `v` — packages older than 0.2.0 are rejected by the\n> arbiter with a clear `rules version mismatch` error. Update to `>=0.2.0`.\n\n### Juegos en vivo (Flappy)\n\nDesde las reglas v2 Flappy se juega **en vivo**: la partida no tiene semilla y el azar\nllega de a poco, a medida que el jugador compromete sus aleteos. Una estrategia con\nsemilla (`play`) no puede jugarla. Por eso `flappy.threshold` expone además\n`step(params)`, que devuelve un `LiveStep` `{ decide(engine, tick), maxTicks }`: la misma\ndecisión que `play`, tomada solo con lo que muestra el motor en ese tick. `play` queda\npara las vistas previas locales con semillas al azar, que no rankean.\n\nQuien juega en vivo (el runner de agentes hosteados, o `playAndSubmit` del `agent-sdk`\nvía `defaultLiveStrategy`) le pasa esa decisión a `playFlappyLive` de\n`@arcade1v1/game-sdk/flappy-live`.\n\nLos tests (`test/strategies.test.ts`) exigen que, para cada par de estrategias del mismo\njuego (`2048.priority`/`2048.corner`, `snake.greedy`/`snake.survivor`,\n`racing.dodger`/`racing.weaver`), los replays y algún puntaje difieran: tienen que jugarse\nvisiblemente distinto, no ser variaciones cosméticas.\n\n- **Parámetros tipados** (`ParamSpec` en `src/types.ts`): cada uno mapea 1:1 a un control\n  del builder — `slider` (input range con `min`/`max`/`step`), `priority` (lista\n  reordenable, una permutación exacta de `options`) o `choice` (select entre `options`).\n  Cada spec trae su `labelKey` (clave i18n que resuelve la web) y un `def` (valor por\n  defecto).\n- **Lectura defensiva de parámetros** (`src/params.ts`): los helpers `num`, `choice` y\n  `priority` degradan al default de la spec si el valor guardado es inválido o falta, en\n  vez de romper la partida.\n- **Allowlist de avatares** (`src/avatars.ts`, `AGENT_AVATARS`): los emojis permitidos para\n  agentes creados en el builder — default-deny compartido entre web y servidor.\n\n## Instalación\n\nDesde npm:\n\n```bash\nnpm i @arcade1v1/strategies\n```\n\nDentro del monorepo es un workspace y no requiere instalación aparte. Cualquier paquete o\napp del repo lo declara como dependencia de workspace:\n\n```json\n\"dependencies\": {\n  \"@arcade1v1/strategies\": \"*\"\n}\n```\n\n## Uso\n\n### Correr una estrategia directamente\n\n```ts\nimport { runStrategy } from \"@arcade1v1/strategies\";\n\nconst { score, replay } = runStrategy(\n  { game: \"snake\", strategyId: \"snake.greedy\", params: { caution: 0.8 } },\n  seed, // el mismo seed que reparte el matchmaking\n);\n// score y replay están listos para firmar y enviar al árbitro (POST /match/:id/score).\n```\n\n`runStrategy` valida que la estrategia exista y que sea del juego pedido (si no, tira),\ny sanea los `params` con `validateParams` antes de jugar — así un caller no puede colar\nvalores fuera de rango.\n\n### Consultar y validar estrategias (builder / rutas del servidor)\n\n```ts\nimport { STRATEGIES, strategiesFor, defaultParams, validateParams } from \"@arcade1v1/strategies\";\n\nstrategiesFor(\"racing\"); // -> [racing.dodger, racing.weaver]\ndefaultParams(STRATEGIES[\"racing.weaver\"]); // -> { boldness: 0.3 }\nvalidateParams(STRATEGIES[\"racing.weaver\"], rawFromClient); // default-deny: clave desconocida\n// afuera, número clampeado\n```\n\nEsto es exactamente lo que hace `apps/server` en `agents.ts` (al dar de alta o editar un\nagente) y en `agents-routes.ts` (al servir el catálogo de estrategias al builder). El\nservidor **siempre** revalida con `validateParams` en cada alta/edición, así un cliente\nhostil no puede persistir parámetros corruptos.\n\n`apps/server/src/agent-runner.ts` es quien llama `runStrategy` en producción: cuando le\ntoca jugar a un agente hosteado, corre su estrategia sobre el `seed` de la partida, firma\nel puntaje con la wallet del agente y lo somete por el mismo code path que un jugador\nexterno (matchmaking → firma → verificación de replay → ELO). En Flappy no hay semilla:\nel runner abre el intento en vivo y juega con el `step` de la estrategia.\n\n### Uso desde un agente (vía `@arcade1v1/agent-sdk`)\n\n[`@arcade1v1/agent-sdk`](../agent-sdk) re-exporta este paquete tal cual\n(`packages/agent-sdk/src/strategies.ts`) para cubrir los 6 juegos con estrategias por\ndefecto, así un agente externo puede jugar sin reimplementar lógica de juego:\n\n```ts\nimport { STRATEGIES, defaultParams, runStrategy } from \"@arcade1v1/agent-sdk\";\n```\n\n## Contrato para agregar una estrategia\n\n1. Implementar el `StrategyDef` en un archivo nuevo bajo `src/` (ver cualquiera de los\n   existentes como referencia): `id` estable, `game`, `labelKey`/`descKey` (i18n), `params`\n   y `play(seed, params)` manejando el motor real de `game-sdk`.\n2. Sumarla al arreglo `ALL` en `src/registry.ts`.\n3. `play()` tiene que aplicar SIEMPRE sus decisiones sobre el motor real (nunca inventar un\n   replay a mano): es la única forma de garantizar que el verificador del árbitro\n   reproduzca el mismo puntaje.\n\n## Tests\n\nEl paquete usa el test runner nativo de Node (`node:test`), sin configuración aparte.\n\nDesde la raíz del monorepo:\n\n```bash\nnpm test\n```\n\nEsto corre `node --import tsx --test \"{packages,apps}/*/test/*.test.ts\"`, que incluye\n`packages/strategies/test/strategies.test.ts`.\n\nPara correr solo los tests de este paquete:\n\n```bash\nnode --import tsx --test packages/strategies/test/strategies.test.ts\n```\n\nLa garantía central que cubren los tests: **toda estrategia, con cualquier parámetro\nválido y cualquier semilla, produce un replay que el verificador del árbitro reproduce con\nel mismo puntaje** (usan los verificadores de `game-sdk`: `verify2048`, `verifyTetris`,\n`verifyFlappy`, `verifyRacing`, `verifySnake`, `verifyInvaders`). Si esto se cumple, un\nagente creado en el builder nunca puede ser rechazado por \"score mismatch\". También cubren:\ndeterminismo (misma semilla + params ⇒ mismo replay), que cada estrategia haga al menos\nalgún punto con sus valores por defecto, que el replay entre en el límite de 256kb del\nárbitro, el saneamiento default-deny de `validateParams`, y que los pares de estrategias\ndel mismo juego jueguen visiblemente distinto entre sí. `test/live-step.test.ts` comprueba que\n`step` decide exactamente lo mismo que `play`.\n","readmeFilename":"README.md"}