NetHack minimo


64

NetHack è un gioco roguelike in cui un giocatore deve recuperare l'Amuleto di Yendor dal livello più basso del sotterraneo. Comunemente giocato via telnet, l'intero gioco è rappresentato con grafica ASCII. Il gioco è estremamente impegnativo e richiede la conoscenza di molte meccaniche di gioco per avere successo.

Ai fini di questa sfida, supponi che l'intero dungeon sia un singolo livello e solo 5 × 16 personaggi. Inoltre, supponi che si tratti di un dungeon "sicuro" o che stai implementando solo un prototipo: non ci saranno mostri, preoccupazioni per la fame, ecc. In effetti, devi solo tenere traccia della posizione del personaggio, dell'amuleto e del gioco termina effettivamente quando il giocatore arriva nella stessa posizione dell'amuleto.

Requisiti della sfida

  • Ci sarà un dungeon 5 × 16 (livello singolo).
  • Dai al giocatore una posizione di partenza (facoltativamente casuale) e l'amuleto una casistica separata (diversa ogni volta che il programma viene eseguito) all'interno della prigione. Cioè, l'amuleto non può iniziare nella stessa casella del giocatore.
  • Accetta quattro tasti di input che muovono il giocatore di un quadrato alla volta (quattro direzioni cardinali). È consentita la lettura / elaborazione di altri input (una funzione readline () che richiede la pressione di 'enter', ecc.).
  • Viaggiare fuori dai confini della prigione non è permesso. Ad esempio, se il giocatore si trova sul bordo destro del sotterraneo premendo a destra non dovrebbe fare nulla.
  • Dopo la generazione iniziale e dopo ogni movimento, stampa lo stato del gioco. Poiché si tratta di code golf e la stampa non è abbastanza interessante, ignorare il conteggio dei caratteri per la funzione di stampa e la chiamata di funzione presupponendo che non vi siano cambiamenti di stato . Le celle vuote dovrebbero essere mostrate come punto ( .), amuleto come virgoletta doppia ( ") e carattere come simbolo ( @).
  • Il gioco termina quando il giocatore "scopre" l'amuleto (arriva nella stessa casella)

vincente

Questa è una sfida di golf del codice, il codice più breve per soddisfare i requisiti tra una settimana da oggi sarà dichiarato vincitore.

Esempio

Ecco una soluzione di esempio in C # (non salvato) per mostrare i requisiti di base e l'output di esempio.

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');
            }
        }
    }
}

Il conteggio totale dei caratteri è 1474, ma ignorando le chiamate alla funzione di stampa e la sua definizione è il conteggio dei caratteri finali 896.

Uscita durante l'esecuzione del programma:

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

Uscita (incluso sopra) dopo aver premuto due volte il tasto 'a':

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

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

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

10
Ho la sensazione che questo sarà di interesse per @Doorknob.
Alex A.

10
Rogue è il gioco roguelike originale in cui un giocatore deve recuperare l'Amuleto di Yendor dal livello più basso del sotterraneo. Perché non chiamare questo un Ladro minimale?
Gilles 'SO- smetti di essere malvagio' il

5
@Gilles Perché non chiamarlo un serpente minimale?
Casey Kuball,

26
Psshh, nessun movimento diagonale? No yubnhjkl? Nemmeno una scala su per salire dopo aver ottenuto l'amuleto? : P ( voti furiosi comunque )
Maniglia della porta

2
@tolos: Non sono ancora chiaro ciò che conta come casuale qui. Non è davvero possibile soddisfare i diversi ogni volta che il programma viene eseguito se il programma viene eseguito 80 volte ... Nello specifico, in questa risposta , l'amuleto può occupare solo 9 di tutte le 79 posizioni possibili. Questo conta?
Dennis,

Risposte:


37

TI-BASIC, 42 41 38 36 35 byte

Per la tua calcolatrice grafica serie TI-83 o 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

