1997 — 2026

El Castillo:
Una Arqueología Web

Veintinueve años separan dos versiones de un mismo reto lógico. Este documento es la cápsula del tiempo que explica cómo se construyó la web interactiva antes de que existieran los frameworks, el cloud, y en muchos casos, antes de que JavaScript fuera de confianza.

Reparto original 1997
Hada original de El Castillo (1997) Genio original de El Castillo (1997)
Reparto 2026
Hada y Genio en la versión 2026 de El Castillo
1997
2026

Los arquitectos del Castillo

El Castillo nació como Proyecto Fin de Carrera en la Facultad de Informática de la Universidad de Málaga. Dos catedráticos de disciplinas distintas —lógica filosófica y sistemas informáticos— se unieron para crear algo que iba mucho más allá de un trabajo académico: un puente entre el razonamiento formal y la tecnología emergente de la web interactiva.

La base artística original se mantiene como referencia histórica: los dibujos de 1997, realizados a mano por Elena Bueno Vallejo, siguen siendo el origen visual del universo de El Castillo.

Director de Contenido · Lógica

Alfredo Burrieza Muñiz

Catedrático de Lógica y Filosofía de la Ciencia

Concibió y diseñó todos los acertijos lógicos del juego, inspirándose en los trabajos del matemático y lógico Raymond Smullyan —célebre por sus libros de puzzles de caballeros y escuderos que siempre dicen la verdad o siempre mienten—. Cada uno de los doce niveles esconde un teorema de lógica proposicional envuelto en la piel de un enigma narrativo.

Director Técnico · Web pioneer

Ricardo Conejo Muñoz

Catedrático de Lenguajes y Ciencias de la Computación

Director de la implementación y de la tesis doctoral del autor. Fue el webmaster del departamento cuando en España apenas existían cinco páginas web, sentando las bases para que David comenzara su andadura en la programación web. Su visión de la informática educativa y su conocimiento pionero de las tecnologías de Internet hicieron posible que este proyecto existiera.

Arte original · Ilustración manual

Elena Bueno Vallejo

Autora de los dibujos originales de El Castillo (1997)

Los personajes y escenas del juego original fueron dibujados a mano por Elena Bueno Vallejo, pieza esencial para la identidad visual del proyecto. Su trabajo artístico fijó la estética que esta versión 2026 respeta y homenajea.

📚

Sobre Raymond Smullyan (1919–2017): Matemático, lógico y mago estadounidense, autor de ¿Cómo se llama este libro? (1978) y El Señor de las Islas Misteriosas. Sus puzzles de islas donde los caballeros siempre dicen la verdad y los escuderos siempre mienten son hoy un clásico de la lógica recreativa. Los acertijos de El Castillo siguen exactamente esa tradición: premisas condicionales reales cuya solución requiere razonamiento deductivo puro.

Cuando el servidor era el único inteligente

En 1997 la World Wide Web estaba apenas en pañales como plataforma de aplicaciones interactivas. Los navegadores dominantes eran Netscape Navigator 3 e Internet Explorer 3, y JavaScript —recién nacido en 1995— era considerado inseguro, inconsistente entre navegadores y totalmente inadecuado para manejar lógica de negocio real.

La respuesta arquitectónica de la época fue clara: toda la inteligencia vive en el servidor. Cada interacción del usuario —pulsar un botón, marcar un checkbox, elegir una opción— enviaba un formulario HTTP al servidor. Una aplicación en C leía los parámetros, calculaba el nuevo estado, y devolvía HTML puro generado dinámicamente. Esto es lo que se denominó CGI: Common Gateway Interface.

🌐

HTTP sin estado

Cada petición era absolutamente independiente. No existían sesiones nativas. El estado del usuario (nivel actual, vidas restantes) debía pasarse explícitamente en cada URL o en campos ocultos del formulario.

Latencia como Gameplay

Cada click en una "zona sensible" enviaba el formulario al servidor, que generaba la pantalla siguiente. El tiempo de respuesta de la red era parte involuntaria de la experiencia de usuario.

🖥️

HTML 3.2 estático

Sin CSS en cascada, sin layout moderno. Tablas HTML para maquetar, atributos WIDTH y BGCOLOR directamente sobre los tags. Dos niveles de fuente. Nada de animaciones.


experto.c: el corazón del castillo

El fichero EXPERTO.C es el alma original del proyecto. Un programa ANSI C compilado como ejecutable que el servidor web invocaba en cada petición. Recibía parámetros vía stdin (método POST) o la variable de entorno QUERY_STRING (método GET), procesaba la lógica del juego y escribía HTML completo a stdout. El servidor enviaba esa salida directamente al navegador.

