Microhobby 26. Año II, del 30 de abril al 6 de mayo de 1985

Estrategia. Laberintos: cómo generarlos

Paco Martín

Cuántas veces, dejando volar la imaginación no habremos pensado en crear un laberinto para el más fantástico y emocionante juego jamás construido por nosotros.

Nos imaginamos escenas llenas de emoción y misterio a raudales en los que, tras una lucha o una persecución, más o menos encarnizada, el héroe (nosotros por supuesto), llega a su destino glorioso y feliz.

Y de pronto, nos caemos de la nube, ¿cómo diablos se puede hacer tan fantástico laberinto?

Imaginamos mil y una maneras, pero él se resiste a mostrarnos sus secretos. Al final, resignados (y bastante enfadados, por qué no decirlo) decidimos hacer una especie de «laberinto aleatorio», cuyo resultado final provoca comentarios ciertamente aleatorios.

Pues bien: ¡Se acabó tal tortura! En este artículo vamos a tratar de explicar, de la forma más clara y concisa posible, su verdadero secreto. Un secreto que sólo poseían hasta ahora los mejores juegos: «FRED», «MAZIACS», etc.

Quisiéramos, antes que nada, aclarar que la forma que tendrá cada laberinto (su estructura) es algo que está en función del gusto personal de cada uno, y que el programa que vamos a explicar a continuación, es una simple muestra para entender lo único realmente importante: el «truco», «secreto», o como lo queráis llamar.

Vamos a enumerar inicialmente, las condiciones más importantes y ABSOLUTAMENTE NECESARIAS para su construcción:

  1. SIEMPRE DEBERA TENER DIMENSIONES IMPARES, sean éstas las que sean, para evitar que se produzcan errores durante el chequeo en la fase de construcción.
  2. EL PUNTO DE PARTIDA puede decidirse aleatoriamente, pero SIEMPRE SERA IMPAR (en ambas coordenadas) y, EN NINGUN CASO DEBERA POSICIONARSE ENCIMA DE LOS LATERALES DEL LABERINTO (error en la fase de chequeo).
  3. LOS PASOS DE AVANCE durante la construcción, SERAN SIEMPRE DE DOS EN DOS o de lo contrario, os podréis llevar sorpresas desagradables (normalmente el programa o se queda «atrapado» en el laberinto o hace una «masacre» que, si se está trabajando en código máquina, destruye el trabajo realizado). La mejor forma de crear un laberinto, es hacerlo directamente sobre la memoria, esto es, almacenándolo como bytes (CODE), pero para mayor claridad, lo vamos a hacer sobre una matriz de caracteres (A$ en el programa), de forma que cualquiera pueda trabajar con ella sin mayores problemas, junto con otra matriz numérica que nos servirá como «indicador de posibles caminos». Para empezar, vamos a utilizar varios convenios:
  • Los «MUROS» exteriores se han de señalizar con un byte específico para ese cometido; en nuestro caso, lo vamos a hacer con el carácter de espacio (CHR$ 32).
  • El «INTERIOR» del laberinto se llenará inicialmente con un byte indicador de «posible camino». El encargado de esta misión es el carácter UDG «A» que permitirá dar la forma de «pared» que se nos antoje.
  • El «CAMINO» que vamos a ir abriendo se irá marcando con otro byte, siendo el carácter elegido en este caso el gráfico «I» por ejemplo.

Construyamos el laberinto

Con todo esto, vamos a empezar a construir el laberinto tratando de seguir y explicar los pasos del programa.

En primer lugar se asignan sus dimensiones (línea 20) o se define su estructura global, ya que no necesariamente éste debe tener una forma definida, y a continuación, se «llena» por completo el laberinto con los bytes indicadores de «muro» (CHR$ 32, línea 38) y «posible camino» (gráfico «A», línea 40 combina ambos).

En la línea 50 se inicializan una matriz y una variable numérica (c y CO respectivamente), cuyo cometido será explicado en breve.

El «punto de partida» lo determinan las variables «V» y «H» que aquí (línea 60), toman un valor fijo pero que, como ya se dijo, éstas pueden inicializarse aleatoriamente (no olvidar las restricciones).

Para una mejor compresión del proceso, el laberinto, además de crearse en la variable A$, a su vez se va imprimiendo en la pantalla (la parte «más visible») haciéndose una impresión «general» con la instrucción GOSUB 9000.

Entramos ahora en el bucle principal en el que SE HAN DE SEGUIR los siguientes pasos:

Figura 1

PASO 1. (GOSUB 400). Esta sencilla pero muy importante subrutina, determina el número de «caminos libres» que podemos tomar asignando su valor a la variable L1. Si observáis la figura 1, partiendo de la posición actual y siempre mirando DOS PASOS hacia la posición a examinar, se efectúa un chequeo en las cuatro direcciones posibles siendo el número obtenido igual al de «posibles caminos» o, dicho de otro modo, igual al de CHR$ (144) encontrados (UDG «A»), Si L1 = 0 se salta al PASO 4 (GOSUB 300) de lo contrario, continuamos con el PASO 2.

