NetHack es un juego roguelike en el que un jugador debe recuperar el Amuleto de Yendor desde el nivel más bajo de la mazmorra. Comúnmente jugado a través de telnet, todo el juego está representado con gráficos ASCII. El juego es extremadamente desafiante y requiere el conocimiento de muchas mecánicas de juego para tener éxito.
Para los propósitos de este desafío, suponga que toda la mazmorra tiene un solo nivel y solo 5 × 16 caracteres. Además, suponga que esta es una mazmorra "segura" o que solo está implementando un prototipo: no habrá monstruos, preocupaciones sobre el hambre, etc. De hecho, solo debe rastrear la ubicación del personaje, el amuleto y el juego. efectivamente terminará cuando el jugador llegue a la misma ubicación que el amuleto.
Requisitos de desafío
- Habrá una mazmorra de 5 × 16 (nivel único).
- Dale al jugador una ubicación inicial (opcionalmente al azar) y el amuleto al azar por separado (diferente cada vez que se ejecute el programa) dentro del calabozo. Es decir, el amuleto no puede comenzar en la misma casilla que el jugador.
- Acepte cuatro teclas de entrada que mueven al jugador un cuadrado a la vez (cuatro direcciones cardinales). Se permite leer / procesar otra entrada (una función readline () que requiere presionar 'enter', etc.).
- No se permite viajar fuera de los límites de la mazmorra. Por ejemplo, si el jugador está en el borde derecho de la mazmorra, presionar a la derecha no debería hacer nada.
- Después de la generación inicial y después de cada movimiento, imprime el estado del juego. Como se trata de un código de golf y la impresión es poco interesante, ignore el recuento de caracteres para la función de impresión y la función de llamada suponiendo que no haya cambios de estado . Las celdas vacías se deben mostrar como punto (
.
), el amuleto como comillas dobles ("
) y el carácter como símbolo (@
). - El juego termina cuando el jugador "descubre" el amuleto (llega a la misma casilla)
Victorioso
Este es un desafío de código de golf, el código más corto para cumplir con los requisitos dentro de una semana a partir de hoy será declarado ganador.
Ejemplo
Aquí hay una solución de ejemplo en C # (sin golf) para mostrar los requisitos básicos y la salida de muestra.
using System;
namespace nh
{
class Program
{
static Random random = new Random();
// player x/y, amulet x/y
static int px, py, ax, ay;
static void Main(string[] args)
{
px = random.Next(0, 16);
py = random.Next(0, 5);
// amulet starts on a position different from the player
do { ax = random.Next(0, 16); } while (px == ax);
do { ay = random.Next(0, 5); } while (py == ay);
print();
do
{
// reads a single keypress (no need to press enter)
// result is cast to int to compare with character literals
var m = (int)Console.ReadKey(true).Key;
// Move the player. Here standard WASD keys are used.
// Boundary checks for edge of dungeon as well.
if (m == 'W')
py = (py > 0) ? py - 1 : py;
if (m == 'S')
py = (py < 5) ? py + 1 : py;
if (m == 'A')
px = (px > 0) ? px - 1 : px;
if (m == 'D')
px = (px < 16) ? px + 1 : px;
// print state after each keypress. If the player doesn't
// move this is redundant but oh well.
print();
// game ends when player is on same square as amulet
} while (px != ax || py != ay);
}
static void print()
{
Console.Write('\n');
for (int y=0; y<5; y++)
{
for (int x = 0; x < 16; x++)
{
if (x == px && y == py)
Console.Write('@');
else if (x == ax && y == ay)
Console.Write('"');
else
Console.Write('.');
}
Console.Write('\n');
}
}
}
}
El recuento total de caracteres es 1474, pero ignorando las llamadas a la función de impresión y su definición, el recuento final de caracteres es 896
.
Salida cuando se ejecuta el programa:
................
...."...........
..........@.....
................
................
Salida (incluida arriba) después de presionar la tecla 'a' dos veces:
................
...."...........
..........@.....
................
................
................
...."...........
.........@......
................
................
................
...."...........
........@.......
................
................
Respuestas:
TI-BASIC,
4241383635 bytesPara su calculadora gráfica de la serie TI-83 u 84+.
La dirección en la que irá el jugador es una función del código de la tecla presionada, pero cuatro teclas que definitivamente funcionan son estas en la fila superior:
El amuleto comienza en uno de los cinco cuadrados de la primera columna, y el jugador comienza en el cuadrado inferior derecho. Por ejemplo, un posible arreglo es:
Explicación
La posición del jugador se almacena como un número complejo desde
0+0i
hasta15+4i
, donde la parte real va hacia la derecha y la parte imaginaria baja. Esto facilita la comprobación de límites fácil en la parte superior e izquierda: simplemente compensamos el número ligeramente y redondeamos hacia cero. Por ejemplo, si el desplazamiento es0.5
y nuestra posición es-1+3i
(fuera de la pantalla a la izquierda), entonces la posición se corregirá aiPart(-0.5+3.5i)=0+3i
donde debería estar. Verificar los límites inferior y derecho es un poco más complicado; necesitamos restar el número de una constanteC
, que es aproximadamente15.635 + 4.093i
(es la más corta que pude encontrar entre15+4i
y16+5i
), redondear, restar deC
nuevo para voltear el número y redondear nuevamente.Cuando se presiona una tecla, la posición del jugador sin ajustar se moverá 1 unidad en alguna dirección, pero la parte entera solo cambia cuando se presionan ciertas teclas. Afortunadamente, las teclas que funcionan están en la fila superior. A continuación se muestra un gráfico de los desplazamientos en los casos en que se presionan las teclas 11, 12, 13 y 15, y cuando no se presiona ninguna tecla (No presionar es el punto dentro del cuadrado central, lo que hace que las partes enteras no cambien; las cuatro teclas presionadas 'las compensaciones tienen diferentes partes enteras).
C
es la cruz roja en el centro del círculo.Código antiguo (42 bytes):
Limitaciones
No hay forma de escapar de un
"
personaje, por"
lo que no se pueden generar cadenas con un dentro de un programa. Por lo tanto, esto usa la marca de diéresis en¨
lugar de una comilla (si hubiera una cadena ya existente con una comilla, podría mostrar eso). Para entrar¨
y@
en un programa, se requiere una herramienta externa; sin embargo, es válido TI-BASIC.fuente
CHIP-8 , 48 bytes
Esto puede no ser considerado legal, pero ¿por qué demonios no? Escribí mi programa en CHIP-8, un lenguaje de programación basado en bytecode para una consola de juegos virtual. Puede probar el programa completo (99 bytes) en su navegador usando un emulador / depurador que escribí llamado Octo:
http://johnearnest.github.io/Octo/index.html?gist=1318903acdc1dd266469
Un volcado hexadecimal de ese programa completo es el siguiente:
Puede mover el reproductor con las teclas ASWD o las teclas 7589 en el teclado CHIP-8 original. Si elimino todo el código y los datos para dibujar el fondo y el reproductor, en su lugar obtengo este volcado de 48 bytes:
La forma completa y sin golf del programa fue escrita en un lenguaje ensamblador de alto nivel de la siguiente manera:
Tenga en cuenta que el compilado bytes mismos son el lenguaje de programación CHIP-8; El ensamblador es simplemente un medio más conveniente para componer tales programas.
fuente
Python 3, 86 bytes
Solo contando las dos líneas inferiores y soltando
d();
.fuente
a=id(9)%79
cona=id(9)%p
.raw_input
llamada a soloinput
.C,
122121115104102101 bytesPrimera vez publicando aquí! Espero que te guste :)
o
es la impresión, erm, función. Nuestro valiente héroe puede moverse con 2, 4, 6 y 8, pero tenga cuidado de no enviar ninguna otra entrada (¡no hay nuevas líneas!).Actualización 1: traído
a
yi
dentromain
de los parámetros.Actualización 2: OP confirmó que una sola cadena de entrada está bien, me deshice
scanf
(que solía omitir la nueva línea).Actualización 3: Usó una matriz compuesta literal y modificó el diseño de entrada. El programa ahora se vuelve loco si ingresa una dirección no válida;)
Actualización 4: Noté que la llamada a la función de impresión no cuenta. Tomó nota para leer las reglas con más cuidado.
Actualización 5: un byte guardado, gracias a Mikkel Alan Stokkebye Christia.
fuente
!!(p%16)
serp%16>0
? No recuerdo mi orden de operaciones.-
no puede evitar quedarsep
, por lo que se necesitan paréntesis de cualquier manera. El doble golpe es solo ofuscación :)CJam,
464544403937 bytesLa primera línea (define una función que imprime el estado actual del juego) y las P en la segunda línea (llamar a esa función) no contribuyen al recuento de bytes.
Tanto la posición inicial como la posición del amuleto se seleccionan seudoaleatoriamente. La distribución es tan uniforme y el PRNG subyacente lo permite.
De entrada es E, 6, 9y Bpara arriba , abajo , izquierda y derecha , con Caps Lockactivado, seguido por Enter.
Versión alternativa
A costa de cuatro bytes más, el formato de entrada se mejora significativamente:
Pruebas
Como la E / S es interactiva, debe probar este código con el intérprete de Java .
Descargue la última versión y ejecute el programa así:
Para evitar presionar Enterdespués de cada tecla, y para actualizaciones en el lugar de la salida, puede usar este contenedor:
Invocar así:
Versión principal
Versión alternativa
Función P
fuente
Java, 231 bytes (196 si función)
Aquí está el código completo del programa en 342:
Sin la función de impresión, 231:
Si solo una función está bien (no estoy claro por la especificación), entonces puedo reducir esto un poco más a 196:
Y con algunos saltos de línea para un poco de claridad ...
Tenga en cuenta que no estoy contando la función de impresión en
p(p,y)
sí, pero estoy contando la llamada, ya que tengo cosas que cambian dentro de la declaración de llamada.Funciona con mayúsculas
ASDW
. Debido a la forma en que los verifica, algunas otras letras también podrían funcionar, pero la especificación realmente no dice nada sobre lo que debería suceder si presiono diferentes teclas.fuente
void m()
convierte en()->
p+=
?Java, 574 bytes
Básicamente lo mismo que la versión C #, excepto ofuscado y minimizado.
fuente
Julia, 161 bytes
Usos w, a, s, y dpara desplazarse hacia arriba, izquierda, abajo, y derecha, respectivamente.
Código completo, incluida la impresión (330 bytes):
Código puntuado, excluye la impresión (161 bytes):
La diferencia aquí es que no guardamos el estado del juego como una matriz; Toda la información relevante está contenida en las matrices
c
ya
. Y, por supuesto, no se imprime nada. Ya no se le solicitará al usuario que ingrese una vez que el jugador alcance el amuleto.Ungolfed + explicación (código completo):
fuente
a=[rand(1:5),1] c=a+1
Lote, 329 bytes
fuente
Microsoft Windows [Version 6.1.7601]
Microsoft Windows [Version 6.2.9200]
)Perl,
228222 caracteres (sin contar las nuevas líneas que no son parte integral del funcionamiento del código) - 207 si no cuenta las partesprint
y laprint if
declaración que se utilizan para imprimir, pero no se agregan a la lógica del juego; 144 si también considera el código de generación de representación de campo como parte de la impresión, como sugiere Yakk en los comentarios)Este código usa wasd en minúsculas para el control; La entrada debe confirmarse con Enter. Probado con Perl 5.14.2.
Tenga en cuenta que para este código, es imposible separar el cálculo y la impresión, ya que las operaciones se realizan directamente en la representación impresa utilizando expresiones regulares.
Explicación:
Esta línea determina la posición del jugador y el amuleto. La posición del jugador está determinada
$==rand(80)
y es realmente fácil de entender: en un tablero de 5 × 16, hay 80 posiciones distintas donde el jugador puede estar. La posición se almacena en la$=
variable que fuerza el valor almacenado a entero; Esto ahorra algunos bytes por no tener que convertir explícitamente el resultado a entero (rand
entrega un valor de coma flotante).Como una de las posiciones ya está ocupada por el jugador, solo quedan 79 posiciones para el amuleto, por lo tanto, para la posición del amuleto,
$a=$==rand(79)
se utiliza. Nuevamente, la asignación a$=
obliga a una conversión a entero, sin embargo, la asigno$a
para reutilizarla$=
para la posición del jugador.Ahora, para evitar que el amuleto ocupe la misma posición que el jugador, avanza una posición si su posición es al menos tan grande como la del jugador, lo que proporciona una distribución uniforme en los lugares no ocupados por el jugador. Esto se logra por
$a = ($a >= $=)
donde$=
aquí ocupa la posición del jugador. Ahora la primera línea se genera insertando las dos asignaciones iniciales en lugar del primer$a$ and the only
$ = `en esta expresión.Esto genera el campo inicial, y luego imprime es.
("."x80)
solo genera una cadena de 80 puntos.=~s/(.{$=})./\1@/r
luego reemplaza el$=
carácter th con@
, y=~s/(.{$=})./\1@/r
el$a
carácter th con"
. Debido alr
modificador, no intentan modificar en su lugar, sino que devuelven la cadena modificada, es por eso que pueden aplicarse a las expresiones anteriores. Finalmente,=~s/(.{16})/\1\n/gr
inserta una nueva línea cada 16 caracteres. Tenga en cuenta que el campo se almacena en la variable especial$_
que se puede usar implícitamente en declaraciones posteriores.Esto crea un hash que contiene las reglas de reemplazo para los diferentes movimientos. Una versión más legible de esto es
Las claves son los caracteres para los movimientos, y los valores son cadenas que contienen la regla de reemplazo correspondiente.
Este es el bucle principal.
while(/"/)
comprueba si todavía hay un"
carácter en$_
(es decir, en el campo). Si pasamos al amuleto, su personaje se reemplaza con el personaje del jugador, por lo que desaparece del campo.eval $r{getc STDIN}
lee un carácter de la entrada estándar, busca la regla de reemplazo correspondiente a partir del has%r
y la aplica$_
, es decir, al campo. Esto se evalúa como verdadero si realmente se realizó un reemplazo (es decir, la clave se encontró en el hash y el movimiento fue posible; un movimiento imposible no coincidirá en la regla de reemplazo). En ese casoprint
se ejecuta. Como se llama sin argumento, imprime$_
, es decir, el campo modificado.fuente
("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/gr
está bastante cerca a primera vista, pero mi perl-fu tiene algunos años oxidado. Me podría haber perdido un cambio de estado allí.C #,
256 248 234 227 226225 bytesUtiliza las flechas de NumPad con NumLock activado para moverse.
Sangrado y comentado para mayor claridad:
fuente
Main
no es necesario invocar el métodoMain
, por lo que podría eliminar otros tres caracteres.HTML + JavaScript (ES6), puntaje quizás 217
Demasiado largo, pero jugable en línea en los fragmentos a continuación.
La línea 6 (T.value ...) es para salida y no contada (pero por simplicidad conté las etiquetas de apertura y cierre de área de texto, incluso si también es salida)
En cuanto a la aleatoriedad: el amuleto siempre está en la mitad derecha de la cuadrícula y el jugador siempre comienza en la mitad izquierda.
Haga clic en el área de texto (después de agrandarlo) para iniciar y reiniciar el juego.
Fragmento de EcmaScript 6 (solo Firefox)
Fragmento de EcmaScript 5 (probado en Chrome)
fuente
Actionscript 3: 267 bytes
Un ejemplo de trabajo está en línea.
var a:int,p:int,t;function g(){var r=Math.random;while(p==a){a=r()*80;p=r()*80}addEventListener("keyDown",function(e){if(a==p)return;if(e.keyCode==87&&p>15)p-=16if(e.keyCode==83&&p<64)p+=16if(e.keyCode==65&&p%16>0)p--if(e.keyCode==68&&(p+1)%16>0)p++print()});print()}
Aquí hay un programa completo (espacios en blanco incluidos para facilitar la lectura) que utiliza la función de juego:
fuente
Javascript:
307216¡Puedes jugar en el fragmento de abajo! Los números a la izquierda son solo para que la consola (Chrome uno al menos) no combine las filas.
Para ejecutar el código:
Sin golf:
Edición 1: lea las reglas con más cuidado y reescribí mi código en consecuencia
fuente
SpecBAS -
428402 (excluyendo impresión,466425 cuando se cuenta)Utiliza Q / A / O / P para moverse hacia arriba / abajo / izquierda / derecha respectivamente.
La línea para imprimir la mazmorra en la línea 1 es la única línea que se puede ignorar, pero también se ha reducido un poco.
La referencia al # 34 es solo una forma abreviada de poner CHR $ (34) en el código.
Gracias @Thomas Kwa, no me había dado cuenta de que la posición de inicio del jugador al azar era opcional. También se utilizan declaraciones IF separadas para eliminar algunos caracteres.
fuente
2 LET px=1: LET py=1: LET ax=2: LET ay=INT(RND*5)
y también usandoIF instead of ELSE IF
.Otro C #,
221171170Aquí hay otra forma en C # con ambas posiciones al azar. Quería mostrar esto incluso si esta parte es 7 bytes más larga que la solución de Hand-E-Food.
La respuesta de Hand-E-Food será más corta, por supuesto, tan pronto como use Console.Read ().
La desventaja de Consol.Read es que presionar la tecla Intro necesaria hace que el campo se imprima 2 veces más.
Pero no creo que haya un requisito para imprimir solo en la entrada (real).
La navegación se realiza por 8426 como en la solución Hand-E-Foods.
Editar: (agregó una nueva solución y movió PrinterClass al final)
Editar2: (cambió un 14 a un 15 y guardó el byte comenzando en la parte inferior derecha)
Adaptando la técnica de Mauris es posible fusionarlo a 171 bytes en C # (por supuesto ahora sin ambas posiciones al azar):
La clase de impresora es casi la misma, solo una nueva sobrecarga de impresión ...
fuente
Rubí, 185
Aquí hay un ejemplo de Ruby también.
Soy muy nuevo en Ruby, tal vez alguien sepa cómo hacerlo mejor :)
He contado lineFeeds como 1 ya que de lo contrario el programa se bloqueará
La navegación se realiza por 8462. Debe enviar la entrada cada vez con enter.
fuente
QBasic, 103 bytes
Según las reglas del desafío, el
Show
subprograma no está incluido en el conteo de bytes, ni laShow p, q, a, b
llamada (con la siguiente línea nueva).Para moverse, ingrese un número y presione Entrar:
1
para ir a la izquierda,2
para subir,3
para ir a la derecha y4
para bajar.Este código no muestra el estado del juego al final, cuando el jugador ha encontrado el amuleto. Para hacerlo, agregue otro
Show p, q, a, b
después de laIF
declaración.Explicación
Deje
a
,b
representar las coordenadas del amuleto yp
,q
las coordenadas del jugador. El jugador comienza en (0, 0), y el amuleto comienza en la fila 0, con una columna entre 1 y 9, inclusive, basada en el dígito del 1 de la hora actual.El resto es solo un montón de matemáticas con condicionales. Lo importante para recordar es que los condicionales en QBasic devuelven
0
falso,-1
verdadero. Veamos la declaración de actualización de la fila del jugador:Si
m=2
, queremos avanzar restando 1 dep
, siempre quep>0
. Del mismo modo, sim=4
, queremos movernos hacia abajo agregando 1 ap
, siempre quep<4
. Podemos obtener el comportamiento deseado multiplicando. Si ambos factores son-1
, su producto será1
, lo que podemos restar o agregarp
. Si cualquiera de los condicional es0
, el producto será0
, sin efecto.Del mismo modo, la condición para determinar si el jugador ha encontrado el amuleto es:
Si cualquiera de los condicionales es verdadero, su suma será distinta de cero (cualquiera
-1
o-2
) y, por lo tanto, verdadera, y el programa volverá a la línea 1. Una vez que seap
iguala
eq
igualb
, ambos condicionales lo serán0
, por lo que su suma será0
y el flujo de control puede alcanzar el Fin del programa.fuente