Quale direzione prenderà il giocatore è una funzione del codice tasto del tasto premuto, ma quattro tasti che funzionano sicuramente sono questi nella riga superiore:

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

L'amuleto inizia su una delle cinque caselle nella prima colonna e il giocatore inizia nella casella in basso a destra. Ad esempio, una possibile disposizione è:

................
¨...............
................
................
...............@

Spiegazione

La posizione del giocatore viene memorizzata come un numero complesso da 0+0ia 15+4i, dove la parte reale va a destra e la parte immaginaria scende. Questo facilita il facile controllo dei confini in alto e a sinistra: semplicemente spostiamo leggermente il numero e arrotondiamo verso zero. Ad esempio, se l'offset è 0.5e la nostra posizione è -1+3i(fuori dallo schermo a sinistra), allora la posizione verrà corretta iPart(-0.5+3.5i)=0+3i, dove dovrebbe essere. Il controllo dei limiti inferiore e destro è leggermente più complicato; dobbiamo sottrarre il numero da una costante C, che è circa 15.635 + 4.093i(è la più breve che potessi trovare tra 15+4ie 16+5i), arrotondare, sottrarre di Cnuovo per capovolgere il numero e arrotondare di nuovo.

Quando viene premuto un tasto, la posizione del giocatore non aggiustata si sposta di 1 unità in una direzione, ma la parte intera cambia solo quando vengono premuti determinati tasti. Fortunatamente, le chiavi che funzionano sono tutte nella riga superiore. Di seguito è riportato un grafico degli offset nei casi in cui vengono premuti i tasti 11, 12, 13 e 15 e quando non viene premuto alcun tasto (Nessuna pressione è il punto all'interno del quadrato centrale, facendo in modo che le parti intere rimangano invariate; i quattro tasti premono 'offset hanno parti intere diverse). Cè la croce rossa al centro del cerchio.

inserisci qui la descrizione dell'immagine

Vecchio codice (42 byte):

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

limitazioni

Non c'è modo di sfuggire a un "carattere, quindi le stringhe con a "non possono essere generate all'interno di un programma. Pertanto, questo utilizza il segno umlaut ¨invece di una virgoletta (se esistesse una stringa già esistente con una virgoletta, potrei visualizzarla). Per ottenere ¨e @in un programma, è necessario uno strumento esterno; tuttavia, è valido TI-BASIC.


2
Solo per divertimento, ho creato questo frammento che inserisce la diaeresi e il simbolo @ in Str1 (al contrario di "uno strumento esterno"). Seleziona la riga in alto che corrisponde alla tua calcolatrice, inseriscila in un nuovo programma ed esegui quel programma con Asm (.
MI Wright

Oh, ho dimenticato di scrivere il codice macchina sulla calcolatrice. Non voglio mandare in crash il mio con un mistype, ma confido che funzioni.
lirtosiast

44

CHIP-8 , 48 byte

Questo non può essere considerato legale, ma perché no. Ho scritto il mio programma in CHIP-8, un linguaggio di programmazione basato su bytecode per una console di gioco virtuale. Puoi provare il programma completo (99 byte) nel tuo browser usando un emulatore / debugger che ho scritto chiamato Octo:

Immagine dello schermo

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

Un dump esadecimale di quel programma completo è il seguente:

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

È possibile spostare il lettore con i tasti ASWD o 7589 sulla tastiera CHIP-8 originale. Se rimuovo tutto il codice e i dati per disegnare lo sfondo e il lettore, ottengo invece questo dump da 48 byte:

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 e non definita del programma è stata scritta in un linguaggio assembly di alto livello come segue:

: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

Si noti che i byte compilati stessi sono il linguaggio di programmazione CHIP-8; l'assemblatore è semplicemente un mezzo più conveniente per comporre tali programmi.


19
Strumento giusto per il lavoro.
Dennis,

6
+1 per avermi fatto perdere un sacco di tempo giocando il tuo gioco ancora e ancora.
Alex A.

4
@AlexA. se vuoi perdere ancora più tempo, dovresti provare Cave Explorer . La mossa ASWD negli overworld e il QE sono usati per ripristinare / spostare i blocchi nei livelli platform.
Giovanni,

4
Bene, va bene il mio fine settimana.
Alex A.

1
All'inizio ero scettico, ma Cave Explorer era divertente e CHIP-8 è stato in giro molto più a lungo di quanto avrei immaginato. Quindi immagino che dovrò imparare questo.

10

Python 3, 86 byte

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]

