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))