Apps multijugador
Los juegos de tablero y de dados de ZooBC los juegan de dos a cuatro personas, y cada movimiento es una transacción que todos los nodos comprueban con las mismas reglas. Las apuestas forman un bote, que el protocolo paga cuando termina la partida, menos un rake del 1 % para el fondo de apps, salvo que la partida termine en tablas.
Abrir y unirse
Un jugador abre una partida con CreateApp, eligiendo el tipo y de 2 a 4 asientos (la batalla naval siempre tiene exactamente 2), y paga la primera apuesta. La partida queda abierta (Open). Cada JoinApp paga una apuesta igual, y cuando se ocupa el último asiento la partida pasa a estar activa (Active). Un rival designado opcional convierte la partida en un desafío directo al que solo esa cuenta puede unirse.
Un asiento necesita una cuenta de 36 bytes, como una cuenta nativa de ZooBC. Las cuentas con direcciones de 24 bytes, los tipos de Ethereum y de hash de Bitcoin, no pueden ocupar un asiento, aunque el mensaje de error diga «multiplayer apps require a ZBC account» (claves y tipos de cuenta). Las apuestas en solitario aceptan cualquier cuenta.
Quién mueve primero
Quién empieza puede importar, así que nadie puede saberlo ni dirigirlo de antemano. Cuando se ocupa el último asiento, el turno queda pendiente: nadie tiene el reloj en marcha, y todo movimiento es una operación nula. Dos bloques después, el resolutor sortea el asiento que abre la partida, como un hash de la semilla de ese bloque y del id de la app tomado módulo el número de asientos. El productor del bloque con la última unión conoce su propia semilla, pero no la semilla de dos bloques después, así que no puede incluir ni dejar fuera la unión según quién empezaría. Ni el creador ni el último en unirse empiezan por regla. La batalla naval es la excepción: el que se une mueve primero, publicando el compromiso de su tablero.
En los cuatro juegos de dados (ludo, pig, race y monopoly-lite) un movimiento no se aplica en el bloque que lo incluye. Se guarda como pendiente y lo aplica el bloque siguiente, con la semilla de ese bloque y usando como clave el id de la transacción del movimiento, de modo que el productor que incluyó el movimiento nunca ve la tirada. Solo se permite un movimiento pendiente a la vez, y un movimiento que entretanto se ha vuelto ilegal se descarta.
El reloj de movimientos
Cuando se une el último asiento, y otra vez después de cada movimiento aceptado, el plazo se fija 240 bloques más adelante, aproximadamente una hora. El jugador al que le toca debe mover antes, o enviar un AppMove con un movimiento vacío: un mantenimiento pagado que aplaza el plazo otros 240 bloques. Un movimiento de un jugador que no tiene el reloj en marcha, o un movimiento ilegal, se rechaza al enviarlo; si uno llega a un bloque, es una operación nula que no cuesta comisión.
Cómo termina una partida
| Final | Cómo | Pago |
|---|---|---|
| Victoria | un movimiento gana la partida | el bote menos el rake del 1 %, para el ganador |
| Empate | un movimiento termina la partida en tablas | cada asiento recupera su apuesta; sin rake |
| Rendición | un jugador envía ResignApp | el bote menos el rake, repartido a partes iguales entre los demás asientos, con cualquier resto para el primero de ellos |
| Tiempo agotado | un jugador sentado que no tiene el reloj en marcha envía ClaimAppTimeout, desde el plazo + 1 | el bote menos el rake, repartido entre todos los asientos salvo el que tenía el reloj en marcha |
El rake es floor(bote × 100 ÷ 10 000), el 1 % del bote: dos jugadores que apuestan 1 ZBC cada uno forman un bote de 2 ZBC, y el ganador recibe 1.98 ZBC en el bloque del movimiento ganador. El productor del bloque no toma nada del bote. Nada termina por sí solo: tras un plazo vencido, la partida espera hasta que un jugador decide enviar la reclamación, y nadie, ni siquiera la ZooBC Foundation, puede cancelar una partida.
Los motores
El motor de cada juego forma parte del nodo, con algunas simplificaciones que conviene conocer:
- el ajedrez no tiene enroque ni captura al paso, y los peones siempre coronan en dama;
- en las damas la captura es obligatoria y los saltos múltiples continúan;
- en el reversi se salta el turno de un asiento que no tiene ningún movimiento legal;
- en puntos y cajas se concede otro movimiento tras completar una caja;
- el pig se gana al llegar a 100, y el race, el juego de serpientes y escaleras, termina en la casilla 49;
- en el ludo cada asiento mueve cuatro fichas;
- en el monopoly-lite cada asiento empieza con 1500 y cobra 200 al pasar por la SALIDA.
Batalla naval: secretos en una cadena pública
La batalla naval necesita información oculta en una cadena en la que todo es público, y la consigue mediante compromiso y revelación. Antes de jugar, cada jugador elige una sal secreta de 32 bytes para cada una de las 100 casillas de un tablero de 10 × 10 y publica SHA3-256(is_ship ‖ salt) para cada casilla: 100 hashes, 3200 bytes en total. El creador envía su compromiso con CreateApp, y el que se une envía el suyo como su primer movimiento. Como cada sal es aleatoria, los hashes no revelan nada.
Un jugador dispara con el movimiento [0, cell]. El dueño de ese tablero debe revelar la casilla pendiente con [1, is_ship, salt], y cada nodo comprueba que estos den como hash el valor comprometido. Una mentira da un hash distinto y se rechaza, así que el dueño solo puede decir la verdad, o quedarse sin tiempo y perder ante un ClaimAppTimeout. El primer jugador que acierta en 17 casillas de barco gana. Comprometer menos casillas de barco no sirve de nada: cuando quien dispara ha hecho sus 100 disparos y se han revelado menos de 17 casillas de barco, quien dispara gana.