Contando solo le due righe inferiori e scendendo d();.


Ho salvato un altro byte avviando il giocatore nell'angolo in basso a destra (l '"ultimo" quadrato), quindi campionando casualmente dai primi 79 quadrati.
Lynn,

Oops, scusa, risolto! Immagino di non essere eccezionale nel contare manualmente i byte. : <
Lynn,

1
Penso che puoi salvare un altro personaggio sostituendolo a=id(9)%79con a=id(9)%p.
kirbyfan64sos,

@ kirbyfan64sos Brilliant! Grazie.
Lynn,

1
Inoltre, se lo fai per Python 3, puoi cambiare la raw_inputchiamata in just input.
kirbyfan64sos,

10

C, 122 121 115 104 102 101 byte

#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]);}

La prima volta che pubblichi qui! Spero vi piaccia :)

oè la funzione di stampa, erm. Il nostro eroe coraggioso può essere spostato con 2, 4, 6 e 8, ma attenzione a non inviare altri input (nessuna nuova riga!).

Aggiornamento 1: portato ae inei mainparametri di.

Aggiornamento 2: OP dopo aver confermato che una singola stringa di input è OK, mi sono sbarazzato di scanf(che ho usato per saltare la nuova riga).

Aggiornamento 3: utilizzato un array composto letterale e modificato il layout di input. Il programma ora va in tilt se si immette una direzione non valida;)

Aggiornamento 4: notato che la chiamata alla funzione di stampa non conta. Ha preso atto di leggere le regole più attentamente.

Aggiornamento 5: un byte salvato, grazie a Mikkel Alan Stokkebye Christia.


Potrebbe !!(p%16)essere p%16>0? Non ricordo il mio ordine delle operazioni.
lirtosiast,

@ThomasKwa lo è, ma quell'unario non -può fare a meno di attenersi p, quindi le parentesi sono necessarie in entrambi i modi. Il doppio botto è solo offuscamento :)
Quentin,

@Quentin 3 & getchar () / 2 <getchar () / 2-25
Mikkel Alan Stokkebye Christia

@MikkelAlanStokkebyeChristia grazie :)
Quentin

9

CJam, 46 45 44 40 39 37 byte

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

La prima riga (definisce una funzione che stampa lo stato corrente del gioco) e le P sulla seconda riga (chiama quella funzione) non contribuiscono al conteggio dei byte.

Sia la posizione iniziale che la posizione dell'amuleto sono selezionate in modo pseudo casuale. La distribuzione è uniforme e il PRNG sottostante lo consente.

Ingresso è E, 6, 9e Bper Up , Giù , Sinistra e Destra , con Caps Lockattivato, seguito da Enter.

Versione alternativa

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

Al costo di altri quattro byte, il formato di input è migliorato in modo significativo:

  • Questa versione accetta 8, 2, 4e 6per Up , Giù , Sinistra e Destra , che abbina i tasti freccia corrispondenti sul tastierino numerico.
  • Esso accetta anche 7, 9, 1e 3per i corrispondenti movimenti diagonali.

analisi

Poiché l'I / O è interattivo, è necessario provare questo codice con l' interprete Java .

Scarica l'ultima versione ed esegui il programma in questo modo:

java -jar cjam-0.6.5.jar nethack.cjam

Per evitare di premere Enterdopo ogni tasto e per gli aggiornamenti sul posto dell'output, è possibile utilizzare questo wrapper:

#!/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"

Invoca in questo modo:

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

Versione principale

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.

Versione 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.

Funzione 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.

