Recreando el Parqués/Parchis en ReactJS - Segunda Parte
Tags: react, pwa, serviceworkers, websockets
Published: 2020-03-07 16:43:17

---
title: Recreando el Parqués/Parchis en ReactJS - Segunda Parte
published: true
description: Parchis ReacJS
tags: React, PWA, ServiceWorkers, WebSockets
---

Esta es la segunda parte relacionada a la experienca de desarollo del juego conocido como el [parchís](https://es.wikipedia.org/wiki/Parch%C3%ADs), en la primera parte se pudo ver las reglas que lo rigen, así como el stack de tecnologías que componen el juego.

### Modalidades de juego

El juego cuenta con diferentes modalidades para ser jugado como son:

**Modo Offline:** Permite que el juego sea jugado en un mismo dispositivo, a su vez se puede tener las siguientes variaciones:

![Image_04_modo_offline](https://raw.githubusercontent.com/Jorger/parchisi-game/master/images_tutorial/img_04_modo_offline.gif?token=AAAHKYQRPOHOEGCQRJDUX726KQ5O4)

* **Jugar dos o tres usuarios:** Permite que en un mismo dispositivo puedan jugar de dos a tres jugadores, en este caso cada usuario hará su movimiento, útil cuando no se tiene conexión.

* **Jugar versus un Bot:** Opción que permite que un usuario pueda jugar contra la máquina, potencialmente puede existir varias variaciones como por ejemplo, humano versus bot, humano versus dos bots, humano, humano versus bot, etc.

* **Jugar entre bots:** Este es un modo especial, en el cual el jugador es sólo un espectador, ya que los únicos que jugarán son bots, este modo fue útil para las pruebas ya que se podía dejar jugando varios bots al mismo tiempo y así crear una especia de prueba de carga, de esta forma se evidenciaron varios bugs, ya que creaba escenarios que no se habían teniendo en cuenta, es decir, funciono como un random testing.

**Modo Online:** Permite dos a cuatro jugadores puedan jugar en realtime en su propio dispositivo, este modo hace uso de websockets/Socket.io, permitiendo que cada usuario envié sus movientos a los demás jugadores

![Image_04_modo_online](https://raw.githubusercontent.com/Jorger/parchisi-game/master/images_tutorial/Play_two_users.gif?token=AAAHKYT4MJQRW3HBNPSAV6K6KRAUI)

Otras modalidades son:

* **Play with friends:** Permite la creación de salas privadas, en las cuales pueden jugar dos a cuatro jugadores.

![Play_with_friends](https://raw.githubusercontent.com/Jorger/parchisi-game/master/images_tutorial/Play_with_friends.gif?token=AAAHKYVA5HZ73VZRVH7TVKC6KWE6W)


* **Party mode:** Modo especial en el cual se fusionan los tipos offline y online, en este caso los jugadores harán uso de un sólo tablero y las acciones de movimientos y lanzamiento de dados se podrían hacer desde un dispositivo móvil.

![Party_mode](https://raw.githubusercontent.com/Jorger/parchisi-game/master/images_tutorial/party_mode_gif.gif?token=AAAHKYT44J6LJT4SR5CH7KK6KWF52)

La motivación para este modo, es entregar la posibilidad que el juego sea utilizado en un entorno social, por ejemplo una reunión/fiesta, en la cual los participates quieran jugar al parchís, pero no lo deseen hacer en su mismo dispositivo, sino que tal vez proyectar el tablero y hacer usos de sus móviles para controlar el juego.

Otras características que posee este modo son:

* **Emojis:** Permite que un jugador pueda expresarse a través del uso de emojis y mensajes predeterminados durante una partida, igualmente existe la opción para silenciar un usuario si fuese necesario.

![Emojis](https://raw.githubusercontent.com/Jorger/parchisi-game/master/images_tutorial/Emojis.gif?token=AAAHKYQRD2XMZ4M56PFT7JS6KWGJ2)

* **Chat:** Igualmente existe un chat desde el cual los usuarios podrán conversar durante una partida online, los mensajes escritos no son almacenados.

---

### Arquitectura Sockets.


Como lo comentaba el juego cuenta con el modo online, el cual permite que dos a cuatro jugadores puedan jugar en tiempo real, esto es logrado gracias al uso de Websockets, haciendo uso de la librería Socket.io para el manejo de los mismos.


![Dados](https://raw.githubusercontent.com/Jorger/parchisi-game/master/images_tutorial/envia_dado.gif?token=AAAHKYQVYXOHZWFXP77L4AK6KWINO)

En el diagrama se muestra un ejemplo de como sería la acción cuando un usuario realiza la acción de lanzar los dados, la obtención de este valor (el valor de los dados) se obtiene en cada cliente, este valor es enviado al backend a través de los sockets, previamente se había creado una sala, si se eligió la opción **Play with two Players** o **Play with four Players**, la creación de la sala se hará de forma aleatoria, es decir, los jugadores se eligieran de forma aleatoria entre los usuarios que se encuentren disponibles, si se elige el modo **Play with friends**, se creará una sala privada y sólo ingresarán los jugadores que cuenten con el código de la sala.

Como se puede apreciar en la gráfica, el valor del dado es enviado, y este es enviado a cada uno de los clientes (incluido el que hizo la acción), esto con el fin de sincronizar el giro de los dados en cada uno de los jugadores que se encuentre conectados.

Está misma acción se realiza para la acción de mover una ficha, las validaciones del tablero se hará en cada cliente, es decir, en los sockets se envían acciones como:

* Girar dados: Enviando el valor que tendrá cada dado.
* Mover ficha: Indicará la ficha a mover y el número de posiciones que se moverá.

Acciones como sacar de la cárcel, enviar a la cárcel, terminar el juego, entre otras es realizado en cada cliente.

#### Modo Party.

EL modo party es la combinación entre el modo offline y el online, la arquitectura de los sockets para está modalidad varían un poco en relación a la anterior.


![artquitectura_modo_party](https://raw.githubusercontent.com/Jorger/parchisi-game/master/images_tutorial/diagrama_modo_versus.gif?token=AAAHKYTIM6KBPABERNP5TRS6KWJYK)


Como se aprecia en la gráfica, existirá un sólo tablero, las acciones de lanzar los dados y de mover las fichas, serán realizadas desde otros clientes, los cuales no realizan acción alguna, las validaciones de movimientos, bloqueos y demás se realizan en el tablero central.

Cuando un cliente envía una acción a realizar, por ejemplo lanzar un dado, envía una petición al backend a través de los socktes, este se comunica a la vez con el tablero, el cual recibe la acción a realizar, una vez que haya terminado de realizar una acción, por ejemplo mover una ficha, envía dicha información al backend vía websockets, está a su vez es propagada a cada unos de los clientes/controles que se encuentren conectados.

### Manejo del "emparejamiento/matchmaking" usuarios.



---

### Desafíos.

El desarrollo del juego presentó varios desafíos, algunos de los cuales fueron:

* Creación del escenario a través de CSS y ubicación de cada unas de las celdas en el escenario de forma dinámica.

* Establecer el movimiento de las fichas en el board, validar cuando se encuentra más de una ficha en una celda y establecer posiciones que evite que una ficha quede sobre otra.

* Manejo del estado de cada una de las fichas, las cuales tuvieran "conocimiento" en que posición/celda se encuentra, el tipo de celda (salida, seguro, meta).

* Sincronización de los eventos realizados a través de los websockets.

* Hacer distinción entre el router manejado en el front, versus el router manejado en el backend.

Para el front se hizo uso de [Reach Router](https://reach.tech/router) para así definir diferentes tipos de páginas, pero igualmente se hizo uso del [router de ExpressJS](https://expressjs.com/en/guide/routing.html), en algún momento existió un conflicto entre las rutas, es decir, cuando se ponía una ruta que hacía referencia al llamado en el backend, quien capturaba la ruta era el front, mostrando que dicha ruta no existía, se hacía necesario crear algunas rutas con las cuales se podía hacer referencia a llamadas del API en el backend, además de rutas necesarias para la autenticación social.

Para ello se creo un `namespace` que hacía referencia a aquellas rutas que se manejarían a nivel de servidor, toda ruta que iniciaría con `/api/auth` correspondían a rutas en el backend, las demás rutas serían manejadas a nivel de front.

Ejemplo ruta en backend:

```js
router.get(
  "/api/auth/github",
  passport.authenticate("github", { scope: ["user:email"] })
);
```

Rutas que no son manejadas en el backend:

```js
// Maneja los demás requests que no se ajusten a los rutas definidas
app.get("*", (req, res) => {
  res.sendFile(path.join(__dirname + "/build/index.html"));
});
```
---

* Definir que aquellas rutas que fueran correspondientes a llamados al backend o rutas relacionadas a autenticación, no entrarán en la estrategia de cacheo del ServiceWorker.

Por defecto CRA, maneja [workbox](https://developers.google.com/web/tools/workbox) para el manejo y configuración de los serviceworkers, esté está configurado como `cache firts` por lo que toda ruta y/o assets será chacheado, esto es muy bueno ya que permite que la aplicación pueda seguir funcionando incluso si el usuario no tiene conexión a internet, pero al chachear todo también existía el problema que rutas relacionadas a llamados al API y rutas relacionadas a la autenticación fueran chacheadas, para evitar esto se podría realizar un `eject` de CRA exponiendo toda la configuración que éste tiene, pero se perdería los beneficios que CRA entrega, para evitar ello existe el paquete [react-app-rewired](https://www.npmjs.com/package/react-app-rewired) el cual permite reescribir algunas de las reglas que CRA tiene, sin la necesitad de realizar un `eject`, para ello se debe realizar el cambio en el comando que crea el build `npm run build`

**Antes**

```json
"build": "react-scripts build
```


**Después**

```json
"build": "react-app-rewired build
```

Y crear un archivo de configuración, en el cual se indica qué reglas se deben reescrbir, en este caso particular relacionado a las rutas que no deben entrar en la estrategia de cacheo.

Toda ruta que inicie con `/api` no se chacheará

```js
// config-overrides.js
module.exports = function override(config, env) {
  const swPrecacheConfig = config.plugins.find(
    plugin => plugin.constructor.name === "GenerateSW"
  );
  const blacklist = swPrecacheConfig.config.navigateFallbackBlacklist;
  blacklist.push(/\/api\//);
  return config;
};

```

---

* Ejecutar el backend y el front al mismo tiempo.

CRA, por defecto monta un servidor, usualmente en el puerto 3000, (aunque puede ser cambiando `PORT=3001 react-scripts start` por ejemplo), en este caso para permitir hacer la autenticación social y el manejo de sockets era necesario tener otro servidor, CRA entrega una solución la cual es estableciendo un [`proxy`](https://create-react-app.dev/docs/proxying-api-requests-in-development/) para hacer uso de este es necesario establecerlo en el `package.json`:

```json
"proxy": "http://localhost:5000",
```

En este caso el servidor correrá en el puerto 5000.

### Conslusiones.

* Este tipo de aplicaciones/juegos, es posible ser desarrollado en cualquier librería, no es exclusivo a ReactJS.
* El manejo de componentes ayudó a un rápido desarrollo del juego.
* Existe una gran variedad de paquetes/librerías que ayudan a un rápido desarrollo.
* Aprender nuevas tecnologías/lenguajes/librerías a través de desarrollos de este tipo de actividades es divertido y desafiante.