💡

El protocolo CGI era brutalmente simple: el servidor ejecutaba el binario, pasaba los datos como variables de entorno y capturaba su stdout. La primera línea era siempre Content-type: text/html seguida de una línea en blanco. El resto era HTML puro. No había framework, no había ORM, no había nada.

EXPERTO.C — main() y tipos de dato
/* ============================================================
   EXPERTO.C — Motor principal del juego El Castillo (1997)
   Compilado con Borland C para Windows NT / UNIX CGI
   ============================================================ */

#define NIVE         1  /* Solicitud de pantalla de nivel         */
#define NUEVO        2  /* Creación de usuario nuevo              */
#define NUEVAVIDA    6  /* El jugador ha perdido una vida         */
#define VERRECORDS   8  /* Mostrar tabla de records               */
#define MARCA       '{' /* Carácter centinela → sustituir por ID  */
#define MARCACGI    '^' /* Centinela → sustituir por URL del CGI  */
#define MARCAVIDAS  '`' /* Centinela → inyectar corazones de vida */
#define NUMVIDAS     3

typedef struct NIV {
    int    n_opc;        /* Número de opciones del nivel       */
    OPCION opc[5];     /* Hasta 5 puertas posibles           */
    char   lista[4];   /* Selección del jugador (N7 y N12)   */
} NIVEL;

int main() {
    read_cgi_input(&entries);          /* Lee parámetros POST/GET            */
    printf("Content-type : text/html \n\n");  /* Cabecera HTTP obligatoria          */

    tipo = atoi(cgi_val(entries, "tipo"));
    switch(tipo) {
        case NIVE:       analizar_nivel();   break;
        case NUEVAVIDA:  ir_sgte_nivel();    break;
        case VERRECORDS: mostrar_records();  break;
    }
    list_clear(&entries);  /* Liberar memoria (no había GC)       */
    exit(0);
}

El programa mantenía la lista de jugadores en ficheros de texto planos. Cada usuario tenía un fichero usuN.dat con su nivel actual, variante, vidas y el historial de los niveles donde había muerto. No había base de datos relacional: el sistema de ficheros era la base de datos.


El truco de los caracteres centinela: { } ^ `

Sin lenguajes de plantillas, sin Jinja2, sin Handlebars, sin JSX —ni siquiera PHP existía en producción estable— el desarrollador de 1997 necesitaba algún mecanismo para parametrizar los ficheros HTML. La solución fue tan sencilla como brillante: reservar caracteres raros como marcadores de inserción.

🔑

La función mostrar_nivel() leía el fichero HTML carácter a carácter. Cuando encontraba un carácter especial, lo sustituía por el valor correspondiente calculado en tiempo real. Era un motor de plantillas artesanal de 40 líneas de C.

mostrar_nivel() — El motor de plantillas de 1997
/* Los ficheros HTML contenían caracteres especiales:
   {  →  sustituir por el ID de usuario (estado de sesión)
   }  →  sustituir por la URL base del servidor
   ^  →  sustituir por la URL del ejecutable CGI
   `  →  inyectar los corazones de vida (IMG tags) + formulario
   ñ  →  mostrar botones de Fin de Juego                         */

char car = fgetc(f);
while(!feof(f)) {
    switch(car) {

        case MARCA:         /* '{' = ID del usuario → sostiene el estado de sesión */
            printf("%s", cad);  /* ej: "usuario=157"  */
            break;

        case MARCABASE:     /* '}' = URL base del servidor                         */
            printf("%s", DIRBASE);
            break;

        case MARCACGI:      /* '^' = URL del ejecutable (ej: /cgi-bin/experto.exe) */
            printf("%s", DIRCGI);
            break;

        case MARCAVIDAS:    /* '`' = Inyectar corazones ❤️ y barra de nivel        */
            for(int i=0; i<vidas; i++)
                printf("<IMG SRC=\"pantallas/vida.gif\" ALIGN=MIDDLE>");
            printf("<IMG SRC=\"pantallas/barra%s.gif\">", usu->niv_actual);
            break;

        default:
            putchar(car);      /* El resto del HTML se copia tal cual              */
    }
    car = fgetc(f);
}

Este patrón —leer stream, detectar marcador, sustituir por valor dinámico— es exactamente lo que décadas después popularizarían Mustache (2009), Handlebars (2011) o Jinja2 bajo los nombres de "interpolación de variables" y "motor de plantillas", con sus dobles llaves {{ variable }}, sus filtros y su herencia de bloques.