2
Sono sulla tua coda con TI-BASIC! Pubblicherò una volta verificato la mia soluzione.
Lirtosiast,

8

Java, 231 byte (196 se funzione)

Ecco il codice completo del programma a 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":""));}}}

Senza la funzione di stampa, 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);}}

Se solo una funzione va bene (non sono chiaro dalle specifiche), allora posso ridurlo un po 'più 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);}

E con alcune interruzioni di riga per un po 'di chiarezza ...

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":""));
        }
    }
}

Nota che non sto contando la funzione di stampa p(p,y)stessa, ma sto contando la chiamata in quanto ho delle cose che cambiano all'interno dell'istruzione call.

Funziona con lettere maiuscole ASDW. A causa del modo in cui controlla quelli, anche alcune altre lettere potrebbero funzionare, ma le specifiche non dicono davvero cosa dovrebbe succedere se premo tasti diversi.


Preferisco formattare operatori ternari nidificati allo stesso livello di rientro, come faresti con una catena di if / else if. È più leggibile.
Lirtosiast,

@ThomasKwa Sì, a volte l'ho fatto in entrambi i modi. È più simile a istruzioni nidificate se concatenate. Mi sento meglio perché entrambe le metà di ogni ternario sono allo stesso livello, ma distinte dalle altre.
Geobits il

Se una funzione anonima è accettabile, puoi tagliare la tua risposta a 192 byte: void m()diventa()->
ankh-morpork il

@ dohaqatar7 Sì, ma non uso le funzioni anon di Java per il golf del codice. In linea di principio, mi sembra ombroso, indipendentemente dal fatto che gli altri provino lo stesso.
Geobits il

Si può fare p+=?
lirtosiast

5

Java, 574 byte

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();}}}

Sostanzialmente uguale alla versione C #, tranne che offuscata e ridotta a icona.


così tanti spazi inutili ...;)
Will

@ Volevo solo aggiustarlo: P
fase

1
Inoltre, usa nomi di una sola lettera e ternari.
Lirtosiast,

@ThomasKwa risolto: D
fase

6
Ci sono ancora molti spazi inutili e mancanza di ternari;)
Will

5

Julia, 161 byte

Usi w, a, s, e dper spostarsi in alto, a sinistra, in basso, ea destra, rispettivamente.

Codice completo, inclusa la stampa (330 byte):

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

Codice con punteggio, esclusa la stampa (161 byte):

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 differenza qui è che non salviamo lo stato del gioco come matrice; tutte le informazioni pertinenti sono contenute negli array ce a. E, naturalmente, non viene stampato nulla. All'utente non verrà più richiesto l'inserimento una volta che il giocatore avrà raggiunto l'amuleto.


Ungolfed + spiegazione (codice 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

Penso che

3
+1 per la versione compressa / offuscata dall'aspetto molto simile a quello che ricordo dell'effettivo codice sorgente di nethack.
Ben Jackson,

Puoi salvare alcuni byte usando una randomizzazione peggiore:a=[rand(1:5),1] c=a+1
lirtosiast

@ThomasKwa: che divertimento è che è sempre in prima linea? :)
Alex A.

3

Lotto, 329 byte

@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

Questo è molto impressionante. Sono sorpreso che sia possibile farlo.
eis,

Questo non mostra il dungeon per me, solo una serie di righe che suggeriscono [W, A, S, D] ?. Sembra "funzionare" - alla fine il dungeon non visualizzato viene chiuso. win7 cmd.exe
Dan Pritts

Funziona per me con Win7 cmd.exe - quando scrivo ver ottengoMicrosoft Windows [Version 6.1.7601]
Jerry Jeremiah

@DanPritts È strano. Funziona perfettamente per me su Windows 8 ( Microsoft Windows [Version 6.2.9200])
ankh-morpork

doh, non avevo copiato e incollato il tutto, non ho fatto scorrere verso il basso nella finestra. Molto bene.
Dan Pritts,

3

