Juego tipo escape room virtual
Table of Contents
Durante la cuarentena del COVID-19 ha habido tiempo para casi todo. Después de jugar a un par de juegos escape room virtuales (paradoxroom, escaperoomdigital) me ha parecido interesante inventarme el mio propio.
El código fuente está oculto, para que no se vean las soluciones a los acertijos.
Opciones para la implementación del juego
Solo dispongo de alojamiento web estático (Github Pages y similar), así que hay que implementar la lógica en el lado cliente. Para que cada página no tenga la solución en el código html, hay dos soluciones
- Ofuscar la respuesta correcta: La respuesta puede estar incluida en la página, pero no en texto legible.
- Preguntar al servidor si la respuesta es correcta: Aunque sea un hosting estático, el servidor responde con un código HTTP 200 si el recurso existe, u otro código si no existe.
Opción utilizada
Cuando el jugador introduce la respuesta, la normalizo pasándola a mayúsculas y quitando caracteres sobrantes, como espacio, guión, acentos…
function normalizaRespuesta(str){ let sustituciones = { " " : "", "-" : "", "," : "", "." : "", "Á" : "A", "É" : "E", "Í" : "I", "Ó" : "O", "Ú" : "U", "Ü" : "U", "Ñ" : "N" }; letras = Array.from(str.toUpperCase()); let sanitized = letras.map( c => typeof sustituciones[c] != "undefined" ? sustituciones[c] : c ).join(""); return sanitized; }
Cada página web de la aventura está en un directorio que tiene por nombre la solución del paso anterior. Por ejemplo, si el paso 1 tiene como respuesta correcta El cantar del mío Cid, esta respuesta se normaliza a ELCANTARDELMIOCID
y el siguiente paso se almacena en la URL ../ELCANTARDELMIOCID/index.hml
.
Utilizo el siguiente script para saber si un recurso existe:
function existeURL(url){ let request = new XMLHttpRequest(); request.open('GET', url, false); request.send(null); let found = request.status != 404; return found; }
De esta forma, se detecta una respuesta correcta porque existe una página en el servidor con ese nombre, y se salta a esa página. Más serverless no puede ser 😎
Generación de páginas
Cualquier generador de sitios estáticos valdría para implementar el juego. Yo he elegido org-publish, para no salir de emacs.
La configuración se basa en dos proyectos: uno que transforma los ficheros org
en html
, y otro que copia el resto de recursos (js
, css
, zip
…)
(setq org-publish-project-alist '( ("aventura-org" :base-directory "/home/alvaro/github/aventura/org/" :base-extension "org" :publishing-directory "/home/alvaro/github/aventura/public/" :recursive t :publishing-function org-html-publish-to-html :headline-levels 4 ; Just the default for this project. :auto-preamble t ) ("aventura-static" :base-directory "/home/alvaro/github/aventura/org/" :base-extension "css\\|js\\|png\\|jpg\\|gif\\|pdf\\|mp3\\|ogg\\|swf\\|html\\|svg\\|zip\\|ttf" :publishing-directory "/home/alvaro/github/aventura/public/" :recursive t :publishing-function org-publish-attachment ) ("aventura" :components ("aventura-org" "aventura-static") ) ))
Para generar las páginas utilizo esta función interactiva:
(defun publicar-aventura() (interactive) (delete-directory "/home/alvaro/github/aventura/public/" t) (org-publish-remove-all-timestamps) (org-publish-project "aventura" t))