🧩

Mustache / Handlebars (2009–11)

Popularizaron {{ nombre }}. La misma idea: un marcador que el motor sustituye por un valor. La diferencia: eran agnósticos al lenguaje y tenían loops y condicionales.

🐍

Jinja2 / Django Templates

Llevaron el concepto al extremo con herencia de bloques ({% extends %}), filtros ({{ var | upper }}) y macros. El equivalente moderno del switch de C.

⚛️

JSX / React (2013)

En JSX la interpolación usa {variable}, una sola llave. El abuelo C de experto.c usaba { por la misma razón: es el carácter más raro que no aparece en HTML puro.


Zonas sensibles: el padre del click-to-play

Antes de que existieran los div posicionados con coordenadas porcentuales, la única forma de crear áreas clicables sobre una imagen era el Image Map de HTML 3.2. Se definía un elemento <MAP> con áreas rectangulares, circulares o poligonales, cada una con sus coordenadas absolutas en píxeles y su enlace destino.

index.html (1997) — Image Map de la pantalla principal
<!-- La imagen de 693×287 píxeles tenía dos zonas clicables:
     una para usuarios nuevos (izquierda) y otra para veteranos (derecha) -->

<map NAME="MAPA">
  <area SHAPE="RECT" COORDS="131,102,251,273" HREF="nuevousu.html">
  <area SHAPE="RECT" COORDS="432,101,549,274" HREF="oldusu.html">
</map>

<img BORDER="0" SRC="pantallas/principi.gif"
     USEMAP="#MAPA" WIDTH="693" HEIGHT="287">
⚠️

El gran problema: las coordenadas eran absolutas en píxeles. Si la imagen se escalaba (por resolución de pantalla diferente, o un usuario con zoom), las zonas quedaban desplazadas por completo. No había concepto de "porcentaje" ni "responsive". En El Castillo 2026 hemos resuelto esto con coordenadas porcentuales calculadas dinámicamente.


El guardián invisible: verifica_fich_usuario()

Un diseño interactivo en web siempre enfrenta el mismo dilema: ¿cómo impedir que un jugador manipule la URL para saltar directamente al nivel 12 sin haber superado los anteriores? En 1997 no existían JWT, ni HMAC, ni tokens firmados. La solución de EXPERTO.C era elegantemente simple: el estado real nunca salía del servidor.

En la URL solo viajaba un número de usuario entero autoincremental (usuario=157). El nivel donde estaba realmente ese jugador vivía en un fichero en disco del servidor (usu157.dat). Aunque el usuario tecleara nivel=12 en la barra de direcciones, el servidor lo ignoraba olímpicamente y leía la verdad desde el fichero.

🛡️

El principio de seguridad: Zero-Trust Client. Todo parámetro que viene del navegador se considera potencialmente falso. La única fuente de verdad es el estado que el servidor custodia. Este principio —que hoy llamamos server-side authoritative state— sigue siendo el fundamento de la seguridad en juegos online modernos como los MMORPGs.

verifica_fich_usuario() — El guardián anti-trampa
/* Llamada en cada petición de nivel antes de mostrar nada.
   Si el usuario manipuló la URL, es expulsado con un aviso. */

void verifica_fich_usuario(char *fichero)
{
    /* Leer el estado REAL del jugador desde su fichero en disco */
    leer_fichero_usuario(&usuario);

    /* Comprobación 1: ¿El nivel de la URL coincide con tu nivel real? */
    if (atoi(usuario.niv_actual) != atoi(nivel_en_url))
        → Error: el jugador intenta ir a un nivel que no le corresponde

    /* Comprobación 2: ¿Es este subnivel uno donde ya moriste? */
    if (muertoen(&usuario, nivcompleto))
        → Error: intentas resetear una pantalla que ya perdiste

    /* Comprobación 3: ¿Te quedan vidas? */
    if (usuario.vidas == 0)
        → Redirige a pantalla de "has perdido todas tus vidas"

    /* Si todo es correcto → mostrar el nivel */

    /* Respuesta al intento de trampa (estaba en mensaje1.htm): */
    /* «No intentes engañarme. Tú no vas por ahí.»             */
}

/* muertoen(): devuelve 1 si el subnivel pedido es uno donde ya cayó */
int muertoen(USUARIO *usuario, char *subnivel_pedido)
{
    for(int i=0; i < (NUMVIDAS - usuario->vidas); i++)
        if (atoi(usuario->muerte[i]) == atoi(subnivel_pedido))
            return 1;  /* Trampa detectada */
    return 0;
}

Adicionalmente, la función alea() garantizaba que al reaparecer en un nivel después de un fallo nunca te tocaba la misma variante donde ya habías muerto. Usaba srand(time()) con un bucle de reintento para esquivar las variantes registradas en el historial del jugador —sin necesidad de ningún algoritmo sofisticado.

🔒

Estado autoritativo (1997)

El fichero usu{N}.dat en el servidor era la única fuente de verdad. El cliente solo tenía su número de ID opaco. Imposible falsificar el progreso sin acceso directo al disco del servidor.

🎲

Anti-repetición con alea()

Al volver a un nivel tras un fallo, rand() % num_variantes con lista negra de subniveles muertos garantizaba que siempre veías un reto fresco, sin poder memorizar la solución.

💬

El mensaje eterno

El fichero mensaje1.htm contenía el aviso de trampa. En cursiva, lacónico y contundente: «No intentes engañarme. Tú no vas por ahí.» En 2026 aún podría servir.


Cómo se rehizo El Castillo con Inteligencia Artificial

Veintinueve años después de la versión original, el proyecto fue resucitado usando un stack completamente diferente al de 1997: ninguna línea de C, ninguna de PHP, ningún servidor propio. En su lugar, dos herramientas de IA trabajaron en tándem para dar vida a la remasterización.

Motor de código · Agente autónomo

Antigravity

Asistente de programación agencial de Google DeepMind

Encargado de toda la arquitectura de la aplicación 2026: diseñó e implementó el motor de juego en Vanilla JS, la integración con Firebase, el sistema de coordenadas porcentuales, el modo Editor para calibrar zonas táctiles, los niveles especiales (ciclo y multiselección) y la migración del lore histórico desde los ficheros .htm de 1997 al nuevo levels.json.

Motor de imagen · Consistencia visual

Nanobanana

Generador de imágenes con IA de alta consistencia

Responsable de la remasterización visual. Recibió las imágenes GIF originales de 1997 como referencia de escena y un prompt maestro de estilo para producir las 72 ilustraciones nuevas, una a una, manteniendo los mismos personajes y la misma arquitectura de sala en cada variante.

El reto: 72 imágenes con consistencia visual

El catálogo visual del juego es de 72 pantallas únicas (12 niveles × 6 variantes cada uno). Cada variante del mismo nivel muestra la misma sala pero con personajes distintos —distintas profesiones, edades o rangos, que son la clave del acertijo lógico—. El desafío: que el fondo, la iluminación, el estilo del bocadillo de diálogo y los personajes recurrentes (el Hada Benéfica, el Genio Maléfico) fueran idénticos en todas las variantes de un mismo nivel, pero distintos entre niveles.

🧪

Crónica real del proceso: primero generamos 30 niveles a mano, uno por uno, con paciencia monástica y café en vena. Cuando vimos que quedaban 42, activamos el modo “trabaja tú, máquina”: construimos un script con la API para automatizar el resto. Resultado: menos clics repetitivos, más control de calidad y cero riesgo de acabar hablando con las antorchas.

🎨

El prompt maestro de remasterización fue redactado para funcionar como una hoja de encargo a un director de arte. En lugar de describir “una sala de castillo” en abstracto, le pedía al modelo que analizara primero el GIF original, extrajera sus elementos clave (escenario, poses, texto de bocadillos, composición), y luego los trasladara al nuevo estilo manteniendo la coherencia espacial al mílimetro.

PROMPT_IMAGENES.md — El prompt maestro de remasterización
Instrucción: Actúa como un artista digital principal encargado de remasterizar
una escena de un juego de aventura gráfica clásico (estilo pixel art de los 90)
a un estilo de ilustración de fantasía moderno, detallado y cinematográfico.

PASO 1 — Analizar la Imagen Antigua:
  ► Escenario: paredes, suelo, puertas, ventanas, antorchas y su ubicación exacta.
  ► Personajes: personaje femenino (hada/princesa) y personaje mágico (genio/mago).
  ► Textos: lee y transcribe verbatim cada bloque de texto de los bocadillos.
  ► Composición: mantén la disposición horizontal y la relación espacial.

PASO 2 — Analizar la Imagen de Referencia (Estilo Objetivo):
  ► Estilo artístico: ilustración digital de alta calidad, renderizado vibrante,
    texturas detalladas (hiedra, piedra, terciopelo), iluminación ambiental profunda.
  ► Diseño de personajes: el hada moderna (vestido azul, tiara, varita)
    y el genio (humo verde, brazaletes, lámpara).
  ► Formato de bocadillos: nube limpia, tipografía sans-serif legible y uniforme.

PASO 3 — Ejecutar la Remasterización:Escenario modernizado: recrea el entorno con texturas ricas, hiedra, musgo
    e iluminación ambiental caálida.
  ► Personajes actualizados: sustituye modelos antiguos por los modernos
    manteniendo poses y ubicación originales.
  ► Texto preservado: inserta el texto exacto en bocadillos modernos.

VERIFICACIÓN:
  ► ¿Están todos los elementos de la escena original?
  ► ¿El texto es idéntico al original?
  ► ¿El estilo es indistinguible de la referencia?
  ► ¿Los personajes son los modernos, no redibujados?

El problema de la consistencia: la pesadilla de toda IA generativa

En generación de imágenes, la consistencia de personaje entre imágenes es el problema más difícil. Cada generación parte de ruido aleatorio: sin anclar el modelo a una referencia visual sólida, el Hada Benéfica puede cambiar de cabello entre el nivel 3 y el 4. La estrategia usada fue siempre adjuntar la primera imagen generada y aprobada de cada nivel como referencia de estilo para las 5 variantes siguientes, forzando al modelo a mantener el mismo Genio, la misma Hada y el mismo escenario.

En términos de producción, quedó así: fase artesanal (30 niveles), fase industrial (42 niveles por API). El equilibrio perfecto entre ojo humano y automatización: el humano decide el estándar; el script hace horas extra sin quejarse.

📸

GIF → PNG: el salto de resolución

Los GIF originales eran de 640×480 en 256 colores. Las nuevas imágenes PNG generadas tienen resolución libre y full-color, adaptadas automáticamente a cualquier pantalla gracias al contenedor CSS de aspecto dinámico.

📍

Reajuste de zonas táctiles

Al cambiar el tamaño y proporción de las imágenes, las áreas clicables de 1997 (en píxeles absolutos) no servían. Un Modo Editor integrado en la propia app permitió arrastrar y reposicionar cada zona sobre la nueva imagen hasta ajustarla con precisión porcentual.

🤖

El humano en el bucle

Cada imagen generada fue revisada manualmente: texto correcto, personajes coherentes, composición respetada. Lo que no era aceptable se regeneraba con el prompt refinado. La IA es rápida; el criterio artístico sigue siendo humano.


1997 vs 2026: la misma idea, otro universo técnico

Característica El Castillo 1997 El Castillo 2026
Lenguaje servidor C compilado (experto.exe) Sin servidor — lógica 100% cliente JS
Base de datos Ficheros .dat en el filesystem Firebase Firestore (NoSQL cloud)
Autenticación Login/Password en fichero de texto OAuth2 con Google (Firebase Auth)
Sesión de usuario ID numérico en cada URL y campo oculto JWT token gestionado por el SDK de Firebase
Zonas interactivas Image Maps HTML con px absolutos divs CSS con coordenadas % relativas
Plantillas Caracteres centinela en ficheros .htm Template literals ES6 + DOM dinámico
Generación de UI printf() de HTML en C createElement() + appendChild() en JS
Imágenes GIF 256 colores, 640×480 PNG generado con IA (resolución libre)
Despliegue FTP manual a servidor Unix Firebase Hosting + CDN global
Dependencias cgi-lib.c, html-lib.c, llist.c (propias) Zero dependencies — solo Firebase SDK

Lo que no ha cambiado

Veintinueve años después, el reto sigue siendo el mismo: que el usuario piense, se equivoque y aprenda. Las herramientas han evolucionado de forma radical —de un binario C en un servidor Unix compartido a una SPA serverless con Firebase y assets generados por IA— pero el núcleo del diseño instruccional se mantiene intacto.

El mayor homenaje que podemos hacerle a EXPERTO.C es que los principios que lo guiaron siguen vigentes: separación de datos y presentación (levels.json vs app.js), estado mínimo y explícito (gameState), y lógica en el punto de mínima latencia (cliente en 2026, servidor en 1997).

🏰

El Castillo no es solo un juego de lógica. Es un documento vivo de treinta años de evolución de la ingeniería web, guardado en una misma carpeta donde conviven EXPERTO.C de 1997 y app.js de 2026, separados por 48.000 bytes de historia.