Perl, 228 222 caratteri (senza contare le nuove righe che non sono parte integrante del funzionamento del codice) - 207 se non si contano le parti dell'istruzione printe print ifutilizzate per la stampa, ma non si aggiungono alla logica del gioco; 144 se si considera anche il codice di generazione della rappresentazione del campo come parte della stampa, come suggerito da Yakk nei commenti)

Questo codice utilizza wasd minuscolo per il controllo; l'immissione deve essere confermata con Invio. Testato 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}}

Si noti che per questo codice, è impossibile separare il calcolo e la stampa, poiché le operazioni vengono eseguite direttamente sulla rappresentazione stampata utilizzando espressioni regolari.

Spiegazione:

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

Questa linea determina la posizione del giocatore e dell'amuleto. La posizione del giocatore è determinata da $==rand(80)ed è in realtà facile da capire: su una tavola 5 × 16, ci sono 80 posizioni distinte in cui il giocatore può trovarsi. La posizione viene memorizzata nella $=variabile che forza il valore memorizzato in numero intero; ciò consente di risparmiare alcuni byte per non dover esplicitamente eseguire il cast del risultato in numero intero ( randfornisce un valore in virgola mobile).

Poiché una delle posizioni è già occupata dal giocatore, vengono utilizzate solo 79 posizioni per l'amuleto, quindi $a=$==rand(79)viene utilizzata la posizione dell'amuleto . Ancora una volta, il compito di $=forzare una conversione in numero intero, tuttavia lo assegno ulteriormente $aper riutilizzarlo $=per la posizione del giocatore.

Ora, per evitare che l'amuleto occupi la stessa posizione del giocatore, viene avanzato di una posizione se la sua posizione è almeno grande quanto quella del giocatore, dando una distribuzione uniforme sui luoghi non occupati dal giocatore. Questo è ottenuto da $a = ($a >= $=)dove $=qui detiene la posizione del giocatore. Ora la prima riga viene generata inserendo le due assegnazioni iniziali anziché le prime $a$ and the only$ = `in questa espressione.

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

Questo genera il campo iniziale e successivamente le stampe lo sono. ("."x80)genera solo una stringa di 80 punti. =~s/(.{$=})./\1@/rquindi sostituisce il $=carattere th con @e =~s/(.{$=})./\1@/ril $acarattere th con ". A causa del rmodificatore non provano a modificarsi sul posto, ma restituiscono la stringa modificata, ecco perché possono essere applicati alle espressioni precedenti. Infine, =~s/(.{16})/\1\n/grinserisce una nuova riga ogni 16 caratteri. Si noti che il campo è memorizzato nella variabile speciale $_che può essere utilizzata implicitamente nelle istruzioni successive.

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

Questo crea un hash contenente le regole di sostituzione per le diverse mosse. Una versione più leggibile di questo è

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

Le chiavi sono i caratteri delle mosse e i valori sono stringhe contenenti la regola di sostituzione corrispondente.

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