PASO 2. Si L1 > (más de una posible dirección a tomar), entonces se almacenan las posiciones vertical y horizontal (GOSUB 200) en la matriz con subíndice CO. Así, a C (CO,1) se le asigna la posición vertical y a C (CO,2) la horizontal; luego, incrementamos el subíndice CO y continuamos con el PASO 3.

PASO 3. (Líneas 130 a 170). Si L1 > = 1 se elige aleatoriamente uno de los caminos libres (si sólo hay uno, se escoge ese, naturalmente) se avanzan DOS PASOS en esa dirección llenando este espacio con dos CHR$ (143) (gráfico «1»), y se actualizan las coordenadas vertical y horizontal asignándoles la nueva posición. Nuestro programa se encarga de pintar el nuevo camino para saltar, a continuación, al PASO 1.

PASO 4. (Línea 310). El subíndice CO se reduce en uno, asignándose las nuevas posiciones vertical y horizontal con C (CO,1) y C (CO,2), respectivamente. El programa, al retornar de la subrutina, chequea si ambas son CERO. ¿Por qué?, bien, al inicializar el programa, cuando dimensionamos C(), al subíndice CO le asignamos un valor de DOS para que C (1,1) y C (1,2) NO SEAN ALTERADOS por el programa (quedando por tanto igual a CERO) ya que precisamente, estos valores se van a utilizar como INDICADORES (podían haber tomado cualquier otro, 255 por ejemplo, siempre y cuando sólo se utilicen en C() para ese cometido) y su finalidad es muy simple: cuando V=0 y H=0 quiere decir que el laberinto… ¡está terminado! El programa salta entonces a la línea 500.

Cada vez que queramos tener una «vista» general del laberinto (el construido por este programa por supuesto), no tenemos más que hacer un GOSUB 9000 y entonces, se nos mostrará, como dijimos antes, la parte más «visible», esto es, la «parte interna del laberinto» y no sus «muros». Esto solo depende de los planes de cada uno y no hay razón alguna para no tratarlos como un elemento más (laberintos de estructura irregular, o conectados a otros minilaberintos, etc.).

Cuando queramos «movernos» por él, lo haremos chequeando el contenido de A$ (pos. horizontal). Entonces, si éste es un carácter «1», quiere decir que estamos encima de un camino y si no es así, es que hemos «tropezado» con «algo» que, o bien es un muro (UDG «A»), o bien puede ser otra «cosa»: un tesoro, un monstruo, etc. Estos últimos, claro está, se habrán introducido previamente de una forma más o menos definida, según nuestro criterio personal, siendo vuestro cometido el dar «vida» al laberinto.

Para los que saben código máquina

Los pasos de construcción del laberinto son exactamente los mismos: se delimitará una zona en memoria inicializándose todos los bytes, cada uno con su valor específico (según sean «muros» o «posible camino»).

El STACK se utilizará para almacenar las posiciones vertical y horizontal cada vez que se chequee más de una dirección posible de avance, por lo que deberéis tener muy presente que cuanto más grande sea el laberinto, más espacio debéis reservar para el STACK si no queréis llevaros la consabida sorpresa.

Al comenzara construir el laberinto, se inicializará el STACK, pusheando dos bytes indicadores de «LABERINTO TERMINADO» cuyo valor sólo se utilice para ese cometido ( 00 o ff, por ejemplo).

Cada vez que chequeemos más de un camino, pushearemos las coordenadas vertical y horizontal y las popearemos si el chequeo nos da cero, quedando terminado el laberinto cuando sus valores sean los definidos como indicadores de «fin».

¡No a los laberintos «aburridos»!

Con el método explicado, nuestro laberinto quedará totalmente «lleno» (lo cual está muy bien), pero no será muy original hacer varios laberintos. Para darle un toque «personal», bastará con rellenar (antes de que empiece a construirse el camino) el interior con «bloques» de bytes, caracteres, que impidan que se «abra» camino por allí. Insertar las líneas siguientes: (Listados en Ky Enter)

Hacer «RUN». ¿Curioso no? La razón de utilizar los UDG «A» y «B» no es otra que permitir a los menos experimentados la posibilidad de dar una forma cualquiera a las «paredes» y luego, poderlo visualizar de una forma sencilla.

Ya que la forma más correcta (siempre que se pueda) de «trabajar» con un laberinto es la de utilizar el contenido de éste como simples indicadores para hacer, a continuación, un «volcado» por bloques en pantalla del gráfico correspondiente: si detectamos un «camino» pintaremos un bloque gráfico diseñado como camino; si detectamos un muro, pintaremos el bloque correspondiente, etc. La pantalla se definirá entonces por bloques (su tamaño dependerá del grado de «aplicación» que queráis darle) siendo el central la posición que estamos ocupando.

Esperamos que vuestros héroes se sientan orgullosos (que no acobardados) de llevar a cabo sus más gloriosas gestas entre los terribles y sinuosos muros del laberinto.

 
026/estrategia.txt · Última modificación: d/m/Y H:i por miguel
Recent changes RSS feed Creative Commons License Driven by DokuWiki Made on Mac