- Add variable offer system where P1 can offer any amount of tokens - Players start with 10 tokens each (P1: pavos, P2: elotes) - Implement offer/request mechanism with token validation - Auto-advance rounds after P2 actions or P1 no-offer - G2: Force offer by default, disable no-offer button when forced - G3: Wait for shame decision after snatch before advancing - G4: Implement inverse sanction (P1 gets requested without giving offered) - Reset rounds to 1 when changing game variants - Fix OfferControls responsiveness issues - Hide offer controls after active offer - Update all G1-G5 components with proper offer flow
8.3 KiB
8.3 KiB
SnatchGame – Diagramas Mermaid
Este índice reúne los diagramas claves para implementar el juego y verificar los flujos. Puedes abrir cada .mmd con la extensión oficial de Mermaid o verlos embebidos abajo.
Visión general del ciclo
%% 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]
Orquestación global (200 jugadores, G1->G5)
%% tournament-orchestration.mmd
flowchart TD
Start[Init torneo] --> PhaseG1[Phase G1: iniciar]
PhaseG1 --> MatchG1[Emparejar 200 jugadores al azar]
MatchG1 --> RoomsG1[Crear rooms P1-P2 y asignar roles]
RoomsG1 --> PlayG1[Jugar 3 rondas en paralelo]
PlayG1 --> CommitG1[Commit solo resultado de ronda 3]
CommitG1 --> WaitAllG1[Esperar que TODOS terminen]
WaitAllG1 --> RematchG2[Reemparejar todos al azar]
RematchG2 --> PhaseG2[Phase G2: iniciar]
PhaseG2 --> MatchG2[Emparejar 200 jugadores al azar]
MatchG2 --> RoomsG2[Crear rooms y roles]
RoomsG2 --> PlayG2[Jugar 3 rondas en paralelo]
PlayG2 --> CommitG2[Commit ronda 3]
CommitG2 --> WaitAllG2[Esperar TODOS]
WaitAllG2 --> RematchG3[Reemparejar]
RematchG3 --> PhaseG3[Phase G3: iniciar]
PhaseG3 --> MatchG3
MatchG3 --> RoomsG3
RoomsG3 --> PlayG3
PlayG3 --> CommitG3
CommitG3 --> WaitAllG3
WaitAllG3 --> RematchG4
RematchG4 --> PhaseG4[Phase G4: iniciar]
PhaseG4 --> MatchG4
MatchG4 --> RoomsG4
RoomsG4 --> PlayG4
PlayG4 --> CommitG4
CommitG4 --> WaitAllG4
WaitAllG4 --> RematchG5
RematchG5 --> PhaseG5[Phase G5: iniciar]
PhaseG5 --> MatchG5
MatchG5 --> RoomsG5
RoomsG5 --> PlayG5
PlayG5 --> CommitG5
CommitG5 --> End[Fin del torneo]
Máquina de estados (Room/Partida)
%% 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)
end note
Secuencia por ronda (cliente-servidor)
%% game-sequence.mmd
sequenceDiagram
participant P1 as Player 1
participant P2 as Player 2
participant S as Server/Room
participant AJ as AutoJudge G4
S->>P1: startRound(gameType, roundNo, role=P1)
S->>P2: startRound(gameType, roundNo, role=P2)
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
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
end
end
opt G3 repudio
P1->>S: shameToken: assign yes or no
S-->>P2: actualizar contador vergüenza (próxima partida)
end
end
end
S-->>P1: endRound
S-->>P2: endRound
Variantes de juego
G1 – Sin derechos de propiedad (oferta variable)
%% 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]
G2 – Regla contraproductiva (P2 puede forzar) – oferta variable
%% 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]
G3 – Token de repudio (vergüenza) – oferta variable
%% 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]
G4 – Derechos mínimos de propiedad (juez) – oferta variable
%% 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]
G5 – Cheap talk (conversación previa) – oferta variable
%% 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]
Emparejamiento en masa (fase Gx)
%% matchmaking.mmd
sequenceDiagram
participant OR as Orchestrator
participant MM as Matchmaker
participant P as PlayerPool
participant R as RoomFactory
OR->>MM: start phase (Gx) for ALL
MM->>P: collect all available players (200)
MM->>P: shuffle randomly
loop pair players
MM->>R: create room with pair (P1,P2) and roles
R-->>MM: roomId
end
MM-->>OR: rooms created for all pairs
OR->>R: broadcast startRound(1) to all rooms
Modelo de datos (mínimo)
%% data-model.mmd
classDiagram
class Player {
+string id
+string name
+int pavoTokens // tokens tipo P1
+int eloteTokens // tokens tipo P2
+number shameTokens // visible en próxima partida
}
note for Player "Scoring: como P1 => pavo*1 + elote*2; como P2 => elote*1 + pavo*2; total = suma"
class GameSession {
+string id
+string gameType // G1..G5
+string player1Id
+string player2Id
+int currentRound // 1..3
+Round[] rounds // length=3
+Date createdAt
}
class Round {
+int index // 1,2,3
+string p1Action // offer|no_offer|forced_offer
+string p2Action // accept|reject|snatch|null
+boolean forcedByP2 // G2
+boolean reported // G4
+boolean shameAssigned // G3
+number outcomeP1
+number outcomeP2
+boolean isThird
}
class LeaderboardEntry {
+string playerId
+number scoreAsP1 // P1: pavo*1 + elote*2
+number scoreAsP2 // P2: elote*1 + pavo*2
+number aggregateScore // scoreAsP1 + scoreAsP2
+Date updatedAt
}
Player "1" -- "0..*" GameSession : participa
GameSession "1" o-- "3" Round : incluye
Player "1" -- "0..*" LeaderboardEntry : puntuación
Notas:
- Solo el resultado de la R3 se agrega al leaderboard/analytics.
- G2 introduce
forcedByP2; G3,shameAssignedy contador visible en la siguiente partida; G4,reportedy sanción del juez. - El servidor es autoritativo; clientes no mutan estado.