Questo è il ciclo principale. while(/"/)controlla se è ancora presente un "carattere $_(ovvero, nel campo). Se ci spostiamo sull'amuleto, il suo personaggio viene sostituito con il personaggio del giocatore in modo che scompaia dal campo.

eval $r{getc STDIN}legge un carattere dall'input standard, cerca la regola di sostituzione corrispondente dall'ha %re lo applica al $_campo. Ciò viene considerato vero se è stata effettivamente effettuata una sostituzione (ovvero, la chiave è stata trovata nell'hash e la mossa era possibile; una mossa impossibile non corrisponderà nella regola di sostituzione). In tal caso printviene eseguito. Poiché viene chiamato senza argomento, stampa $_, ovvero il campo modificato.


1
Solo perché includi i feed di linea per la leggibilità non significa che devi contarli. Vedo 228 byte. Inoltre, in base alle regole specifiche di questa domanda, la parte stampata del codice non contribuisce al conteggio dei byte.
Dennis,

@Dennis: per la parte relativa alla stampa, vedere la spiegazione che ho aggiunto ora: non è possibile separare in modo significativo stampa e valutazione nel mio codice. Ora ho cambiato il conteggio come mi hai suggerito.
Celtschk,

Ci sono cambiamenti di stato nel tuo codice di stampa? No? Bene, secondo me, riutilizzare l'output del tuo codice di stampa per la tua logica non dovrebbe penalizzarti. Il codice di movimento (che è distinto!) Dovrebbe essere conteggiato, ma il codice che genera la "stringa di visualizzazione" non dovrebbe essere conteggiato.
Yakk,

@Yakk: Quale parte del mio codice consideri il codice di stampa? (In realtà la mia opinione è che l'esclusione del codice di stampa dal conteggio sia stata una cattiva idea, proprio perché non è sempre ben definito quale sia il "codice di stampa".)
Celtschk,

@celtschk ("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/grè abbastanza vicino a prima vista, ma il mio perl-fu è arrugginito da qualche anno. Lì avrei potuto perdere un cambio di stato.
Yakk,

2

C #, 256 248 234 227 226 225 byte

Utilizza le frecce NumPad con NumLock attivato per spostarsi.

Rientrato e commentato per chiarezza:

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();
        }
    }
}

1
Penso che C # inserisca implicitamente init a zero. Inoltre (al momento non è possibile verificare) se il casting non è un problema, puoi convertire i letterali dei personaggi in interi, o almeno la "a" in 97 (credo) sebbene le altre siano di tre cifre.

Solo i campi di classe vengono inizializzati per impostazione predefinita e ciò richiede che vengano dichiarati statici in questo caso. Le variabili del metodo devono essere inizializzate prima del primo utilizzo. Ci vogliono meno personaggi: 4 contro 7.
Hand-E-Food

Grazie @tolos per il suggerimento sul cast implicito di caratteri in int! Meglio ancora, se uso il cast enum ConsoleKey come int, posso usare valori a 2 cifre.
Hand-E-Food

Tecnicamente, Mainnon è necessario chiamare il metodo Main, quindi è possibile radere altri tre caratteri.
Luaan,

@Luaan, penso che ti sbagli. Documentazione C #: msdn.microsoft.com/en-us/library/acy3edy3.aspx
Hand-E-Food

2

HTML + JavaScript (ES6), punteggio forse 217

Troppo lungo, ma giocabile online nei frammenti di seguito.

La riga 6 (T.value ...) è per l'output e non conteggiata (ma per semplicità ho contato i tag di apertura e chiusura textarea, anche se è anche output)

Per quanto riguarda la casualità: l'amuleto è sempre nella metà destra della griglia e il giocatore inizia sempre nella metà sinistra.

Fai clic sul testoArea (dopo averlo ingrandito) per avviare e riavviare il gioco.

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

Snippet 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>

Frammento di EcmaScript 5 (testato in 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>


2

ActionScript 3: 267 byte

Un esempio funzionante è online

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()}

Ecco un programma completo (spazi inclusi per la leggibilità) che utilizza la funzione di gioco:

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;
        }
    }
}

2

Javascript: 307 216

Puoi giocare nel frammento qui sotto! I numeri a sinistra sono solo così la console (almeno una cromata) non unisce le righe.

Per eseguire il codice:

  1. premi "esegui snippet di codice"
  2. premi ctrl-shift-j per aprire la console
  3. fai clic nella sezione dei risultati
  4. usa i tasti freccia e gioca

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();};

Un-giocato a 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();
};

Modifica 1: leggi le regole più attentamente e riscrivi il mio codice di conseguenza

  • il valore dell'amuleto è ora randomizzato
  • il giocatore non può più scappare dalla stanza
  • Non conto più i personaggi nella funzione di disegno o li chiama

1

SpecBAS - 428 402 (esclusa la stampa, 466 425 se conteggiato)

Usa Q / A / O / P per spostarsi rispettivamente su / giù / sinistra / destra.

