| # 📖 Manual de juego — Lesky's Shop (Legisladores del Bosque) |
|
|
| > Un duelo de fichas en un tablero donde el verdadero campo de batalla |
| > son **las leyes**: quien gana una ronda dicta una norma en lenguaje libre |
| > que deforma el tablero para todos. Y cuidado: los rivales mienten. |
|
|
| --- |
|
|
| ## 1. El concepto |
|
|
| Es una **campaña contra dos rivales**. Juegas con tus **fichas azules** 🔵 y |
| debes derrotar, uno tras otro, a: |
|
|
| 1. **Lesky** 🟡 — un duende legislador con pocos escrúpulos. Tablero **3×3**, |
| **5 rondas**. |
| 2. **The Monster** 🟢 — el jefe. Tablero **4×4**, **2 rondas**, más difícil. |
|
|
| Vence a un rival y te llevas su **tesoro**; luego te enfrentas al siguiente. |
| Ganar los dos tesoros = campaña completada. |
|
|
| Cada ronda se disputa sobre el tablero, pero las **leyes activas** (el Pergamino) |
| cambian sus valores y reglas. Ganar una ronda otorga el derecho a legislar; |
| legislar bien es lo que gana partidas. |
|
|
| ## 2. El tablero |
|
|
| El tablero **cambia cada ronda**: se reparte una distribución nueva de valores |
| (las casillas centrales suelen valer más que los bordes, pero la disposición |
| varía). Un ejemplo típico de 3×3: |
|
|
| ``` |
| 2 1 2 |
| 1 3 1 |
| 2 1 2 |
| ``` |
|
|
| Las leyes pueden alterar estos valores (doblarlos, anularlos, sumarles |
| puntos…), prohibir casillas o cambiar las reglas de choque. Contra el Monstruo |
| el tablero es **4×4**, con más casillas y más en juego. |
|
|
| ## 3. Una ronda, paso a paso |
|
|
| 1. Cada jugador coloca sus fichas, una por turno: **3 fichas** en 3×3, **4** en 4×4. |
| 2. La colocación es **simultánea**: tú y el rival elegís casilla a la vez, |
| sin ver la elección del otro. |
| 3. Si elegís **casillas distintas**, cada uno ocupa la suya. |
| 4. Si elegís **la misma casilla**, hay choque (⚔️). Por defecto la casilla |
| queda **disputada**: no es de nadie y no puntúa. Una ley puede cambiarlo |
| (ver modos de choque). |
| 5. Tras colocar todas las fichas se puntúa: **cada uno suma el valor de sus |
| casillas**, con los modificadores de las leyes activas. El que más sume gana |
| la ronda. |
| 6. Si hay empate de puntos, nadie gana la ronda y nadie legisla. |
|
|
| > **Cómo se gana la partida:** NO es "al mejor de 3". Se juegan todas las |
| > rondas y gana quien acumule **más puntos totales** sumando todas las rondas, |
| > con el bonus de astucia (**1 🦊 = +3 puntos**). Ver §6. |
|
|
| ### Modos de choque |
|
|
| | Modo | Qué pasa si ambos eligen la misma casilla | |
| |---|---| |
| | `disputed` *(por defecto)* | La casilla no es de nadie, no puntúa | |
| | `mine_wins` / `red_wins` | Te la quedas tú | |
| | `opponent_wins` / `blue_wins` | Se la queda el rival | |
| | `split` (➗) | Cada uno suma la mitad de su valor | |
|
|
| ## 4. Las leyes |
|
|
| Al ganar una ronda, dictas una ley **escribiendo una frase libre**: |
|
|
| > *"quiero que las esquinas valgan el doble"* |
| > *"prohibido que el rival pise el centro"* |
| > *"si chocamos en una casilla, me la quedo yo"* |
|
|
| Un **LLM (Nemotron, en Modal)** traduce tu frase a un efecto estructurado, y |
| **el árbitro (el código) la valida**: si pide algo fuera del vocabulario, |
| números absurdos o una victoria directa, se rechaza. El LLM propone, el código |
| dispone. |
|
|
| *(Sin LLM —modo `--sin-llm`— las leyes se eligen de una lista fija. Mismas |
| reglas, menos poesía, y los rivales no mienten.)* |
|
|
| ### Vocabulario de efectos |
|
|
| | Efecto | Qué hace | Límites | |
| |---|---|---| |
| | `set_value(zona, valor)` | Fija el valor de las casillas | valor 0–9 | |
| | `multiply_value(zona, factor)` | Multiplica el valor | factor 0–3 | |
| | `add_value(zona, cantidad)` | Suma/resta al valor | −3 a +3 | |
| | `forbid_placement(zona, dueño)` | Prohíbe colocar ahí | no vale `all` | |
| | `penalty_zone(zona, dueño, cantidad)` | Puntos extra/menos por ficha en la zona | −3 a +3 | |
| | `bonus_adjacency(dueño, cantidad)` | Puntos por cada par de fichas propias adyacentes | −3 a +3 | |
| | `clash_resolution(modo)` | Cambia la regla de choque | ver tabla de modos | |
|
|
| **Zonas (3×3):** `center`, `corners`, `edges`, `row_top/mid/bot`, |
| `col_left/mid/right`, `cell(fila,col)`, `all`. |
| **Zonas (4×4):** igual, con `center` = el cuadrado central 2×2 y filas/columnas |
| medias dobles. |
| **Dueños:** `red`/`mine` (tú), `blue`/`opponent` (rival), `any`. |
|
|
| ### El Pergamino |
|
|
| - Las leyes activas viven en el **Pergamino**, máximo **3**. |
| - Para promulgar una cuarta hay que **derogar** una existente. |
| - Las leyes se aplican **en orden de promulgación** (importa: "+1 al centro" y |
| luego "×2 al centro" da 8; al revés da 7). |
| - El Pergamino arranca con un par de **leyes del bosque** aleatorias ya activas. |
|
|
| ## 5. Rivales tramposos |
|
|
| Cuando un rival gana una ronda, también legisla. Pero son ladinos: **lo que |
| anuncian y lo que de verdad meten en el Pergamino pueden no coincidir**. |
|
|
| - En el Pergamino verás siempre *lo que anunció*. |
| - Si sospechas, **acúsalo** (botón ⚖️ *Accuse*). El árbitro compara lo anunciado |
| con lo aplicado: |
| - **Mentía** → la ley se deroga, ganas **astucia** 🦊 y bajas la precisión |
| futura del rival (−7% por caza, se arrastra al Monstruo). |
| - **Era honesto** → se ríe de ti y pierdes **1 de astucia**. |
| - Cada ley solo puede juzgarse una vez. Cualquier ley es acusable (incluso las |
| del bosque). |
| |
| *(Sin LLM, los rivales son honestos: las trampas llegan con el modelo.)* |
|
|
| ## 6. Astucia, misiones y tienda |
|
|
| - La **astucia** 🦊 es tu moneda de ventaja. Al final cuenta fuerte: **cada |
| punto de astucia = +3 puntos** en el marcador total de la partida. |
| - **Misiones secretas:** cada partida tienes un objetivo oculto (controlar |
| bordes, evitar el centro, alinear fichas, sin choques…). Cumplirlo cada ronda |
| da astucia extra. |
| - **Tienda de astucia:** gasta astucia para |
| - 🔎 **espiar** la misión secreta del rival, |
| - 👁️ **revelar** el valor de una casilla oculta, |
| - 🗑️ **derogar** una ley del Pergamino. |
|
|
| ## 7. Las voces |
|
|
| Los rivales **hablan**: una IA de voz, **Chatterbox** (Resemble AI, ~0.5B, en Modal), |
| clona un timbre distinto para Lesky, el Monstruo y los gnomos a partir de unos segundos |
| de audio de referencia (`assets/voices/`). Cuando un personaje habla, la música baja |
| para escucharlo. Las voces se generan al vuelo y se cachean en disco (frase repetida = |
| instantánea, sin coste). |
|
|
| ## 8. Cómo se ejecuta |
|
|
| ```bash |
| conda activate smolhack |
| pip install -r requirements.txt |
| |
| # Interfaz gráfica (la demo): abre http://127.0.0.1:7860 |
| gradio app.py # con hot-reload |
| python app.py # igual, sin reload |
| python app.py --sin-llm # sin LLM: leyes de lista fija, rivales honestos |
| |
| # Tests del motor |
| python -m pytest game/test_engine.py -q |
| ``` |
|
|
| - **LLM:** Nemotron-Nano-4B servido en **Modal** (endpoint en `game/llm.py`, |
| `MODAL_ENDPOINT_URL`). Define la app en `modal/app.py`. |
| - **Voces (TTS):** **Chatterbox** (Resemble AI) en **Modal** (`tools/tts_modal.py`); |
| las voces de referencia están en `assets/voices/`. |
|
|
| ## 9. Consejos del bosque |
|
|
| - El centro suele valer más y el rival lo sabe: ir a por él es jugarse un choque. |
| - Una ley defensiva (*"prohibido que el rival pise el centro"*) vale tanto como |
| una ofensiva. |
| - Vigila el orden del Pergamino antes de derogar: quitar una ley antigua puede |
| cambiar el resultado de las que vinieron después. |
| - La astucia pesa el triple al final: cazar una mentira no solo deroga la ley, |
| te da ventaja real en el marcador. |
| - Acusar por sistema sale caro. Acusa cuando la ley *huela* raro: anuncios |
| grandilocuentes con efectos pequeños suelen esconder otra cosa. |
|
|
| --- |
|
|
| *Proyecto para el Build Small Hackathon (Gradio + Hugging Face + Modal). |
| Arquitectura: el LLM propone, el código dispone — el modelo solo traduce frases |
| a efectos; el estado, la validación y la puntuación son siempre del árbitro en |
| Python. La UI (`ui/`) y la lógica (`game/`) están separadas por el contrato |
| `game.Session`.* |