NetHack mínimo

64

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:

................
...."...........
..........@.....
................
................

................
...."...........
.........@......
................
................

................
...."...........
........@.......
................
................

fuente
10
Tengo la sensación de que esto será de interés para @Doorknob.
Alex A.
10
Rogue es el juego original de roguelike donde un jugador debe recuperar el Amuleto de Yendor desde el nivel más bajo de la mazmorra. ¿Por qué no llamar a esto un pícaro mínimo?
Gilles 'SO- deja de ser malvado'
55
@Gilles ¿Por qué no llamar a esto una serpiente mínima?
Casey Kuball
26
Psshh, no hay movimiento diagonal? No yubnhjkl? ¿Ni siquiera una escalera para subir después de obtener el amuleto? : P ( furiosamente upvotes de todos modos )
Pomo
2
@tolos: Todavía no estoy claro qué cuenta como aleatorio aquí. Realmente no es posible cumplir con el requisito diferente cada vez que el programa se ejecuta si el programa se ejecuta 80 veces ... Específicamente, en esta respuesta , el amuleto puede ocupar solo 9 de las 79 ubicaciones posibles. ¿Eso cuenta?
Dennis

Respuestas:

37

TI-BASIC, 42 41 38 36 35 bytes

Para su calculadora gráfica de la serie TI-83 u 84+.

