Cuando era niño, jugué al juego Intellivision Advanced Dungeons and Dragons: Treasure of Tarmin . Los gráficos en 3-D lo colocan en un punto de vista en primera persona con un realismo impactante:
Pero luego obtuve un C-64. Y pude dibujar en la cuadrícula de 40x25 caracteres al pasar el cursor por la pantalla, establecer el color con la tecla Ctrl y un dígito, y poner símbolos en cualquier lugar que quisiera (¿por qué no me bash
dejas hacer eso?) . El conjunto de caracteres tenía componentes triangulares y componentes de bloque sólido. Así que pude razonar cómo se puede generar una representación de la perspectiva de uno en una cuadrícula a través de ese medio.
Encontré la especificación de casi tres décadas de antigüedad, en papel de cuaderno encuadernado en espiral, sobre "Dungeon Construction Set" esta semana:
( ACTUALIZACIÓN : los lectores cuidadosos notarán que esto no se mantiene bien en las partes inclinadas. Los números corregidos se proporcionan a continuación).
Aunque Treasure of Tarmin se jugó en una cuadrícula, las paredes solo existían en los bordes de los cuadrados de la cuadrícula. Después de saber qué bytes eran, me di cuenta de que si hacía el mapa con bytes ... entonces cada cuadrado en el mapa podría tener cuatro estados posibles para cada uno de sus bordes:
- Sin obstáculos
- pared
- Puerta
- ¿Algo más?
Nunca pude escribirlo (hasta anoche). Pensé que sería divertido para otros intentarlo.
Entonces, su tarea es implementar un renderizador de laberintos basado en modo de personaje que implemente mi (¡corregido!) Especificación ... pero usando las tecnologías de 2013.
Entrada
Debido a que la especificación no define el renderizado para puertas, asumiremos que las únicas opciones son wall-and-not-wall. Para simplificar, su entrada es un mapa compuesto por líneas de cadenas que se ven así:
WN.. .N.. .N.. .N.. .N.E
W... .... .... ..S. ...E
W... .N.E W... .N.. ...E
W... .... .... .... ...E
W.S. ..S. ..S. ..S. ..SE
Eso sería un mapa de 5x5. La esquina superior izquierda (1,1) tiene su conjunto de pared W
est y N
orth. La esquina inferior derecha (5,5) tiene su conjunto de pared S
exterior y exterior E
.
Esto es considerablemente menos divertido sin navegación por el mapa. Entonces, como mínimo, coloque su jugador en (1,1) hacia el norte y ofrézcales:
[F]orward, [B]ackward, turn [L]eft, turn [R]ight or [Q]uit?
En cada paso, imprima una pantalla de 16x15 de la perspectiva en primera persona, tal como se define en las especificaciones del papel del cuaderno. Para evitar que tenga que contar, el tamaño de las paredes planas en las tres distancias son:
14x13 (directly in front of you; e.g. wall is in same cell)
8x7 (one step away)
6x5 (two steps away)
Los tamaños límite de las paredes inclinadas son:
1x15 (your direct left or right; e.g. wall is in same cell)
3x13 (one step away)
1x7 (two steps away)
Aclaraciones
Las celdas adyacentes pueden estar en desacuerdo sobre las paredes compartidas. Por lo tanto, el borde sur de un cuadrado podría ser una pared, mientras que el borde norte de la plaza al sur no estaría obstruido. En el diseño original, consideraba esto como una característica: permite ideas interesantes como puertas unidireccionales ... o paredes invisibles que solo aparecen después de pasar por ellas. Para esta simplificación, siga la misma regla: para la navegación y el renderizado, preste atención solo al estado del borde en la celda más cercana a usted en la dirección que está mirando .
La vista es mucho mejor con "sombreado". Entonces, para sus bloques completos, alterne Unicode 2593 ▓ y 2591 °, o use
X
y+
si su implementación es ASCII.Los caracteres de triángulo Unicode (25E2 ◢, 25E3 ◣, 25E4 ◤, 25E5 ◥) son un poco aburridos para dibujar esto. Además de no tener variantes sombreadas, a menudo estiran solo el ancho del carácter y no la altura completa ... incluso en fuentes de ancho fijo. Puede dibujar bloques completos o caracteres de barra diagonal o algo de su elección en los lugares que quería diagonales. Se aprecian soluciones creativas interesantes que incorporan color y usan estos caracteres en lugar de sombrear.
Puede suponer que las paredes más externas están configuradas para delimitar el área de juego, por lo que no tiene que preocuparse por renderizar nada fuera del laberinto. Cualquier muro más alejado de ti que la especificación se ignora y simplemente deja un espacio vacío.
El sombreado de la pared que ve directamente frente a usted si mira hacia el norte en (1,1) debe ser OSCURO. Sombreado alternativo en las paredes adyacentes en el mapa, de modo que si todas las paredes estuvieran presentes, una pared clara nunca colindaría con una pared oscura.
Una implementación C-64 que realmente hace lo que originalmente pretendía ... con los caracteres diagonales y todo ... prevalecerá sobre cualquier otro criterio de entrada. :-)
Ejemplos
Para el mapa de muestra dado anteriormente ...
En (1,3) hacia el sur:
/
/+
/X+
/XX+
/XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
\XXX+
\XX+
\X+
\+
\
En (3,2) hacia el sur:
/* blank line */
X /
X /+
X /++
X +++
X +++
X +++
X +++
X +++
X +++
X +++
X \++
X \+
X \
/* blank line */
En (3,2) hacia el este:
/* blank line */
/
/X
/XX
XXX
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
+++++XXXXXX+XXX+
XXX
\XX
\X
\
/* blank line */
En (2,3) hacia el norte:
/
++++++++++++++X
++++++++++++++X
++++++++++++++X
++++++++++++++X
X++++++++++++++X
X++++++++++++++X
X++++++++++++++X
X++++++++++++++X
X++++++++++++++X
++++++++++++++X
++++++++++++++X
++++++++++++++X
++++++++++++++X
\
fuente
X
s en su vista3, 2
hacia el sur?Respuestas:
Commodore 64 Basic
Hombre, eso fue divertido. Y duro. C64 Basic es casi no borrable, ni siquiera puede usar la
print
depuración porque la pantalla ya está ocupada para representar la mazmorra. Sabes que te estás divirtiendo cuando escribes código como55250 goto 55110
. Dijkstra me matará.El programa usa dos colores y caracteres diagonales.
No hace falta decir que no jugué golf. Dice desafío de código ahora, después de todo. Son 7183 bytes si estás interesado.
Es lento: a la velocidad predeterminada, tarda varios segundos en reproducir la escena. El tamaño máximo del mapa es de 10 por 10, pero se puede cambiar editando la línea 120.
Desarrollé y probé esto usando el emulador VICE . El siguiente código se muestra en ASCII, por lo que significa PETSCII desplazado . Sin embargo, al ingresar el mapa, debe usar PETSCII sin desplazar .
Captura de pantalla:
Código:
Imagen de la cinta: descargue aquí .
Los ejemplos:
fuente
Solo tenía que hacerlo ahora.
Bash, 12743 caracteres
Tenga en cuenta que esto es más o menos lo primero que hice con
bash
eso que fue más que simplemente juntar algunos comandos. Probablemente sería reducible bastante si no codificara todas las paredes, pero me pareció más fácil. No tiene consistencia alguna. El formato de bytes para cada cuadrado se selecciona de una manera horrible. Pero funciona.Incluso agregué soporte para el movimiento a través de las teclas de flecha :)
Estas son algunas capturas de pantalla para la entrada de muestra (tenga en cuenta que mi mapa comienza en (0 | 0)):
Además del cuarto, todos se parecen a los de muestra también (vea mi comentario sobre el OP).Estas capturas de pantalla se tomaron en urxvt v9.15 con soporte de 256 colores, probablemente se vería bastante mal en un terminal de 88 colores, y los terminales sin soporte Unicode no funcionan en absoluto. La fuente que utilicé fue Source Code Pro de Adobe.
fuente
Aquí está mi versión, en Python 3. Es algo así como 3k caracteres y podría reducirse un poco con un poco de esfuerzo (para empezar, hay un montón de espacio en blanco que podría eliminarse).
Actualmente se usa
+X/\
como sus caracteres de dibujo, pero está configurado para dibujar con caracteres Unicode si tiene una fuente de ancho fijo que los representará correctamente. Admite el uso de mosaicos separados para las partes anguladas de las paredes de diferentes colores, aunque no estoy usando esa característica. También le permite proporcionar fichas de techo, piso y "distantes", y puede usar diferentes para cuando el jugador está mirando hacia el este o el oeste frente al norte o al sur. Por desgracia, esto nunca se vio muy bien, por lo que probablemente todos estos deberían estar en blanco (o algo sólido, como█
).Por desgracia, en mi sistema Windows 7, tuve un momento horrible tratando de encontrar una fuente monoespaciada con el conjunto completo de caracteres de bloque (por ejemplo,
▜
y▟
). La mayoría de los que encontré no podían estar disponibles en elcmd
consola por alguna razón (¿tal vez porque no están perfectamente monoespaciados?). Si cree que su consola es más funcional, intente usar el juego de caracteres alternativo que he comentado cerca de la parte superior del archivo, que no se ve tan mal incluso con solo dos colores. Se ha rellenado de techos y suelos y en su mayoría paredes transparentes.El código:
El juego de caracteres se especifica cerca de la parte superior del archivo. El orden de los personajes son:
/
con una pared debajo de él)Hay 15 muros que el juego debe representar, en un patrón como este (con
V
indicación de la posición y el arco de visión del jugador):Los mosaicos utilizados por las 15 paredes están definidos en la
shapes
lista. Es una lista de 2 tuplas. El primer valor de la tupla indica la "paridad" de la pared,0
indicando que debe dibujarse con los mismos caracteres que una pared directamente en frente del personaje y una1
indicación de que debe ser el patrón alternativo (por ejemplo,+
vsX
). El segundo valor es una lista dex,y,t
tuplas que indican las coordenadas de la pantalla y el índice de mosaico de un píxel (los muros que se representan con paridad impar se habrán1
agregado a cada uno de estos índices). Las formas están ordenadas por distancia, por lo que las tres primeras representan las paredes perpendiculares dos fichas delante del personaje, seguidas de las dos paredes paralelas dos fichas más adelante, y así sucesivamente.Las funciones son:
rr
: "renderiza" la pantalla (imprimiendo los mosaicos en el búfer de la pantalla).dw
: "dibujar muros" en un búfer de pantalla proporcionado. Esto utiliza el algoritmo de pintores, por lo que las paredes más distantes se dibujan primero y pueden quedar cubiertas por otras más cercanas.ga
: "get area" devuelve una lista de valores booleanos que indican qué paredes son opacas para una posición y orientación del mapa.rd
: "leer", un generador que lee el mapa, produciendo las líneas. Esto solo es necesario porque la consola de IDLE hace cosas raras cuando pega entradas de varias líneas en lugar de ingresar una línea a la vez.rm
: "leer mapa", analiza el mapa en una lista anidada de booleanos, indexada porm[y][x][d]
(cond=0
ser Este yd=1
Sur). También agrega dos filas y dos columnas de cuadrados de relleno, para evitar errores de índice en el otro código.cl
: "borra" la salida (escribiendo suficientes líneas nuevas para desplazar la vista anterior desde la parte superior de la mayoría de las consolas).gl
: "bucle de juego", donde se recopila la entrada y se llama a las cosas anteriores.Algunas "capturas de pantalla":
La posición inicial:
Mirando a lo largo del muro norte:
Un par de tomas que coinciden con sus ejemplos (tenga en cuenta que Stack Overflow está cortando las primeras líneas en blanco, están en la salida del programa):
Y:
Aquí está una de las vistas más extrañas en el mapa provisto, ya que el muro paralelo a nuestra vista es del mismo color que el muro perpendicular que sobresale detrás de él:
Así es como se vería el área del último disparo desde arriba:
fuente