diff --git a/g1-no-property.mmd b/g1-no-property.mmd
index 7aaa9af..8875561 100644
--- a/g1-no-property.mmd
+++ b/g1-no-property.mmd
@@ -1,6 +1,22 @@
flowchart TD
- A1[P1: Proponer oferta? (pavos/elotes + pedido)] -->|No ofrecer| O1[Sin cambios]
- A1 -->|Ofrecer| B1[P2: Aceptar / Rechazar / Robar]
- B1 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- B1 -->|Rechazar| O3[Sin cambios]
- B1 -->|Robar| O4[Transferir solo lo ofrecido a P2]
+ Start[G1: Sin derechos de propiedad] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> A1{P1: Ofrecer tokens?}
+ A1 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ A1 -->|Proponer oferta| B1[P1 especifica:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+ B1 --> C1[UI: Ocultar OfferControls
Mostrar oferta a ambos jugadores]
+ C1 --> D1{P2: Una sola decisión}
+ D1 -->|Aceptar| O2[Intercambiar tokens:
P1 da oferta, recibe pedido
P2 da pedido, recibe oferta
→ Auto-avance]
+ D1 -->|Rechazar| O3[Sin cambios en tokens
→ Auto-avance]
+ D1 -->|Robar| O4[P2 recibe oferta
P1 pierde oferta
Sin pago de P2
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#1a237e,stroke:#fff,color:#fff
+ style Init fill:#283593,stroke:#fff,color:#fff
+ style A1 fill:#4527a0,stroke:#fff,color:#fff
+ style B1 fill:#512da8,stroke:#fff,color:#fff
+ style C1 fill:#37474f,stroke:#fff,color:#fff
+ style D1 fill:#455a64,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4 fill:#d32f2f,stroke:#fff,color:#fff
diff --git a/g2-counterproductive-rule.mmd b/g2-counterproductive-rule.mmd
index 11e86a4..f237c5a 100644
--- a/g2-counterproductive-rule.mmd
+++ b/g2-counterproductive-rule.mmd
@@ -1,9 +1,30 @@
flowchart TD
- A2[P2: Forzar?] -->|Sí| F2[P1: Debe proponer oferta]
- A2 -->|No| B2[P1: Proponer oferta?]
- F2 --> C2[P2: Acción final]
- B2 -->|No ofrecer| O1[Sin cambios]
- B2 -->|Ofrecer| C2[P2: Aceptar / Rechazar / Robar]
- C2 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- C2 -->|Rechazar| O3[Sin cambios]
- C2 -->|Robar| O4[Transferir solo lo ofrecido a P2]
+ Start[G2: Regla contraproductiva] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> A2[P2: Checkbox 'Forzar oferta'
🔲 Activo por defecto]
+ A2 -->|forcedByP2 = true| F2[P1 DEBE ofrecer
Botón 'No ofrecer' deshabilitado]
+ A2 -->|forcedByP2 = false| B2{P1: Ofrecer tokens?}
+
+ F2 --> C2[P1 especifica oferta obligatoria:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+ B2 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ B2 -->|Proponer oferta| C2
+
+ C2 --> D2[UI: Ocultar OfferControls
Mostrar detalles oferta]
+ D2 --> E2{P2: Una sola decisión}
+
+ E2 -->|Aceptar| O2[Intercambiar tokens
→ Auto-avance]
+ E2 -->|Rechazar| O3[Sin cambios
→ Auto-avance]
+ E2 -->|Robar| O4[P2 recibe oferta sin pagar
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#6a1b9a,stroke:#fff,color:#fff
+ style Init fill:#7b1fa2,stroke:#fff,color:#fff
+ style A2 fill:#8e24aa,stroke:#fff,color:#fff
+ style F2 fill:#ab47bc,stroke:#fff,color:#fff
+ style B2 fill:#4527a0,stroke:#fff,color:#fff
+ style C2 fill:#512da8,stroke:#fff,color:#fff
+ style D2 fill:#37474f,stroke:#fff,color:#fff
+ style E2 fill:#455a64,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4 fill:#d32f2f,stroke:#fff,color:#fff
diff --git a/g3-shame-token.mmd b/g3-shame-token.mmd
index 4cbe390..f461d8b 100644
--- a/g3-shame-token.mmd
+++ b/g3-shame-token.mmd
@@ -1,8 +1,31 @@
flowchart TD
- A3[P1: Proponer oferta?] -->|No ofrecer| O1[Sin cambios]
- A3 -->|Ofrecer| B3[P2: Aceptar / Rechazar / Robar]
- B3 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- B3 -->|Rechazar| O3[Sin cambios]
- B3 -->|Robar| C3[P1: Asignar ficha de vergüenza?]
- C3 -->|Sí| O4a[+1 vergüenza para P2]
- C3 -->|No| O4b[Sin vergüenza]
+ Start[G3: Token de repudio/vergüenza] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> A3{P1: Ofrecer tokens?}
+ A3 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ A3 -->|Proponer oferta| B3[P1 especifica:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+
+ B3 --> C3[UI: Ocultar OfferControls
Mostrar detalles oferta]
+ C3 --> D3{P2: Una sola decisión}
+
+ D3 -->|Aceptar| O2[Intercambiar tokens
→ Auto-avance]
+ D3 -->|Rechazar| O3[Sin cambios
→ Auto-avance]
+ D3 -->|Robar| E3[P2 recibe oferta sin pagar
UI: Ocultar botones P2]
+
+ E3 --> F3{P1: ¿Asignar vergüenza?}
+ F3 -->|Asignar| O4a[P2.shameTokens += 1
😶 Visible en UI
→ Auto-avance]
+ F3 -->|No asignar| O4b[Sin penalización
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#e65100,stroke:#fff,color:#fff
+ style Init fill:#ef6c00,stroke:#fff,color:#fff
+ style A3 fill:#4527a0,stroke:#fff,color:#fff
+ style B3 fill:#512da8,stroke:#fff,color:#fff
+ style C3 fill:#37474f,stroke:#fff,color:#fff
+ style D3 fill:#455a64,stroke:#fff,color:#fff
+ style E3 fill:#bf360c,stroke:#fff,color:#fff
+ style F3 fill:#ff6f00,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4a fill:#ff3d00,stroke:#fff,color:#fff
+ style O4b fill:#616161,stroke:#fff,color:#fff
diff --git a/g4-min-property-rights.mmd b/g4-min-property-rights.mmd
index a9ad18d..1e2ab75 100644
--- a/g4-min-property-rights.mmd
+++ b/g4-min-property-rights.mmd
@@ -1,9 +1,38 @@
flowchart TD
- A4[P1: Proponer oferta?] -->|No ofrecer| O1[Sin cambios]
- A4 -->|Ofrecer| B4[P2: Aceptar / Rechazar / Robar]
- B4 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- B4 -->|Rechazar| O3[Sin cambios]
- B4 -->|Robar| C4[P1: ¿Denunciar?]
- C4 -->|No| O4[Transferir solo lo ofrecido a P2]
- C4 -->|Sí| J4[AutoJudge revierte robo (confisca oferta a P2)]
- J4 --> O5[Restituir oferta a P1]
+ Start[G4: Derechos mínimos de propiedad] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> A4{P1: Ofrecer tokens?}
+ A4 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ A4 -->|Proponer oferta| B4[P1 especifica:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+
+ B4 --> C4[UI: Ocultar OfferControls
Mostrar detalles oferta]
+ C4 --> D4{P2: Una sola decisión}
+
+ D4 -->|Aceptar| O2[Intercambiar tokens
→ Auto-avance]
+ D4 -->|Rechazar| O3[Sin cambios
→ Auto-avance]
+ D4 -->|Robar| E4[P2 recibe oferta sin pagar
UI: Ocultar botones P2]
+
+ E4 --> F4{P1: ¿Denunciar al juez?}
+ F4 -->|No denunciar| O4[Robo exitoso
→ Auto-avance]
+ F4 -->|Denunciar| J4[⚖️ AutoJudge actúa]
+
+ J4 --> S1[Paso 1 - Revertir robo:
Devolver tokens ofrecidos a P1]
+ S1 --> S2[Paso 2 - Sanción inversa:
P1 recibe lo pedido sin dar nada
P2 pierde lo pedido]
+ S2 --> O5[Sanción aplicada
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#b71c1c,stroke:#fff,color:#fff
+ style Init fill:#c62828,stroke:#fff,color:#fff
+ style A4 fill:#4527a0,stroke:#fff,color:#fff
+ style B4 fill:#512da8,stroke:#fff,color:#fff
+ style C4 fill:#37474f,stroke:#fff,color:#fff
+ style D4 fill:#455a64,stroke:#fff,color:#fff
+ style E4 fill:#d32f2f,stroke:#fff,color:#fff
+ style F4 fill:#e53935,stroke:#fff,color:#fff
+ style J4 fill:#1b5e20,stroke:#fff,color:#fff
+ style S1 fill:#2e7d32,stroke:#fff,color:#fff
+ style S2 fill:#388e3c,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4 fill:#bf360c,stroke:#fff,color:#fff
+ style O5 fill:#43a047,stroke:#fff,color:#fff
diff --git a/g5-cheap-talk.mmd b/g5-cheap-talk.mmd
index 01782a7..45348d1 100644
--- a/g5-cheap-talk.mmd
+++ b/g5-cheap-talk.mmd
@@ -1,7 +1,26 @@
flowchart TD
- Pre[Chat previo 1 min - no vinculante] --> A5[P1: Proponer oferta?]
- A5 -->|No ofrecer| O1[Sin cambios]
- A5 -->|Ofrecer| B5[P2: Aceptar / Rechazar / Robar]
- B5 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- B5 -->|Rechazar| O3[Sin cambios]
- B5 -->|Robar| O4[Transferir solo lo ofrecido a P2]
+ Start[G5: Cheap Talk] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> Pre[💬 Chat no vinculante
Ambos jugadores pueden escribir
Sin compromisos]
+ Pre --> A5{P1: Ofrecer tokens?}
+ A5 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ A5 -->|Proponer oferta| B5[P1 especifica:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+
+ B5 --> C5[UI: Ocultar OfferControls
Mostrar detalles oferta]
+ C5 --> D5{P2: Una sola decisión}
+
+ D5 -->|Aceptar| O2[Intercambiar tokens
→ Auto-avance]
+ D5 -->|Rechazar| O3[Sin cambios
→ Auto-avance]
+ D5 -->|Robar| O4[P2 recibe oferta sin pagar
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#004d40,stroke:#fff,color:#fff
+ style Init fill:#00695c,stroke:#fff,color:#fff
+ style Pre fill:#00796b,stroke:#fff,color:#fff
+ style A5 fill:#4527a0,stroke:#fff,color:#fff
+ style B5 fill:#512da8,stroke:#fff,color:#fff
+ style C5 fill:#37474f,stroke:#fff,color:#fff
+ style D5 fill:#455a64,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4 fill:#d32f2f,stroke:#fff,color:#fff
diff --git a/game-design-mermaid.md b/game-design-mermaid.md
index c538fb2..66a5a5b 100644
--- a/game-design-mermaid.md
+++ b/game-design-mermaid.md
@@ -7,13 +7,72 @@ Este índice reúne los diagramas claves para implementar el juego y verificar l
```mermaid
%% game-overview.mmd
flowchart TD
- A[Emparejar jugadores al azar] --> B[Asignar roles P1/P2]
- B --> C[Seleccionar variante G1..G5]
- C --> D[Iniciar partida de 3 rondas]
- D --> R1[Ronda 1] --> R2[Ronda 2] --> R3[Ronda 3]
- R3 --> E[Registrar SOLO resultado de R3]
- E --> F[Actualizar leaderboard/analytics]
- F --> G[Reemparejar y posible cambio de roles]
+ A[Demo Play] --> B[Asignar roles P1/P2]
+ B --> C{Jugadores pueden cambiar variante}
+ C --> |G1| G1[Sin derechos de propiedad]
+ C --> |G2| G2[Regla contraproductiva]
+ C --> |G3| G3[Token de repudio]
+ C --> |G4| G4[Derechos mínimos]
+ C --> |G5| G5[Cheap talk]
+
+ G1 --> D[P1: 10 pavos, P2: 10 elotes]
+ G2 --> D
+ G3 --> D
+ G4 --> D
+ G5 --> D
+
+ D --> E[Iniciar ronda]
+ E --> F{P1 ofrece?
❗G2: Si P2 fuerza, DEBE ofrecer}
+ F -->|Sí| G[P1 propone oferta variable]
+ F -->|No| H[No ofrecer → siguiente ronda]
+
+ G --> I{P2 decide}
+ I -->|Aceptar| J[Intercambiar tokens]
+ I -->|Rechazar| K[Sin cambios]
+ I -->|Robar| L[P2 toma oferta sin pagar]
+
+ J --> M[Auto-avance a siguiente ronda]
+ K --> M
+ L --> N{Variante especial?}
+ N -->|G3| O[P1: ¿Asignar vergüenza?]
+ N -->|G4| P[P1: ¿Denunciar?]
+ N -->|Otros| M
+
+ O --> M
+ P --> Q[Sanción: P1 recibe pedido sin dar oferta]
+ Q --> M
+
+ M --> R{Ronda < 3?}
+ R -->|Sí| E
+ R -->|No| S[Fin del juego → Status: FINISHED]
+ S --> T[Cambiar variante reinicia todo]
+
+ %%{init: {'theme':'dark'}}%%
+ style A fill:#1a1a2e,stroke:#fff,color:#fff
+ style B fill:#16213e,stroke:#fff,color:#fff
+ style C fill:#0f3460,stroke:#fff,color:#fff
+ style D fill:#1e3a5f,stroke:#fff,color:#fff
+ style E fill:#2d4059,stroke:#fff,color:#fff
+ style F fill:#533e85,stroke:#fff,color:#fff
+ style G fill:#2e7d32,stroke:#fff,color:#fff
+ style G1 fill:#304ffe,stroke:#fff,color:#fff
+ style G2 fill:#6a1b9a,stroke:#fff,color:#fff
+ style G3 fill:#e65100,stroke:#fff,color:#fff
+ style G4 fill:#b71c1c,stroke:#fff,color:#fff
+ style G5 fill:#004d40,stroke:#fff,color:#fff
+ style H fill:#424242,stroke:#fff,color:#fff
+ style I fill:#1a237e,stroke:#fff,color:#fff
+ style J fill:#2e7d32,stroke:#fff,color:#fff
+ style K fill:#757575,stroke:#fff,color:#fff
+ style L fill:#d32f2f,stroke:#fff,color:#fff
+ style M fill:#37474f,stroke:#fff,color:#fff
+ style N fill:#4527a0,stroke:#fff,color:#fff
+ style O fill:#ff6f00,stroke:#fff,color:#fff
+ style P fill:#c62828,stroke:#fff,color:#fff
+ style Q fill:#b71c1c,stroke:#fff,color:#fff
+ style R fill:#455a64,stroke:#fff,color:#fff
+ style S fill:#212121,stroke:#fff,color:#fff
+ style T fill:#263238,stroke:#fff,color:#fff
```
## Orquestación global (200 jugadores, G1->G5)
@@ -62,23 +121,73 @@ flowchart TD
```mermaid
%% game-state-machine.mmd
stateDiagram-v2
- [*] --> Lobby
- Lobby --> Matching : join/ready
- Matching --> Setup : asignar roles + variante
- Setup --> PreChat : si G5 (cheap talk)
- Setup --> Round1 : si no G5
- PreChat --> Round1 : fin ventana chat (1 min)
- Round1 --> Round2 : resultado cerrado
- Round2 --> Round3 : resultado cerrado
- Round3 --> PostGame : resultado cerrado
- PostGame --> Commit : registrar solo R3
- Commit --> Rematch : liberar jugadores
- Rematch --> [*]
-
- note right of Round1
- Las decisiones pueden ser:
- - Secuenciales (G1,G2,G3,G4,G5)
- - Simultáneas (si en el futuro aplica)
+ [*] --> DemoPlay
+
+ DemoPlay --> Waiting : quickPlay()
+ Waiting --> Playing : 2 jugadores conectados
+
+ state Playing {
+ [*] --> VariantSelection
+ VariantSelection --> RoundActive : seleccionar G1-G5
+
+ state RoundActive {
+ [*] --> OfferPhase
+
+ state OfferPhase {
+ [*] --> CheckForce
+ CheckForce --> ForcedOffer : G2 && forcedByP2
+ CheckForce --> OptionalOffer : !forcedByP2
+ ForcedOffer --> ProposeOffer : debe ofrecer
+ OptionalOffer --> ProposeOffer : ofrecer
+ OptionalOffer --> NoOffer : no ofrecer
+ }
+
+ ProposeOffer --> P2Decision : offerActive=true
+ NoOffer --> NextRound : auto-avance
+
+ state P2Decision {
+ [*] --> WaitingP2
+ WaitingP2 --> Accept : p2Action
+ WaitingP2 --> Reject : p2Action
+ WaitingP2 --> Snatch : p2Action
+ }
+
+ Accept --> TokenExchange : intercambiar
+ Reject --> NoChange : sin cambios
+ Snatch --> CheckVariant : robar tokens
+
+ TokenExchange --> NextRound : auto-avance
+ NoChange --> NextRound : auto-avance
+
+ state CheckVariant {
+ [*] --> CheckG3G4
+ CheckG3G4 --> ShameDecision : G3
+ CheckG3G4 --> ReportDecision : G4
+ CheckG3G4 --> NextRound : otros
+ }
+
+ ShameDecision --> NextRound : asignar/no asignar
+ ReportDecision --> Sanction : denunciar
+ ReportDecision --> NextRound : no denunciar
+ Sanction --> NextRound : aplicar sanción inversa
+ }
+
+ NextRound --> RoundActive : round < 3
+ NextRound --> Finished : round = 3
+ }
+
+ Finished --> VariantSelection : cambiar variante reinicia
+ Playing --> Finished : 3 rondas completadas
+
+ note right of VariantSelection
+ Cualquier jugador puede
+ cambiar variante en
+ cualquier momento
+ end note
+
+ note right of P2Decision
+ Una sola acción
+ permitida por oferta
end note
```
@@ -87,55 +196,80 @@ stateDiagram-v2
```mermaid
%% game-sequence.mmd
sequenceDiagram
- participant P1 as Player 1
- participant P2 as Player 2
+ participant P1 as Player 1 (10 pavos)
+ participant P2 as Player 2 (10 elotes)
participant S as Server/Room
- participant AJ as AutoJudge G4
+ participant UI as UI Components
- S->>P1: startRound(gameType, roundNo, role=P1)
- S->>P2: startRound(gameType, roundNo, role=P2)
+ Note over P1,P2: Inicio de Demo Play
+ S->>P1: Asignar rol P1, tokens iniciales
+ S->>P2: Asignar rol P2, tokens iniciales
+
+ Note over UI: Jugadores pueden cambiar variante en cualquier momento
+ P1->>S: setVariant(G1-G5)
+ S->>S: resetRound(), currentRound=1, status=PLAYING
+ S-->>P1: broadcast variantChanged
+ S-->>P2: broadcast variantChanged
- alt G2 (P2 decide forzar)
- P2->>S: decide(force or no_force)
- S-->>P1: forcedOffer = true/false
- else Otros juegos
- Note over P1,P2: Sin decision previa de P2
- end
+ loop Cada Ronda (1-3)
+ alt G2 - Regla contraproductiva
+ Note over P2: Checkbox "Forzar oferta" (activo por defecto)
+ P2->>S: p2Force(true/false)
+ S-->>UI: forcedByP2 = true/false
+ Note over P1: Si forzado, botón "No ofrecer" deshabilitado
+ end
- alt no_offer
- P1->>S: noOffer()
- S-->>P1: sin cambios de tokens
- S-->>P2: sin cambios de tokens
- else oferta
- P1->>S: proposeOffer({offer:{pavo,elote}, request:{pavo,elote}})
- S-->>P2: offerAvailable
- P2->>S: actionP2(accept / reject / snatch)
- alt accept
- S-->>P1: transfer ambos lados (según oferta/pedido)
- S-->>P2: transfer ambos lados (según oferta/pedido)
- else reject
- S-->>P1: sin cambios
- S-->>P2: sin cambios
- else snatch
- S-->>P2: transferir solo lo ofrecido a P2
- opt G4 denuncia
- P1->>S: report: yes or no
- alt report=yes
- S->>AJ: aplicar sanción
- AJ-->>S: confiscar oferta a P2 y revertir a P1
- else report=no
- Note over P1,P2: Se mantiene el robo
+ alt G5 - Cheap talk
+ Note over P1,P2: Chat no vinculante por 1 minuto
+ end
+
+ alt P1 decide ofrecer
+ P1->>S: proposeOffer({offerPavo, offerElote, requestPavo, requestElote})
+ S->>S: Validar tokens disponibles
+ S-->>UI: offerActive = true, ocultar OfferControls
+ S-->>P2: Mostrar oferta y botones de decisión
+
+ P2->>S: p2Action(accept/reject/snatch)
+ S->>S: Prevenir múltiples acciones (if p2Action exists, return)
+
+ alt accept
+ S->>S: Intercambiar tokens ambos lados
+ S->>S: Auto-avanzar ronda
+ else reject
+ S->>S: Sin cambios en tokens
+ S->>S: Auto-avanzar ronda
+ else snatch
+ S->>S: P2 recibe oferta sin pagar
+
+ alt G3 - Token de vergüenza
+ S-->>UI: Mostrar botones vergüenza a P1
+ P1->>S: assignShame(true/false)
+ alt true
+ S->>P2: shameTokens += 1
+ end
+ S->>S: Auto-avanzar ronda
+ else G4 - Derechos mínimos
+ S-->>UI: Mostrar botones denuncia a P1
+ P1->>S: report(true/false)
+ alt true
+ S->>S: Revertir robo
+ S->>S: P1 recibe pedido sin dar oferta (sanción inversa)
+ end
+ S->>S: Auto-avanzar ronda
+ else Otros
+ S->>S: Auto-avanzar ronda
end
end
- opt G3 repudio
- P1->>S: shameToken: assign yes or no
- S-->>P2: actualizar contador vergüenza (próxima partida)
- end
+ else P1 no ofrece
+ P1->>S: noOffer()
+ S->>S: p1Action = "no_offer"
+ S->>S: Auto-avanzar ronda
end
end
- S-->>P1: endRound
- S-->>P2: endRound
+ Note over S: Después de ronda 3
+ S->>S: gameStatus = FINISHED
+ Note over UI: Al cambiar variante, reinicia todo
```
## Variantes de juego
@@ -144,64 +278,172 @@ sequenceDiagram
```mermaid
%% g1-no-property.mmd
flowchart TD
- A1[P1: Proponer oferta? (pavos/elotes + pedido)] -->|No ofrecer| O1[Sin cambios]
- A1 -->|Ofrecer| B1[P2: Aceptar / Rechazar / Robar]
- B1 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- B1 -->|Rechazar| O3[Sin cambios]
- B1 -->|Robar| O4[Transferir solo lo ofrecido a P2]
+ Start[G1: Sin derechos de propiedad] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> A1{P1: Ofrecer tokens?}
+ A1 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ A1 -->|Proponer oferta| B1[P1 especifica:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+ B1 --> C1[UI: Ocultar OfferControls
Mostrar oferta a ambos jugadores]
+ C1 --> D1{P2: Una sola decisión}
+ D1 -->|Aceptar| O2[Intercambiar tokens:
P1 da oferta, recibe pedido
P2 da pedido, recibe oferta
→ Auto-avance]
+ D1 -->|Rechazar| O3[Sin cambios en tokens
→ Auto-avance]
+ D1 -->|Robar| O4[P2 recibe oferta
P1 pierde oferta
Sin pago de P2
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#1a237e,stroke:#fff,color:#fff
+ style Init fill:#283593,stroke:#fff,color:#fff
+ style A1 fill:#4527a0,stroke:#fff,color:#fff
+ style B1 fill:#512da8,stroke:#fff,color:#fff
+ style C1 fill:#37474f,stroke:#fff,color:#fff
+ style D1 fill:#455a64,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4 fill:#d32f2f,stroke:#fff,color:#fff
```
### G2 – Regla contraproductiva (P2 puede forzar) – oferta variable
```mermaid
%% g2-counterproductive-rule.mmd
flowchart TD
- A2[P2: Forzar?] -->|Sí| F2[P1: Debe proponer oferta]
- A2 -->|No| B2[P1: Proponer oferta?]
- F2 --> C2[P2: Acción final]
- B2 -->|No ofrecer| O1[Sin cambios]
- B2 -->|Ofrecer| C2[P2: Aceptar / Rechazar / Robar]
- C2 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- C2 -->|Rechazar| O3[Sin cambios]
- C2 -->|Robar| O4[Transferir solo lo ofrecido a P2]
+ Start[G2: Regla contraproductiva] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> A2[P2: Checkbox 'Forzar oferta'
🔲 Activo por defecto]
+ A2 -->|forcedByP2 = true| F2[P1 DEBE ofrecer
Botón 'No ofrecer' deshabilitado]
+ A2 -->|forcedByP2 = false| B2{P1: Ofrecer tokens?}
+
+ F2 --> C2[P1 especifica oferta obligatoria:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+ B2 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ B2 -->|Proponer oferta| C2
+
+ C2 --> D2[UI: Ocultar OfferControls
Mostrar detalles oferta]
+ D2 --> E2{P2: Una sola decisión}
+
+ E2 -->|Aceptar| O2[Intercambiar tokens
→ Auto-avance]
+ E2 -->|Rechazar| O3[Sin cambios
→ Auto-avance]
+ E2 -->|Robar| O4[P2 recibe oferta sin pagar
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#6a1b9a,stroke:#fff,color:#fff
+ style Init fill:#7b1fa2,stroke:#fff,color:#fff
+ style A2 fill:#8e24aa,stroke:#fff,color:#fff
+ style F2 fill:#ab47bc,stroke:#fff,color:#fff
+ style B2 fill:#4527a0,stroke:#fff,color:#fff
+ style C2 fill:#512da8,stroke:#fff,color:#fff
+ style D2 fill:#37474f,stroke:#fff,color:#fff
+ style E2 fill:#455a64,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4 fill:#d32f2f,stroke:#fff,color:#fff
```
### G3 – Token de repudio (vergüenza) – oferta variable
```mermaid
%% g3-shame-token.mmd
flowchart TD
- A3[P1: Proponer oferta?] -->|No ofrecer| O1[Sin cambios]
- A3 -->|Ofrecer| B3[P2: Aceptar / Rechazar / Robar]
- B3 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- B3 -->|Rechazar| O3[Sin cambios]
- B3 -->|Robar| C3[P1: Asignar ficha de vergüenza?]
- C3 -->|Sí| O4a[+1 vergüenza para P2]
- C3 -->|No| O4b[Sin vergüenza]
+ Start[G3: Token de repudio/vergüenza] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> A3{P1: Ofrecer tokens?}
+ A3 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ A3 -->|Proponer oferta| B3[P1 especifica:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+
+ B3 --> C3[UI: Ocultar OfferControls
Mostrar detalles oferta]
+ C3 --> D3{P2: Una sola decisión}
+
+ D3 -->|Aceptar| O2[Intercambiar tokens
→ Auto-avance]
+ D3 -->|Rechazar| O3[Sin cambios
→ Auto-avance]
+ D3 -->|Robar| E3[P2 recibe oferta sin pagar
UI: Ocultar botones P2]
+
+ E3 --> F3{P1: ¿Asignar vergüenza?}
+ F3 -->|Asignar| O4a[P2.shameTokens += 1
😶 Visible en UI
→ Auto-avance]
+ F3 -->|No asignar| O4b[Sin penalización
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#e65100,stroke:#fff,color:#fff
+ style Init fill:#ef6c00,stroke:#fff,color:#fff
+ style A3 fill:#4527a0,stroke:#fff,color:#fff
+ style B3 fill:#512da8,stroke:#fff,color:#fff
+ style C3 fill:#37474f,stroke:#fff,color:#fff
+ style D3 fill:#455a64,stroke:#fff,color:#fff
+ style E3 fill:#bf360c,stroke:#fff,color:#fff
+ style F3 fill:#ff6f00,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4a fill:#ff3d00,stroke:#fff,color:#fff
+ style O4b fill:#616161,stroke:#fff,color:#fff
```
### G4 – Derechos mínimos de propiedad (juez) – oferta variable
```mermaid
%% g4-min-property-rights.mmd
flowchart TD
- A4[P1: Proponer oferta?] -->|No ofrecer| O1[Sin cambios]
- A4 -->|Ofrecer| B4[P2: Aceptar / Rechazar / Robar]
- B4 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- B4 -->|Rechazar| O3[Sin cambios]
- B4 -->|Robar| C4[P1: ¿Denunciar?]
- C4 -->|No| O4[Transferir solo lo ofrecido a P2]
- C4 -->|Sí| J4[AutoJudge revierte robo (confisca oferta a P2)]
- J4 --> O5[Restituir oferta a P1]
+ Start[G4: Derechos mínimos de propiedad] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> A4{P1: Ofrecer tokens?}
+ A4 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ A4 -->|Proponer oferta| B4[P1 especifica:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+
+ B4 --> C4[UI: Ocultar OfferControls
Mostrar detalles oferta]
+ C4 --> D4{P2: Una sola decisión}
+
+ D4 -->|Aceptar| O2[Intercambiar tokens
→ Auto-avance]
+ D4 -->|Rechazar| O3[Sin cambios
→ Auto-avance]
+ D4 -->|Robar| E4[P2 recibe oferta sin pagar
UI: Ocultar botones P2]
+
+ E4 --> F4{P1: ¿Denunciar al juez?}
+ F4 -->|No denunciar| O4[Robo exitoso
→ Auto-avance]
+ F4 -->|Denunciar| J4[⚖️ AutoJudge actúa]
+
+ J4 --> S1[Paso 1 - Revertir robo:
Devolver tokens ofrecidos a P1]
+ S1 --> S2[Paso 2 - Sanción inversa:
P1 recibe lo pedido sin dar nada
P2 pierde lo pedido]
+ S2 --> O5[Sanción aplicada
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#b71c1c,stroke:#fff,color:#fff
+ style Init fill:#c62828,stroke:#fff,color:#fff
+ style A4 fill:#4527a0,stroke:#fff,color:#fff
+ style B4 fill:#512da8,stroke:#fff,color:#fff
+ style C4 fill:#37474f,stroke:#fff,color:#fff
+ style D4 fill:#455a64,stroke:#fff,color:#fff
+ style E4 fill:#d32f2f,stroke:#fff,color:#fff
+ style F4 fill:#e53935,stroke:#fff,color:#fff
+ style J4 fill:#1b5e20,stroke:#fff,color:#fff
+ style S1 fill:#2e7d32,stroke:#fff,color:#fff
+ style S2 fill:#388e3c,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4 fill:#bf360c,stroke:#fff,color:#fff
+ style O5 fill:#43a047,stroke:#fff,color:#fff
```
### G5 – Cheap talk (conversación previa) – oferta variable
```mermaid
%% g5-cheap-talk.mmd
flowchart TD
- Pre[Chat previo 1 min - no vinculante] --> A5[P1: Proponer oferta?]
- A5 -->|No ofrecer| O1[Sin cambios]
- A5 -->|Ofrecer| B5[P2: Aceptar / Rechazar / Robar]
- B5 -->|Aceptar| O2[Intercambiar según oferta/pedido]
- B5 -->|Rechazar| O3[Sin cambios]
- B5 -->|Robar| O4[Transferir solo lo ofrecido a P2]
+ Start[G5: Cheap Talk] --> Init[P1: 10 pavos
P2: 10 elotes]
+ Init --> Pre[💬 Chat no vinculante
Ambos jugadores pueden escribir
Sin compromisos]
+ Pre --> A5{P1: Ofrecer tokens?}
+ A5 -->|No ofrecer| O1[Sin cambios
→ Siguiente ronda]
+ A5 -->|Proponer oferta| B5[P1 especifica:
- Ofrecer: X pavos, Y elotes
- Pedir: A pavos, B elotes]
+
+ B5 --> C5[UI: Ocultar OfferControls
Mostrar detalles oferta]
+ C5 --> D5{P2: Una sola decisión}
+
+ D5 -->|Aceptar| O2[Intercambiar tokens
→ Auto-avance]
+ D5 -->|Rechazar| O3[Sin cambios
→ Auto-avance]
+ D5 -->|Robar| O4[P2 recibe oferta sin pagar
→ Auto-avance]
+
+ %%{init: {'theme':'dark'}}%%
+ style Start fill:#004d40,stroke:#fff,color:#fff
+ style Init fill:#00695c,stroke:#fff,color:#fff
+ style Pre fill:#00796b,stroke:#fff,color:#fff
+ style A5 fill:#4527a0,stroke:#fff,color:#fff
+ style B5 fill:#512da8,stroke:#fff,color:#fff
+ style C5 fill:#37474f,stroke:#fff,color:#fff
+ style D5 fill:#455a64,stroke:#fff,color:#fff
+ style O1 fill:#424242,stroke:#fff,color:#fff
+ style O2 fill:#2e7d32,stroke:#fff,color:#fff
+ style O3 fill:#757575,stroke:#fff,color:#fff
+ style O4 fill:#d32f2f,stroke:#fff,color:#fff
```
## Emparejamiento en masa (fase Gx)
diff --git a/game-overview.mmd b/game-overview.mmd
index c40f8d4..638dfca 100644
--- a/game-overview.mmd
+++ b/game-overview.mmd
@@ -1,9 +1,68 @@
flowchart TD
- A[Emparejar jugadores al azar] --> B[Asignar roles P1/P2]
- B --> C[Seleccionar variante G1..G5]
- C --> D[Iniciar partida de 3 rondas]
- D --> R1[Ronda 1] --> R2[Ronda 2] --> R3[Ronda 3]
- R3 --> E[Registrar SOLO resultado de R3]
- E --> F[Actualizar leaderboard/analytics]
- F --> G[Reemparejar y posible cambio de roles]
+ A[Demo Play] --> B[Asignar roles P1/P2]
+ B --> C{Jugadores pueden cambiar variante}
+ C --> |G1| G1[Sin derechos de propiedad]
+ C --> |G2| G2[Regla contraproductiva]
+ C --> |G3| G3[Token de repudio]
+ C --> |G4| G4[Derechos mínimos]
+ C --> |G5| G5[Cheap talk]
+
+ G1 --> D[P1: 10 pavos, P2: 10 elotes]
+ G2 --> D
+ G3 --> D
+ G4 --> D
+ G5 --> D
+
+ D --> E[Iniciar ronda]
+ E --> F{P1 ofrece?
❗G2: Si P2 fuerza, DEBE ofrecer}
+ F -->|Sí| G[P1 propone oferta variable]
+ F -->|No| H[No ofrecer → siguiente ronda]
+
+ G --> I{P2 decide}
+ I -->|Aceptar| J[Intercambiar tokens]
+ I -->|Rechazar| K[Sin cambios]
+ I -->|Robar| L[P2 toma oferta sin pagar]
+
+ J --> M[Auto-avance a siguiente ronda]
+ K --> M
+ L --> N{Variante especial?}
+ N -->|G3| O[P1: ¿Asignar vergüenza?]
+ N -->|G4| P[P1: ¿Denunciar?]
+ N -->|Otros| M
+
+ O --> M
+ P --> Q[Sanción: P1 recibe pedido sin dar oferta]
+ Q --> M
+
+ M --> R{Ronda < 3?}
+ R -->|Sí| E
+ R -->|No| S[Fin del juego → Status: FINISHED]
+ S --> T[Cambiar variante reinicia todo]
+
+ %%{init: {'theme':'dark'}}%%
+ style A fill:#1a1a2e,stroke:#fff,color:#fff
+ style B fill:#16213e,stroke:#fff,color:#fff
+ style C fill:#0f3460,stroke:#fff,color:#fff
+ style D fill:#1e3a5f,stroke:#fff,color:#fff
+ style E fill:#2d4059,stroke:#fff,color:#fff
+ style F fill:#533e85,stroke:#fff,color:#fff
+ style G fill:#2e7d32,stroke:#fff,color:#fff
+ style G1 fill:#304ffe,stroke:#fff,color:#fff
+ style G2 fill:#6a1b9a,stroke:#fff,color:#fff
+ style G3 fill:#e65100,stroke:#fff,color:#fff
+ style G4 fill:#b71c1c,stroke:#fff,color:#fff
+ style G5 fill:#004d40,stroke:#fff,color:#fff
+ style H fill:#424242,stroke:#fff,color:#fff
+ style I fill:#1a237e,stroke:#fff,color:#fff
+ style J fill:#2e7d32,stroke:#fff,color:#fff
+ style K fill:#757575,stroke:#fff,color:#fff
+ style L fill:#d32f2f,stroke:#fff,color:#fff
+ style M fill:#37474f,stroke:#fff,color:#fff
+ style N fill:#4527a0,stroke:#fff,color:#fff
+ style O fill:#ff6f00,stroke:#fff,color:#fff
+ style P fill:#c62828,stroke:#fff,color:#fff
+ style Q fill:#b71c1c,stroke:#fff,color:#fff
+ style R fill:#455a64,stroke:#fff,color:#fff
+ style S fill:#212121,stroke:#fff,color:#fff
+ style T fill:#263238,stroke:#fff,color:#fff
diff --git a/game-sequence.mmd b/game-sequence.mmd
index f531482..5e28a62 100644
--- a/game-sequence.mmd
+++ b/game-sequence.mmd
@@ -1,55 +1,75 @@
sequenceDiagram
- participant P1 as Player 1
- participant P2 as Player 2
+ participant P1 as Player 1 (10 pavos)
+ participant P2 as Player 2 (10 elotes)
participant S as Server/Room
- participant AJ as AutoJudge G4
+ participant UI as UI Components
- S->>P1: startRound(gameType, roundNo, role=P1)
- S->>P2: startRound(gameType, roundNo, role=P2)
+ Note over P1,P2: Inicio de Demo Play
+ S->>P1: Asignar rol P1, tokens iniciales
+ S->>P2: Asignar rol P2, tokens iniciales
+
+ Note over UI: Jugadores pueden cambiar variante en cualquier momento
+ P1->>S: setVariant(G1-G5)
+ S->>S: resetRound(), currentRound=1, status=PLAYING
+ S-->>P1: broadcast variantChanged
+ S-->>P2: broadcast variantChanged
- alt G2 (P2 decide forzar)
- P2->>S: decide(force or no_force)
- S-->>P1: forcedOffer = true/false
- else Otros juegos
- Note over P1,P2: Sin decision previa de P2
- end
+ loop Cada Ronda (1-3)
+ alt G2 - Regla contraproductiva
+ Note over P2: Checkbox "Forzar oferta" (activo por defecto)
+ P2->>S: p2Force(true/false)
+ S-->>UI: forcedByP2 = true/false
+ Note over P1: Si forzado, botón "No ofrecer" deshabilitado
+ end
- P1->>S: actionP1(offer or no_offer) - o forzado en G2
- S-->>P2: notifyP1Action(offer or no_offer)
+ alt G5 - Cheap talk
+ Note over P1,P2: Chat no vinculante por 1 minuto
+ end
- alt no_offer
- S-->>P1: outcome(10,10)
- S-->>P2: outcome(10,10)
- else offer
- P2->>S: actionP2(accept / reject / snatch)
- alt accept
- S-->>P1: outcome(15,15)
- S-->>P2: outcome(15,15)
- else reject
- S-->>P1: outcome(10,10)
- S-->>P2: outcome(10,10)
- else snatch
- opt G4 denuncia
- P1->>S: report: yes or no
- alt report=yes
- S->>AJ: aplicar sancion
- AJ-->>S: confiscar tokens P2
- S-->>P1: outcome(10,0)
- S-->>P2: outcome(10,0)
- else report=no
- S-->>P1: outcome(5,20)
- S-->>P2: outcome(5,20)
- end
- opt G3 repudio
- P1->>S: shameToken: assign yes or no
- S-->>P2: actualizar contador verguenza (proxima partida)
+ alt P1 decide ofrecer
+ P1->>S: proposeOffer({offerPavo, offerElote, requestPavo, requestElote})
+ S->>S: Validar tokens disponibles
+ S-->>UI: offerActive = true, ocultar OfferControls
+ S-->>P2: Mostrar oferta y botones de decisión
+
+ P2->>S: p2Action(accept/reject/snatch)
+ S->>S: Prevenir múltiples acciones (if p2Action exists, return)
+
+ alt accept
+ S->>S: Intercambiar tokens ambos lados
+ S->>S: Auto-avanzar ronda
+ else reject
+ S->>S: Sin cambios en tokens
+ S->>S: Auto-avanzar ronda
+ else snatch
+ S->>S: P2 recibe oferta sin pagar
+
+ alt G3 - Token de vergüenza
+ S-->>UI: Mostrar botones vergüenza a P1
+ P1->>S: assignShame(true/false)
+ alt true
+ S->>P2: shameTokens += 1
+ end
+ S->>S: Auto-avanzar ronda
+ else G4 - Derechos mínimos
+ S-->>UI: Mostrar botones denuncia a P1
+ P1->>S: report(true/false)
+ alt true
+ S->>S: Revertir robo
+ S->>S: P1 recibe pedido sin dar oferta (sanción inversa)
+ end
+ S->>S: Auto-avanzar ronda
+ else Otros
+ S->>S: Auto-avanzar ronda
end
+ end
+ else P1 no ofrece
+ P1->>S: noOffer()
+ S->>S: p1Action = "no_offer"
+ S->>S: Auto-avanzar ronda
end
end
- opt Round3 - persistir resultado R3
- S->>S: actualizar leaderboard y analytics
- end
- S-->>P1: endRound
- S-->>P2: endRound
- end
+ Note over S: Después de ronda 3
+ S->>S: gameStatus = FINISHED
+ Note over UI: Al cambiar variante, reinicia todo
diff --git a/game-state-machine.mmd b/game-state-machine.mmd
index 3141e46..d000b42 100644
--- a/game-state-machine.mmd
+++ b/game-state-machine.mmd
@@ -1,20 +1,70 @@
stateDiagram-v2
- [*] --> Lobby
- Lobby --> Matching : join/ready
- Matching --> Setup : asignar roles + variante
- Setup --> PreChat : si G5 (cheap talk)
- Setup --> Round1 : si no G5
- PreChat --> Round1 : fin ventana chat (1 min)
- Round1 --> Round2 : resultado cerrado
- Round2 --> Round3 : resultado cerrado
- Round3 --> PostGame : resultado cerrado
- PostGame --> Commit : registrar solo R3
- Commit --> Rematch : liberar jugadores
- Rematch --> [*]
-
- note right of Round1
- Las decisiones pueden ser:
- - Secuenciales (G1,G2,G3,G4,G5)
- - Simultáneas (si en el futuro aplica)
+ [*] --> DemoPlay
+
+ DemoPlay --> Waiting : quickPlay()
+ Waiting --> Playing : 2 jugadores conectados
+
+ state Playing {
+ [*] --> VariantSelection
+ VariantSelection --> RoundActive : seleccionar G1-G5
+
+ state RoundActive {
+ [*] --> OfferPhase
+
+ state OfferPhase {
+ [*] --> CheckForce
+ CheckForce --> ForcedOffer : G2 && forcedByP2
+ CheckForce --> OptionalOffer : !forcedByP2
+ ForcedOffer --> ProposeOffer : debe ofrecer
+ OptionalOffer --> ProposeOffer : ofrecer
+ OptionalOffer --> NoOffer : no ofrecer
+ }
+
+ ProposeOffer --> P2Decision : offerActive=true
+ NoOffer --> NextRound : auto-avance
+
+ state P2Decision {
+ [*] --> WaitingP2
+ WaitingP2 --> Accept : p2Action
+ WaitingP2 --> Reject : p2Action
+ WaitingP2 --> Snatch : p2Action
+ }
+
+ Accept --> TokenExchange : intercambiar
+ Reject --> NoChange : sin cambios
+ Snatch --> CheckVariant : robar tokens
+
+ TokenExchange --> NextRound : auto-avance
+ NoChange --> NextRound : auto-avance
+
+ state CheckVariant {
+ [*] --> CheckG3G4
+ CheckG3G4 --> ShameDecision : G3
+ CheckG3G4 --> ReportDecision : G4
+ CheckG3G4 --> NextRound : otros
+ }
+
+ ShameDecision --> NextRound : asignar/no asignar
+ ReportDecision --> Sanction : denunciar
+ ReportDecision --> NextRound : no denunciar
+ Sanction --> NextRound : aplicar sanción inversa
+ }
+
+ NextRound --> RoundActive : round < 3
+ NextRound --> Finished : round = 3
+ }
+
+ Finished --> VariantSelection : cambiar variante reinicia
+ Playing --> Finished : 3 rondas completadas
+
+ note right of VariantSelection
+ Cualquier jugador puede
+ cambiar variante en
+ cualquier momento
+ end note
+
+ note right of P2Decision
+ Una sola acción
+ permitida por oferta
end note