int(5irand→A                          //Randomize amulet position
6log(ie^(6→C                          //15.635 + 4.093i
Repeat Ans=A                          //Ans holds the player pos. (starts bottom right)
iPart(C-iPart(C-Ans-e^(igetKey-i      //Boundary check, after adjusting player position
prgmDISPLAY
End

----------
PROGRAM:DISPLAY
For(X,0,15
For(Y,0,4
Output(Y+1,X+1,".
If A=X+Yi
Output(Y+1,X+1,"¨
If Ans=X+Yi
Output(Y+1,X+1,"@
End
End

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:

Key        [Y=]  [WINDOW]  [ZOOM]  [TRACE]  [GRAPH]
           -------------------------------------------
Key code    11      12       13               15
Direction  Left     Up     Right             Down

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+0ihasta 15+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 es 0.5y nuestra posición es -1+3i(fuera de la pantalla a la izquierda), entonces la posición se corregirá a iPart(-0.5+3.5i)=0+3idonde debería estar. Verificar los límites inferior y derecho es un poco más complicado; necesitamos restar el número de una constante C, que es aproximadamente 15.635 + 4.093i(es la más corta que pude encontrar entre 15+4iy 16+5i), redondear, restar de Cnuevo 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). Ces la cruz roja en el centro del círculo.

ingrese la descripción de la imagen aquí

Código antiguo (42 bytes):

int(9irand→A                     // 0≤rand≤1, so int(9irand) = i*x where 0≤x≤8
1                                //set "Ans"wer variable to 1+0i
Repeat Ans=A                     
Ans-iPart(i^int(48ln(getKey-1    //add -i,-1,i,1 for WASD respectively (see rev. history)
Ans-int(Ans/16+real(Ans/7        //ensure player is inside dungeon
prgmDISPLAY                      //display on top 5 rows of the homescreen   
                                 //(for this version switch X+Yi with Y=Xi in prgmDISPLAY)
End

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.

lirtosiast
fuente
2
Solo por diversión, hice este fragmento que pone la diéresis y el símbolo @ en Str1 (en lugar de 'una herramienta externa'). Elija la línea en la parte superior que coincida con su calculadora, ingrésela en un nuevo programa y ejecute ese programa con Asm (.
MI Wright,
Oh, me olvidé de codificar el código de máquina en la calculadora. No quiero estrellar el mío con un tipo incorrecto, pero confío en que funcione.
lirtosiast
44

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:

Captura de pantalla

http://johnearnest.github.io/Octo/index.html?gist=1318903acdc1dd266469

Un volcado hexadecimal de ese programa completo es el siguiente:

0x60 0x14 0x61 0x04 0xC4 0x3C 0xC5 0x08
0x22 0x36 0xF6 0x0A 0x22 0x52 0x40 0x00
0x12 0x16 0x46 0x07 0x70 0xFC 0x40 0x3C
0x12 0x1E 0x46 0x09 0x70 0x04 0x41 0x00
0x12 0x26 0x46 0x05 0x71 0xFC 0x41 0x10
0x12 0x2E 0x46 0x08 0x71 0x04 0x22 0x52
0x3F 0x01 0x12 0x0A 0x00 0xFD 0xA2 0x58
0xD4 0x54 0x22 0x52 0x62 0xFF 0xA2 0x5B
0xD2 0x34 0x72 0x04 0x32 0x3F 0x12 0x40
0x62 0xFF 0x73 0x04 0x33 0x14 0x12 0x40
0x00 0xEE 0xA2 0x5F 0xD0 0x14 0x00 0xEE
0xA0 0xA0 0x40 0x00 0x00 0x20 0x00 0xF0
0x90 0x90 0xD0

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:

0x60 0x14 0x61 0x04 0xC4 0x3C 0xC5 0x08
0xF6 0x0A 0x40 0x00 0x12 0x12 0x46 0x07
0x70 0xFC 0x40 0x3C 0x12 0x1A 0x46 0x09
0x70 0x04 0x41 0x00 0x12 0x22 0x46 0x05
0x71 0xFC 0x41 0x10 0x12 0x2A 0x46 0x08
0x71 0x04 0x3F 0x01 0x12 0x08 0x00 0xFD

La forma completa y sin golf del programa fue escrita en un lenguaje ensamblador de alto nivel de la siguiente manera:

:alias px v0
:alias py v1
:alias tx v2
:alias ty v3
:alias ax v4
:alias ay v5
:alias in v6

: main
    px := 20
    py := 4
    ax := random 0b111100
    ay := random 0b001000
    draw-board
    loop
        in := key
        draw-player
        if px != 0 begin
            if in == 7 then px += -4
        end
        if px != 0x3C begin
            if in == 9 then px +=  4
        end
        if py != 0 begin
            if in == 5 then py += -4
        end
        if py != 16 begin
            if in == 8 then py +=  4
        end
        draw-player
        if vf != 1 then
    again
    exit

: draw-board
    i := amulet
    sprite ax ay 4
    draw-player
    tx := -1
    i := ground
    : draw
    loop
        sprite tx ty 4
        tx += 4
        if tx != 63 then jump draw
        tx := -1
        ty += 4
        if ty != 20 then
    again
;

: draw-player
    i := player
    sprite px py 4  
;

: amulet  0xA0 0xA0 0x40
: ground  0x00 0x00 0x20 0x00
: player  0xF0 0x90 0x90 0xD0

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.

JohnE
fuente
19
Herramienta adecuada para el trabajo.
Dennis
66
+1 por hacerme perder un montón de tiempo jugando tu juego una y otra vez.
Alex A.
44
@AlexA. si quieres perder aún más tiempo deberías probar Cave Explorer . El movimiento ASWD en el supramundo y el QE se usan para restablecer / mover bloques en los niveles de plataformas.
JohnE
44
Genial, bueno ahí va mi fin de semana.
Alex A.
1
Al principio era escéptico, pero Cave Explorer fue divertido y CHIP-8 ha existido mucho más tiempo de lo que hubiera imaginado. Así que supongo que tendré que aprender esto.
10

Python 3, 86 bytes

def d():
    import sys
    for y in range(5):
        line = []
        for x in range(16):
            line.append('@' if y*16+x == p else \
                        '"' if y*16+x == a else \
                        '.')
        print(''.join(line))
    print()
    sys.stdout.flush()

p=79;a=id(9)%p
while p-a:d();p+=[p%16<15,16*(p<64),-(p%16>0),-16*(p>15)][ord(input())%7%5]

Solo contando las dos líneas inferiores y soltando d();.

Lynn
fuente
Ahorré otro byte iniciando al jugador en la esquina inferior derecha (el "último" cuadro), y luego tomando muestras al azar de los primeros 79 cuadros.
Lynn
¡Vaya, lo siento, arreglado! Supongo que no soy sorprendente contando bytes manualmente. : <
Lynn
1
Creo que puedes salvar a otro personaje reemplazándolo a=id(9)%79con a=id(9)%p.
kirbyfan64sos
@ kirbyfan64sos ¡Brillante! Gracias.
Lynn
1
Además, si hace esto para Python 3, puede cambiar la raw_inputllamada a solo input.
kirbyfan64sos
10

C, 122 121 115 104 102 101 bytes

#define o ({for(int t=0;t<80;++t)t%16||putchar(10),putchar(t^p?t^a?46:34:64);})
p;main(a){for(a=1+time(0)%79;p^a;o,p+=(int[]){-16*(p>15),16*(p<64),-!!(p%16),p%16<15}[3&getchar()/2]);}

Primera vez publicando aquí! Espero que te guste :)

oes 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 ay identro mainde 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.

Quentin
fuente
Podría !!(p%16)ser p%16>0? No recuerdo mi orden de operaciones.
lirtosiast
@ThomasKwa lo es, pero ese unario -no puede evitar quedarse p, por lo que se necesitan paréntesis de cualquier manera. El doble golpe es solo ofuscación :)
Quentin
@Quentin 3 & getchar () / 2 <getchar () / 2-25
Mikkel Alan Stokkebye Christia
@MikkelAlanStokkebyeChristia gracias :)
Quentin
9

CJam, 46 45 44 40 39 37 bytes

{'.80*W$Gb'"t1$Gb'@tG/W%N*oNo}:P;
5,G,m*:Dmr~{P_l~4b2fm.+_aD&!$_W$=!}gP];

La 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

{'.80*W$Gb'"t1$Gb'@tG/W%N*oNo}:P;
5,G,m*:Dmr~{P_ZYm*l~(=:(.+_aD&!$_W$=!}gP];

A costa de cuatro bytes más, el formato de entrada se mejora significativamente:

  • Esta versión acepta 8, 2, 4y 6para arriba , abajo , izquierda y derecha , que coincide con las flechas correspondientes en el teclado numérico.
  • También acepta 7, 9, 1y 3para los correspondientes movimientos diagonales.

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í:

java -jar cjam-0.6.5.jar nethack.cjam

Para evitar presionar Enterdespués de cada tecla, y para actualizaciones en el lugar de la salida, puede usar este contenedor:

#!/bin/bash

lines=5
wait=0.05

coproc "$@"
pid=$!

head -$lines <&${COPROC[0]}

while true; do
    kill -0 $pid 2>&- || break
    read -n 1 -s
    echo $REPLY >&${COPROC[1]}
    printf "\e[${lines}A"
    head -$lines <&${COPROC[0]}
    sleep $wait
done

printf "\e[${lines}B"

Invocar así:

./wrapper java -jar cjam-0.6.5.jar nethack.cjam

Versión principal

5,G,   e# Push [0 1 2 3 4] and [0 ... 15].
m*:D   e# Take the Cartesian product and save in D.
mr~    e# Shuffle and dump the array on the stack.
       e# This pushes 80 elements. We'll consider the bottommost the amulet's
       e# position and the topmost the player's.
{      e# Do:
  P    e#   Call P.
  _    e#   Copy the player's position.
  l~   e#   Read and evaluate one line of input.
       e#      "6" -> 6, "9" -> 9, "B" -> 11, "E" -> 14 
  4b   e#   Convert to base 4.
       e#     6 -> [1 2], 9 -> [2 1], 11 -> [2 3], 14 -> [3 2]
  2f-  e#   Subtract 2 from each coordinate.
       e#     [1 2] -> [-1 0], [2 1] -> [0 -1], [2 3] -> [0 1], [3 2] -> [1 0]
  .+   e#   Add the result to the copy of player's position.
  _aD& e#   Push a copy, wrap it in an array and intersect with D.
  !    e#   Logical NOT. This pushes 1 iff the intersection was empty.
  $    e#   Copy the corresponding item from the stack.
       e#     If the intersection was empty, the new position is invalid
       e#     and 1$ copies the old position.
       e#     If the intersection was non-empty, the new position is valid
       e#     and 0$ copies the new position.
  _W$  e#   Push copies of the new position and the amulet's position.
  =!   e#   Push 1 iff the positions are different.
}g     e# While =! pushes 1.
P      e# Call P.
];     e# Clear the stack.

Versión alternativa

ZYm*   e# Push the Cartesian product of 3 and 2, i.e.,
       e#   [[0 0] [0 1] [0 2] [1 0] [1 1] [1 2] [2 0] [2 1] [2 2]].
l~     e#   Read and evaluate one line of input.
(=     e# Subtract 1 and fetch the corresponding element of the array.
:(     e# Subtract 1 from each coordinate.

Función P

'.80*  e# Push a string of 80 dots.
W$Gb   e# Copy the amulet's position and convert from base 16 to integer.
'"t    e# Set the corresponding character of the string to '"'.
1$Gb   e# Copy the player's position and convert from base 16 to integer.
'@t    e# Set the corresponding character of the string to '@'.
G/     e# Split into chunks of length 16.
W%     e# Reverse the chunks (only needed for the alternate program).
N*     e# Join the chunks, separating by linefeeds.
oNo    e# Print the resulting string and an additional linefeed.
Dennis
fuente
2
Estoy justo detrás de ti con TI-BASIC! Publicaré una vez que verifique mi solución.
lirtosiast el
8

Java, 231 bytes (196 si función)

Aquí está el código completo del programa en 342:

class H{public static void main(String[]a){int p=0,y=79,c;y*=Math.random();y++;p(p,y);do p((p=(c=new java.util.Scanner(System.in).next().charAt(0))<66&p%16>0?p-1:c==68&p%16<15?p+1:c>86&p>15?p-16:c==83&p<64?p+16:p),y);while(p!=y);}static void p(int p,int y){for(int i=0;i<80;i++){System.out.print((i==p?'@':i==y?'"':'.')+(i%16>14?"\n":""));}}}

Sin la función de impresión, 231:

class H{public static void main(String[]a){int p=0,y=79,c;y*=Math.random();y++;p(p,y);do p((p=(c=new java.util.Scanner(System.in).next().charAt(0))<66&p%16>0?p-1:c==68&p%16<15?p+1:c>86&p>15?p-16:c==83&p<64?p+16:p),y);while(p!=y);}}

Si solo una función está bien (no estoy claro por la especificación), entonces puedo reducir esto un poco más a 196:

void m(){int p=0,y=79,c;y*=Math.random();y++;p(p,y);do p((p=(c=new java.util.Scanner(System.in).next().charAt(0))<66&p%16>0?p-1:c==68&p%16<15?p+1:c>86&p>15?p-16:c==83&p<64?p+16:p),y);while(p!=y);}

Y con algunos saltos de línea para un poco de claridad ...

class H{
    public static void main(String[]a){
        int p=0,y=79,c;
        y*=Math.random();
        y++;p(p,y);
        do 
            p(
                (p=(c=new java.util.Scanner(System.in).next().charAt(0))<66&p%16>0?
                    p-1:
                    c==68&p%16<15?
                        p+1:
                        c>86&p>15?
                            p-16:
                            c==83&p<64?
                                p+16:
                                p)
                ,y);
        while(p!=y);
    }

    static void p(int p,int y){
        for(int i=0;i<80;i++){
            System.out.print((i==p?'@':i==y?'"':'.')+(i%16>14?"\n":""));
        }
    }
}

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.

Geobits
fuente
Prefiero formatear operadores ternarios anidados en el mismo nivel de sangría, como lo haría con una cadena de if / else if. Es más legible.
lirtosiast el
@ThomasKwa Sí, a veces lo he hecho en ambos sentidos. Esto se parece más a las sentencias if anidadas que a encadenadas. Me parece mejor porque las dos mitades de cada ternario están al mismo nivel, pero son distintas de las demás.
Geobits
Si una función anónima es aceptable, puede recortar su respuesta a 192 bytes: se void m()convierte en()->
ankh-morpork
@ dohaqatar7 Sí, pero no uso las funciones anon de Java para el golf de código. En principio, me parece dudoso que otros sientan lo mismo o no.
Geobits
Puedes hacer p+=?
lirtosiast
5

Java, 574 bytes

import java.util.*;public class N{static Random r=new Random();static int v,b,n,m;public static void main(String[] a){v=r.nextInt(16);b=r.nextInt(5);n=r.nextInt(16);m=r.nextInt(5);p();do{Scanner e=new Scanner(System.in);char m=e.next().charAt(0);if(m=='w')b=b>0?b-1:b;if(m=='s')b=b<5?b+1:b;if(m=='a')v=v>0?v-1:v;if(m=='d')v=v<16?v+1:v;p();}while(v!=n || b!=m);}static void p(){System.out.println();for(int y=0;y<5;y++){for(int x=0;x<16;x++){if(x==z && y==x)System.out.print('@');else if(x==n && y==m)System.out.print('"');else System.out.print('.');}System.out.println();}}}

Básicamente lo mismo que la versión C #, excepto ofuscado y minimizado.

fase
fuente
tantos espacios innecesarios ...;)
Será el
@ ¿Estaba arreglando eso ?: P
fase
1
Además, use nombres de una letra y ternaries.
lirtosiast el
@ThomasKwa corregido: D
fase
66
Todavía hay muchos espacios innecesarios y falta de ternarios;)
Será el
5

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

B=fill('.',5,16)
a=[rand(1:5),rand(1:16)]
B[a[1],a[2]]='"'
c=[1,a==[1,1]?2:1]
B[c[1],c[2]]='@'
for i=1:5 println(join(B[i,:]))end
while c!=a
B[c[1],c[2]]='.'
m=readline()[1]
c[2]+=m=='a'&&c[2]>1?-1:m=='d'&&c[2]<16?1:0
c[1]+=m=='w'&&c[1]>1?-1:m=='s'&&c[1]<5?1:0
m∈"wasd"&&(B[c[1],c[2]]='@')
for i=1:5 println(join(B[i,:]))end
end

Código puntuado, excluye la impresión (161 bytes):

a=[rand(1:5),rand(1:16)]
c=[1,a==[1,1]?2:1]
while c!=a
m=readline()[1]
c[2]+=m=='a'&&c[2]>1?-1:m=='d'&&c[2]<16?1:0
c[1]+=m=='w'&&c[1]>1?-1:m=='s'&&c[1]<5?1:0
end

La diferencia aquí es que no guardamos el estado del juego como una matriz; Toda la información relevante está contenida en las matrices cy a. 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):

# Initialize a 5x16 matrix of dots
B = fill('.', 5, 16)

# Get a random location for the amulet
a = [rand(1:5), rand(1:16)]

# Put the amulet in B
B[a[1], a[2]] = '"'

# Start the player in the upper left unless the amulet is there
c = [1, a == [1,1] ? 2 : 1]

# Put the player in B
B[c[1], c[2]] = '@'

# Print the initial game state
for i = 1:5 println(join(B[i,:])) end

# Loop until the player gets the amulet
while c != a

    # Put a dot in the player's previous location
    B[c[1], c[2]] = '.'

    # Read a line from STDIN, take the first character
    m = readline()[1]

    # Move the player horizontally within the bounds
    if m == 'a' && c[2] > 1
        c[2] -= 1
    elseif m == 'd' && c[2] < 16
        c[2] += 1
    end

    # Move the player vertically within the bounds
    if m == 'w' && c[1] > 1
        c[1] -= 1
    elseif m == 's' && c[1] < 5
        c[1] += 1
    end

    # Set the player's new location in B
    if m ∈ "wasd"
        B[c[1], c[2]] = '@'
    end

    # Print the game state
    for i = 1:5 println(join(B[i,:])) end

end
Alex A.
fuente
Creo que está bien
3
+1 para la versión comprimida / ofuscada que se parece mucho a lo que recuerdo del código fuente real de nethack.
Ben Jackson
Puede guardar algunos bytes utilizando una aleatorización peor:a=[rand(1:5),1] c=a+1
lirtosiast el
@ThomasKwa: ¿Qué divertido es eso si siempre está en la primera línea? :)
Alex A.
3

Lote, 329 bytes

@echo off
set e=goto e
set f= set/a
%f%a=0
%f%b=0
%f%c=%random%*3/32768+1
%f%d=%random%*16/32768+1
:et
call:p %a% %b% %c% %d%
if %a%%b% EQU %c%%d% exit/b
choice/C "wasd"
goto %errorlevel%
:1
%f%a-=1
%e%
:2
%f%b-=1
%e%
:3
%f%a+=1
%e%
:4
%f%b+=1
:e
if %a% GTR 4%f%a=4
if %a% LSS 0%f%a=0
if %b% GTR 15%f%b=15
if %b% LSS 0%f%b=0
%e%t

:p
setlocal enabledelayedexpansion
::creating a new line variable for multi line strings
set NL=^


:: Two empty lines are required here
cls
set "display="
for /l %%r in (0,1,4) do (
    set "line="
    for /l %%c in (0,1,15) do (
        set "char=."
        if %3 EQU %%r (
            if %4 EQU %%c (
                set char="
            )
        )
        if %1 EQU %%r (
            if %2 EQU %%c (
                set "char=@"
            )
        )
        set "line=!line!!char!"
    )
    set "display=!display!!line!!NL!"
)
echo !display!
exit /b
ankh-morpork
fuente
Esto es muy impresionante. Me sorprende que sea posible hacer esto.
eis
Esto no muestra la mazmorra para mí, solo una serie de líneas que provocan [W, A, S, D]. Parece "funcionar": caminar por la mazmorra no mostrada finalmente se cierra. win7 cmd.exe
Dan Pritts
Funciona para mí con Win7 cmd.exe - cuando escribo ver me saleMicrosoft Windows [Version 6.1.7601]
Jerry Jeremiah
@DanPritts Eso es extraño. Funciona perfectamente para mí en Windows 8 ( Microsoft Windows [Version 6.2.9200])
ankh-morpork
doh, no había copiado y pegado todo, no me desplacé hacia abajo en la ventana. Bien hecho.
Dan Pritts
3

Perl, 228 222 caracteres (sin contar las nuevas líneas que no son parte integral del funcionamiento del código) - 207 si no cuenta las partes printy la print ifdeclaració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.

($a=$==rand(79))+=($a>=($==rand(80)));
print $_=("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/gr;
%r=qw(w s/.(.{16})@/@\1./s a s/.@/@./ s s/@(.{16})./.\1@/s d s/@./.@/);
while(/"/){print if eval $r{getc STDIN}}

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:

($a=$==rand(79))+=($a>=($==rand(80)));

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 ( randentrega 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 $apara 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.

print $_=("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/gr;

Esto genera el campo inicial, y luego imprime es. ("."x80)solo genera una cadena de 80 puntos. =~s/(.{$=})./\1@/rluego reemplaza el $=carácter th con @, y =~s/(.{$=})./\1@/rel $acarácter th con ". Debido al rmodificador, 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/grinserta 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.

%r=qw(w s/.(.{16})@/@\1./s a s/.@/@./ s s/@(.{16})./.\1@/s d s/@./.@/);

Esto crea un hash que contiene las reglas de reemplazo para los diferentes movimientos. Una versión más legible de esto es

%r = ( 'w' => 's/.(.{16})@/@\1./s',
       'a' => 's/.@/@./',
       's' => 's/@(.{16})./.\1@/s',
       'd' => 's/@./.@/' );

Las claves son los caracteres para los movimientos, y los valores son cadenas que contienen la regla de reemplazo correspondiente.

while(/"/){print if eval"\$_=~$r{getc STDIN}"}

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 %ry 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 caso printse ejecuta. Como se llama sin argumento, imprime $_, es decir, el campo modificado.

celtschk
fuente
1
El hecho de que incluya saltos de línea para facilitar la lectura no significa que tenga que contarlos. Veo 228 bytes. Además, según las reglas específicas de esta pregunta, la parte de impresión de su código no contribuye al recuento de bytes.
Dennis
@Dennis: Para la parte de impresión, vea la explicación que he agregado ahora: No puede separar significativamente la impresión y la evaluación en mi código. Ahora cambié el conteo como sugeriste.
celtschk
¿Hay algún cambio de estado en su código de impresión? ¿No? Bueno, en mi opinión, reutilizar la salida de su código de impresión para su lógica no debería penalizarlo. El código de movimiento (¡que es distinto!) Debería contar, pero el código que genera la "cadena de visualización" no debería contar.
Yakk
@Yakk: ¿Qué parte de mi código considera el código de impresión? (En realidad, mi opinión es que la exclusión del código de impresión de contar era una mala idea, precisamente porque no siempre está bien definido qué "código de impresión" es.)
celtschk
@celtschk ("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/grestá bastante cerca a primera vista, pero mi perl-fu tiene algunos años oxidado. Me podría haber perdido un cambio de estado allí.
Yakk
2

C #, 256 248 234 227 226 225 bytes

Utiliza las flechas de NumPad con NumLock activado para moverse.

Sangrado y comentado para mayor claridad:

using System;
class P{
    static void Main(){
        int a=0,b=0,c,d,e;
        var r=new Random();
        while(0<((c=r.Next(16))&(d=r.Next(5))));
        Draw(a,b,c,d); // Excluded from the score.
        while(a!=c|b!=d){
            e=Console.ReadKey().KeyChar-48;
            a+=e==4&a>0?-1:e==6&a<15?1:0;
            b+=e==8&b>0?-1:e==2&b<4?1:0;
            Draw(a,b,c,d); // Excluded from the score.
        }
    }
    // The following method is excluded from the score.
    static void Draw(int a, int b, int c, int d){
        Console.Clear();
        for (int y = 0; y < 5; y++)
        {
            for (int x = 0; x < 16; x++)
            {
                Console.Write(
                    x == a && y == b ? '@' :
                    x == c && y == d ? '"' :
                                       '.'
                );
            }
            Console.WriteLine();
        }
    }
}
Hand-E-Food
fuente
1
Creo que C # ints implícitamente init a cero. Además (no se puede verificar en este momento) si la conversión no es un problema, puede convertir los literales de caracteres en caracteres, o al menos la 'a' a 97 (creo), aunque los otros son tres dígitos.
Solo los campos de clase se inicializan de forma predeterminada, y eso requiere que se declaren estáticos en este caso. Las variables de método deben inicializarse antes del primer uso. Eso requiere menos personajes: 4 contra 7.
Hand-E-Food
¡Gracias @tolos por el consejo de enviar implícitamente char a int! Mejor aún, si uso el enunciado ConsoleKey enum como int, puedo usar valores de 2 dígitos.
Hand-E-Food
Técnicamente, Mainno es necesario invocar el método Main, por lo que podría eliminar otros tres caracteres.
Luaan
@Luaan, creo que te equivocas. Documentación de C #: msdn.microsoft.com/en-us/library/acy3edy3.aspx
Hand-E-Food
2

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.

<textarea id=T onclick='s()' onkeyup='m(event.keyCode)'></textarea>
<script>
R=n=>Math.random()*n|0,
s=e=>m(y=R(5),x=R(8),a=R(5)*17+R(8)+8),
m=k=>(x+=(x<15&k==39)-(x>0&k==37),y+=(y<4&k==40)-(y>0&k==38),p=y*17+x,
T.value=p-a?(t=[...('.'.repeat(16)+'\n').repeat(5)],t[a]='X',t[p]='@',t.join('')):t='Well done!'
)
</script>

Fragmento de EcmaScript 6 (solo Firefox)

R=n=>Math.random()*n|0
s=e=>m(y=R(5),x=R(8),a=R(5)*17+R(8)+8)
m=k=>(
  x+=(x<15&k==39)-(x>0&k==37),
  y+=(y<4&k==40)-(y>0&k==38),
  p=y*17+x,
  T.value=p-a?(t=[...('.'.repeat(16)+'\n').repeat(5)],t[a]='"',t[p]='@',t.join('')):t='Well done!'
)
<textarea id=T onclick='s()' onkeyup='m(event.keyCode)'></textarea>

Fragmento de EcmaScript 5 (probado en Chrome)

function R(n) { return Math.random()*n|0 }

function s() { m(y=R(5),x=R(8),a=R(5)*17+R(8)+8) }

function m(k) {
  x+=(x<15&k==39)-(x>0&k==37)
  y+=(y<4&k==40)-(y>0&k==38)
  p=y*17+x
  T.value=p-a?(t=('.'.repeat(16)+'\n').repeat(5).split(''),t[a]='"',t[p]='@',t.join('')):t='Well done!'
}
<textarea id=T onclick='s()' onkeyup='m(event.keyCode)'></textarea>

edc65
fuente
2

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:

package
{
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.text.TextFormat;

    public class MiniRogue extends Sprite
    {
        var a:int, p:int, t;

        public function MiniRogue()
        {
            g();
        }

        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-=16
                if(e.keyCode==83&&p<64)
                    p+=16
                if(e.keyCode==65&&p%16>0)
                    p--
                if(e.keyCode==68&&(p+1)%16>0)
                p++
                print()
            });
            print()
        }

        var old:int = -1;
        private function print():void {
            if (!t) {
                t = new TextField()
                t.defaultTextFormat = new TextFormat("_typewriter", 8)
                t.width=500;
                t.height=375;
                addChild(t)
            }
            var board:String = "";
            for (var i:int=0; i<80;i++) {
                if (i == p) {
                    board += "@";
                } else if (i == a) {
                    board += '"';
                } else {
                    board += ".";
                }
                if ((i + 1) % 16 == 0) {
                    board += "\n";
                }
            }
            if (a==p) {
                board += "Win!";
            }
            if (p == old) {
                board += "Bump!";
            }
            old = p;
            t.text = board;
        }
    }
}
Brian
fuente
2

Javascript: 307 216

¡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:

  1. presione "ejecutar fragmento de código"
  2. presione ctrl-shift-j para abrir la consola
  3. haga clic en la sección de resultados
  4. usa las teclas de flecha y juega

var x=y=2,m=Math,b=m.floor(m.random()*5),a=14,i,j,t,c=console,onload=d;function d(){c.clear();for(i=0;i<5;i++){t=i;for(j=0;j<16;j++){t+=(i==y&&j==x)?"@":(i==b&&j==a)?'"':".";if(a==x&&b==y)t=":)";}c.log(t);}}onkeydown=function(){switch(window.event.keyCode){case 37:if(x>0)x--;break;case 38:if(y>0)y--;break;case 39:if(x<15)x++;break;case 40:if(y<4)y++;break;}d();};

Sin golf:

var px=py=2,m=Math,ay=m.floor(m.random()*5),ax=14,i,j,t,c=console,onload=draw;
function draw() {
  c.clear();
  for(i=0;i<5;i++) {
    t=i;
    for(j=0;j<16;j++) {
      t+=(i==py&&j==px)?"@":
         (i==ay&&j==ax)?'"':".";
      if(ax==px&&ay==py)t=":)";
    }
    c.log(t);
  }
}
onkeydown=function() {
  switch (window.event.keyCode) {
    case 37:
      if(px>0)px--;
      break;
    case 38:
      if(py>0)py--;
      break;
    case 39:
      if(px<15)px++;
      break;
    case 40:
      if(py<4)py++;
      break;
  }
  draw();
};

Edición 1: lea las reglas con más cuidado y reescribí mi código en consecuencia

  • el valor del amuleto y ahora está aleatorizado
  • el jugador ya no puede escapar de la habitación
  • Ya no cuento los caracteres en la función de dibujo o las llamadas a ella
Eric Vincent
fuente
1

SpecBAS - 428 402 (excluyendo impresión, 466 425 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.

1 PRINT ("."*16+#13)*5
2 LET px=8: LET py=3
3 LET ax=INT(RND*16): LET ay=INT(RND*5): IF ax=px AND ay=py THEN GO TO 3
4 PRINT AT ay,ax;#34;AT py,px;"@": LET ox=px: LET oy=py: PAUSE 0: LET k$=INKEY$
5 LET px=px+(k$="p")-(k$="o")
6 IF px<0 THEN LET px=0
7 IF px>15 THEN LET px=15
8 LET py=py+(k$="a")-(k$="q")
9 IF py<0 THEN LET py=0
10 IF py>4 THEN LET py=4
11 PRINT AT oy,ox;"."
12 IF SCREEN$(px,py)<>#34 THEN GO TO 4

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.

Brian
fuente
Es posible que pueda guardar algunos caracteres aleatorizando menos bien: 2 LET px=1: LET py=1: LET ax=2: LET ay=INT(RND*5)y también usando IF instead of ELSE IF.
lirtosiast
1

Otro C #, 221 171 170

Aquí 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.

using System;
class P
{
static void Main()
{
Func<int> n=new Random().Next;
int x=n()%16,y=n()%5,a=n()%16,b,m;
while(y==(b=n()%5));

while(x!=a|y!=b)
{
Printer.Print(a, b, x, y);  // Excluded from the score.
m=Console.Read()-48;
y+=m==8&y>0?-1:m==2&y<4?1:0;
x+=m==4&x>0?-1:m==6&x<15?1:0;
}
}
}


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

using System;
class P
{
static void Main()
{
int p=79,a=new Random().Next()%p,m;
while(p!=a){
Printer.Print(p,a);  // Excluded from the score.
m=Console.Read()-48;
p+=m==4&p/5>0?-5:m==6&p/5<15?5:m==8&p%5>0?-1:m==2&p%5<4?1:0;
}
}
}

La clase de impresora es casi la misma, solo una nueva sobrecarga de impresión ...

class Printer
{
    public static void Print(int ax, int ay, int px, int py)
    {
        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');
        }
    }

    public static void Print(int p, int a)
    {
        Print(p/5,p%5,a/5,a%5);
    }
}
Phil
fuente
1

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.

def display(ax,ay,px,py)
    puts
    for y in 0..4
        for x in 0..15
            if (x == px && y == py)
                print "@"
            elsif (x == ax && y == ay)
                print '"'
            else
                print '.'
            end
        end
        puts
    end
end


x=y=0
a=Random.rand(16) while y==(b=Random.rand(5))
while x!=a or y!=b
display(a,b,x,y)  # Excluded from the score.
m=gets.chomp.to_i
y-=m==8?1:0 if y>0
y+=m==2?1:0 if y<4
x-=m==4?1:0 if x>0
x+=m==6?1:0 if x<15
end
Phil
fuente
0

QBasic, 103 bytes

Según las reglas del desafío, el Showsubprograma no está incluido en el conteo de bytes, ni la Show p, q, a, bllamada (con la siguiente línea nueva).

b=1+TIMER MOD 9
1Show p, q, a, b
INPUT m
p=p-(m=2)*(p>0)+(m=4)*(p<4)
q=q-(m=1)*(q>0)+(m=3)*(q<15)
IF(p<>a)+(q<>b)GOTO 1


SUB Show (playerRow, playerCol, amuletRow, amuletCol)
CLS
FOR row = 0 TO 4
  FOR col = 0 TO 15
    IF row = playerRow AND col = playerCol THEN
      PRINT "@";
    ELSEIF row = amuletRow AND col = amuletCol THEN
      PRINT CHR$(34);    ' Double quote mark
    ELSE
      PRINT ".";
    END IF
  NEXT
  PRINT
NEXT
END SUB

Para moverse, ingrese un número y presione Entrar: 1para ir a la izquierda, 2para subir, 3para ir a la derecha y 4para 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, bdespués de la IFdeclaración.

Explicación

Deje a, brepresentar las coordenadas del amuleto y p, qlas 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 0falso, -1verdadero. Veamos la declaración de actualización de la fila del jugador:

p=p-(m=2)*(p>0)+(m=4)*(p<4)

Si m=2, queremos avanzar restando 1 de p, siempre que p>0. Del mismo modo, si m=4, queremos movernos hacia abajo agregando 1 a p, siempre que p<4. Podemos obtener el comportamiento deseado multiplicando. Si ambos factores son -1, su producto será 1, lo que podemos restar o agregar p. Si cualquiera de los condicional es 0, el producto será 0, sin efecto.

Del mismo modo, la condición para determinar si el jugador ha encontrado el amuleto es:

IF(p<>a)+(q<>b)GOTO 1

Si cualquiera de los condicionales es verdadero, su suma será distinta de cero (cualquiera -1o -2) y, por lo tanto, verdadera, y el programa volverá a la línea 1. Una vez que sea pigual ae qigual b, ambos condicionales lo serán 0, por lo que su suma será 0y el flujo de control puede alcanzar el Fin del programa.

DLosc
fuente