La riga per stampare il dungeon alla riga 1 è l'unica riga che può essere ignorata, ma che ha anche risolto il problema.

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

Il riferimento a # 34 è solo un modo breve di inserire CHR $ (34) nel codice.

Grazie a Thomas Kwa, non avevo notato che la posizione di partenza del giocatore in modo casuale era opzionale. Ha anche usato istruzioni IF separate per radere alcuni caratteri.


Potresti riuscire a salvare alcuni personaggi randomizzando meno bene: 2 LET px=1: LET py=1: LET ax=2: LET ay=INT(RND*5)e anche usando IF instead of ELSE IF.
Lirtosiast

1

Un altro C #, 221 171 170

Ecco un altro modo in C # con entrambe le posizioni casuali. Volevo mostrarlo anche se questa parte è più lunga di 7 byte rispetto alla soluzione Hand-E-Food.
La risposta di Hand-E-Food sarà ovviamente più breve non appena utilizzerà Console.Read ().
Il rovescio della medaglia di Consol.Read è che premendo il tasto Invio necessario si stampa il campo altre 2 volte.
Ma non credo che sia necessario stampare solo sull'input (reale).

La navigazione viene effettuata da 8426 come nella soluzione 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;
}
}
}


Modifica: (aggiunta nuova soluzione e spostato PrinterClass alla fine)
Modifica2: (cambiato un 14 in un 15 e salvato il byte iniziando dal fondo a destra)

Adattando la tecnica di Mauris è possibile fonderlo fino a 171 byte in C # (ovviamente ora senza entrambe le posizioni casuali):

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 classe di stampanti è quasi la stessa, solo un nuovo sovraccarico di stampa ...

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);
    }
}

1

Ruby, 185

Ecco anche un esempio di Ruby.
Sono molto nuovo con Ruby, forse qualcuno sa come farlo meglio :)

Ho contato lineFeeds come 1 poiché il Programma andrà in crash altrimenti ...

La navigazione viene effettuata da 8462. È necessario inviare input ogni volta con invio.

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

0

QBasic, 103 byte

Secondo le regole della sfida, il Showsottoprogramma non è incluso nel conteggio byte, né la Show p, q, a, bchiamata (con la nuova riga seguente).

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

Per spostarti, inserisci un numero e premi Invio: 1per andare a sinistra, 2per andare su, 3per andare a destra e 4per andare giù.

Questo codice non genera lo stato del gioco alla fine, quando il giocatore ha trovato l'amuleto. Per farlo, aggiungine un altro Show p, q, a, bdopo la IFdichiarazione.

Spiegazione

Lasciate a, brappresentano le coordinate del amuleto e p, qle coordinate del giocatore. Il giocatore inizia da (0, 0) e l'amuleto inizia sulla riga 0, con una colonna compresa tra 1 e 9, incluso, in base alla cifra 1 dell'ora corrente.

Il resto è solo un mucchio di matematica con condizionali. La cosa importante da ricordare è che i condizionali in QBasic ritornano 0per falso, -1per vero. Diamo un'occhiata alla dichiarazione di aggiornamento della riga del giocatore:

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

Se m=2, vogliamo salire sottraendo 1 da p, purché p>0. Allo stesso modo, se m=4, vogliamo spostarci verso il basso aggiungendo 1 a p, purché p<4. Possiamo ottenere il comportamento desiderato moltiplicando. Se entrambi i fattori lo sono -1, il loro prodotto sarà 1, al quale possiamo sottrarre o aggiungere p. Se uno dei due è condizionale 0, il prodotto lo sarà 0, senza alcun effetto.

Allo stesso modo, la condizione per determinare se il giocatore ha trovato l'amuleto è:

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

Se uno dei due condizionali è vero, la loro somma sarà diversa da zero (o -1o -2) e quindi veritiera, e il programma tornerà alla linea 1. Una volta puguale ae quguale a bentrambi, saranno i due condizionali 0, quindi la loro somma sarà 0e il flusso di controllo può raggiungere il fine del programma.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.