NetHack minimal


64

NetHack est un jeu peu scrupuleux dans lequel un joueur doit récupérer l'Amulette de Yendor au niveau le plus bas du donjon. Communément joué via telnet, l'ensemble du jeu est représenté avec des graphiques ASCII. Le jeu est extrêmement difficile et nécessite la connaissance de nombreux mécanismes de jeu pour réussir.

Pour les besoins de ce défi, supposons que tout le donjon soit un seul niveau et ne comporte que 5 × 16 caractères. De plus, supposons qu'il s'agit d'un donjon "sûr" ou que vous ne réalisiez qu'un prototype - il n'y aura aucun monstre, aucune inquiétude face à la faim, etc. En fait, vous devez simplement suivre l'emplacement du personnage, de l'amulette et du jeu. se terminera effectivement lorsque le joueur arrivera au même endroit que l’amulette.

Exigences du défi

  • Il y aura un donjon 5 × 16 (niveau unique).
  • Donnez au joueur un emplacement de départ (éventuellement aléatoire) et à l'amulette un emplacement de départ distinct (différent chaque fois que le programme est exécuté) à l'intérieur du donjon. C'est-à-dire que l'amulette n'est pas autorisée à commencer sur la même case que le joueur.
  • Acceptez quatre touches de saisie qui déplacent le joueur d’une case à la fois (quatre directions cardinales). La lecture / le traitement d'autres entrées est autorisé (une fonction readline () qui nécessite d'appuyer sur 'entrée', etc.).
  • Voyager en dehors des limites du donjon n'est pas autorisé. Par exemple, si le joueur est sur le bord droit du donjon, appuyer à droite ne devrait rien faire.
  • Après la génération initiale et après chaque mouvement, imprimez l'état du jeu. Comme il s'agit d'un code golf et que l'impression est plutôt sans intérêt, ignorez le nombre de caractères pour la fonction d'impression et l'appel de fonction en supposant qu'aucun état ne change . Les cellules vides doivent apparaître en tant que point ( .), amulet en tant que double guillemet ( ") et caractère en tant que symbole ( @).
  • La partie est terminée lorsque le joueur "découvre" l'amulette (arrive sur la même case)

Gagnant

Il s’agit d’un code de golf challenege, le code le plus court répondant aux exigences d’une semaine à partir d’aujourd’hui sera déclaré vainqueur.

Exemple

Voici un exemple de solution en C # (non golfé) pour montrer les exigences de base et les exemples de sortie.

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

Le nombre total de caractères est 1474, mais en ignorant les appels à la fonction d'impression et à sa définition, le nombre de caractères final est 896.

Sortie lorsque le programme est exécuté:

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

Sortie (y compris ci-dessus) après avoir appuyé deux fois sur la touche "a":

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

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

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

10
J'ai le sentiment que cela intéressera @Doorknob.
Alex A.

10
Rogue est le jeu roguelike original dans lequel un joueur doit récupérer l'Amulette de Yendor au niveau le plus bas du donjon. Pourquoi ne pas appeler cela un voleur minime?
Gilles 'SO- arrête d'être méchant'

5
@ Gilles Pourquoi ne pas appeler cela un serpent minimal?
Casey Kuball

26
Psshh, pas de mouvement diagonal? Non yubnhjkl? Pas même un escalier à monter après avoir reçu l'amulette? : P ( furieusement les votes tout de même )
Porte-porte

2
@tolos: Je ne comprends toujours pas ce qui compte comme aléatoire ici. Il n'est pas vraiment possible de remplir la condition différente chaque fois que le programme est exécuté si le programme est exécuté 80 fois ... Plus précisément, dans cette réponse , l'amulette ne peut occuper que 9 des 79 emplacements possibles. Cela compte-t-il?
Dennis

Réponses:


37

TI-BASIC, 42 41 38 36 35 octets

Pour votre calculatrice graphique des séries TI-83 ou 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

Dans quelle direction le joueur ira-t-il en fonction du code de la touche enfoncée, mais quatre touches qui fonctionnent vraiment sont celles-ci dans la rangée supérieure:

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

L'amulette commence sur l'une des cinq cases de la première colonne et le joueur commence en bas à droite. Par exemple, un arrangement possible est:

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

Explication

La position du joueur est stockée sous la forme d'un nombre complexe allant de 0+0ià 15+4i, où la partie réelle passe à droite et la partie imaginaire s'abaisse. Cela facilite la vérification des limites en haut et à gauche: nous décalons simplement légèrement le nombre et arrondissons vers zéro. Par exemple, si le décalage est 0.5et que notre position est -1+3i(à gauche de l'écran), la position sera corrigée comme iPart(-0.5+3.5i)=0+3iil se doit. Vérifier les limites inférieure et droite est légèrement plus compliqué. nous devons soustraire le nombre d’une constante Cqui est environ 15.635 + 4.093i(c’est la plus courte que j’ai pu trouver entre 15+4iet 16+5i), arrondir, soustraire de Cnouveau pour renverser le nombre, et arrondir à nouveau.

Lorsqu'une touche est enfoncée, la position du joueur non ajustée se déplace d'une unité dans une direction, mais la partie entière ne change que lorsque certaines touches sont enfoncées. Heureusement, les clés qui fonctionnent se trouvent toutes dans la rangée supérieure. Vous trouverez ci-dessous un graphique des décalages dans les cas où les touches 11, 12, 13 et 15 sont enfoncées, et lorsqu'aucune touche n'est enfoncée les décalages ont des parties entières différentes). Cest la croix rouge au centre du cercle.

entrez la description de l'image ici

Ancien code (42 octets):

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

Limites

Il n'y a aucun moyen d'échapper à un "caractère, donc les chaînes avec un "ne peuvent pas être générées dans un programme. Par conséquent, cela utilise la marque de tréma ¨au lieu d'un guillemet (s'il y avait une chaîne déjà existante avec un guillemet, je pourrais l'afficher). Pour obtenir ¨et @dans un programme, un outil extérieur est nécessaire; Cependant, il est valide TI-BASIC.


2
Juste pour le plaisir, j'ai créé cet extrait qui met la diaérèse et le symbole @ dans Str1 (par opposition à "un outil extérieur"). Sélectionnez la ligne en haut qui correspond à votre calculatrice, entrez-la dans un nouveau programme et exécutez ce programme avec Asm (.
MI Wright le

Oh, j'ai oublié de coder en code machine sur la calculatrice. Vous ne voulez pas écraser le mien avec un type d'erreur, mais je suis convaincu que cela fonctionne.
lirtosiast

44

CHIP-8 , 48 octets

Cela peut ne pas être considéré comme légal, mais pourquoi diable pas. J'ai écrit mon programme dans CHIP-8, un langage de programmation basé sur des codes octets pour une console de jeu virtuelle. Vous pouvez essayer le programme complet (99 octets) dans votre navigateur en utilisant un émulateur / débogueur que j'ai écrit appelé Octo:

Capture d'écran

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

Un vidage hexadécimal de ce programme complet est le suivant:

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

Vous pouvez déplacer le lecteur à l’aide des touches ASWD ou 7589 du clavier CHIP-8 d’origine. Si je supprime tout le code et toutes les données pour dessiner l'arrière-plan et le lecteur, j'obtiens plutôt ce dump de 48 octets:

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 forme complète et non-golfée du programme a été écrite dans un langage d'assemblage de haut niveau, comme suit:

: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

Notez que les octets compilés eux - mêmes sont le langage de programmation CHIP-8; l'assembleur est simplement un moyen plus pratique de composer de tels programmes.


19
Bon outil pour le travail.
Dennis

6
+1 pour m'avoir fait perdre beaucoup de temps à jouer votre jeu encore et encore.
Alex A.

4
@Alexa. Si vous voulez perdre encore plus de temps, essayez Cave Explorer . Les mouvements ASWD dans le monde planétaire et le QE sont utilisés pour réinitialiser / déplacer des blocs dans les niveaux de plateforme.
JohnE

4
Super, et bien voilà mon weekend.
Alex A.

1
Au début, j'étais sceptique, mais Cave Explorer était amusant et CHIP-8 existe depuis bien plus longtemps que je ne l'aurais deviné. Donc je suppose que je devrai apprendre ceci.

10

Python 3, 86 octets

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]

Compter seulement les deux dernières lignes et les laisser tomber d();.


J'ai sauvegardé un autre octet en démarrant le joueur dans le coin inférieur droit (le "dernier" carré), puis en échantillonnant de manière aléatoire à partir des 79 premiers carrés.
Lynn

Oups, désolé, réparé! Je suppose que je ne suis pas étonnant de compter manuellement les octets. : <
Lynn

1
Je pense que vous pouvez sauver un autre personnage en le remplaçant a=id(9)%79par a=id(9)%p.
kirbyfan64sos

@ kirbyfan64sos brillant! Merci.
Lynn

1
De plus, si vous faites cela pour Python 3, vous pouvez changer raw_inputsimplement l' appel input.
Kirbyfan64sos

10

C, 122 121 115 104 102 101 octets

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

Première publication ici! J'espère que tu aimes :)

oest l'impression, euh, fonction. Notre courageux héros peut être déplacé avec 2, 4, 6 et 8, mais méfiez-vous de ne pas envoyer d'autre entrée (pas de nouvelles lignes!).

Mise à jour 1: paramètres introduits aet idans main.

Mise à jour 2: OP ayant confirmé qu'une seule chaîne d'entrée est correcte, je me suis débarrassé de scanf(ce qui me permettait de sauter la nouvelle ligne).

Mise à jour 3: Utilisation d'un littéral de tableau composé et modification de la présentation en entrée. Le programme va maintenant se détraquer si vous entrez une direction invalide;)

Mise à jour 4: remarque que l'appel de la fonction d'impression ne compte pas. A pris note de lire les règles plus attentivement.

Mise à jour 5: un octet enregistré grâce à Mikkel Alan Stokkebye Christia.


Pourrait !!(p%16)être p%16>0? Je ne me souviens pas de mon ordre des opérations.
lirtosiast

@ThomasKwa c'est bien ça, mais ce unaire -ne peut s'empêcher de s'en tenir à pça, des parenthèses sont donc nécessaires de toute façon. Le double coup n'est qu'un obscurcissement :)
Quentin

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

@ MikkelAlanStokkebyeChristia merci :)
Quentin

9

CJam, 46 45 44 40 39 37 octets

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

La première ligne (définit une fonction imprimant l'état actuel du jeu) et les P de la deuxième ligne (appelez cette fonction) ne contribuent pas au nombre d'octets.

La position de départ et la position de l'amulette sont sélectionnées de manière pseudo-aléatoire. La distribution est aussi uniforme et le PRNG sous-jacent le permet.

L' entrée est E, 6, 9et Bpour Up , Bas , Gauche et Droite avec, Caps Lockactivé, suivi Enter.

Version alternative

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

Au prix de quatre octets supplémentaires, le format d'entrée est considérablement amélioré:

  • Cette version accepte 8, 2, 4et 6pour Up , Bas , Gauche et Droite , qui correspond aux touches fléchées correspondantes sur le pavé numérique.
  • Il accepte également 7, 9, 1et 3pour les mouvements en diagonale correspondant.

Essai

Comme les E / S sont interactives, vous devriez essayer ce code avec l' interpréteur Java .

Téléchargez la dernière version et lancez le programme comme ceci:

java -jar cjam-0.6.5.jar nethack.cjam

Pour éviter d'appuyer Enteraprès chaque touche et pour les mises à jour sur place de la sortie, vous pouvez utiliser ce 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"

Invoquer comme ceci:

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

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

Version alternative

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.

Fonction 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
Je suis juste sur votre queue avec TI-BASIC! Je posterai une fois que je vérifierai ma solution.
lirtosiast

8

Java, 231 octets (196 si fonction)

Voici le code complet du programme 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":""));}}}

Sans la fonction d'impression, 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 juste une fonction est correcte (je ne suis pas claire à la spécification), alors je peux la réduire un peu plus loin à 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);}

Et avec quelques sauts de ligne pour plus de clarté ...

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

Notez que je ne compte pas la fonction d'impression p(p,y)lui - même, mais je suis compter l'appel, puisque j'ai des choses changer dans l'instruction d'appel.

Cela fonctionne avec des lettres majuscules ASDW. En raison de la manière dont ils sont vérifiés, certaines autres lettres peuvent également fonctionner, mais la spécification ne dit pas vraiment ce qui devrait se passer si j'appuie sur des touches différentes.


Je préfère formater les opérateurs ternaires imbriqués au même niveau d'indentation que vous le feriez d'une chaîne if / else if. C'est plus lisible.
lirtosiast

@ThomasKwa Oui, je l'ai parfois fait dans les deux sens. Cela ressemble plus à des instructions imbriquées si que chaînées. Je me sens mieux parce que les deux moitiés de chaque ternaire sont au même niveau, mais distinctes des autres.
Geobits

Si une fonction anonyme est acceptable, vous pouvez ajuster votre réponse à 192 octets: void m()devient()->
ankh-morpork le

@ dohaqatar7 Oui, mais je n'utilise pas les fonctions anon de Java pour le code golf. En principe, cela me fait peur, que d'autres ressentent la même chose ou non.
Geobits

Pouvez-vous faire p+=?
lirtosiast

5

Java, 574 octets

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

Fondamentalement identique à la version C #, excepté obscurci et minimisé.


tant d'espaces inutiles ...;)
Will

@Will I était juste en train de réparer ça: P
phase

1
Aussi, utilisez des noms à une lettre et des ternaires.
lirtosiast

@ThomasKwa corrigé:
phase

6
Il y a encore beaucoup d'espaces inutiles et le manque de ternaires;)
Will

5

Julia, 161 octets

Utilisations w, a, set dpour avancer, à gauche, vers le bas, et à droite, respectivement.

Code complet, y compris l'impression (330 octets):

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

Code scoré, exclut l'impression (161 octets):

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 différence ici est que nous ne sauvegardons pas l'état du jeu en tant que matrice; toutes les informations pertinentes sont contenues dans les tableaux cet a. Et bien sûr, rien n’est imprimé. L'utilisateur ne sera plus invité à entrer une fois que le joueur aura atteint l'amulette.


Ungolfed + explication (code complet):

# 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

Je pense que c'est bien

3
+1 pour la version compressée / obscurcie qui ressemble beaucoup à ce que je me souviens du code source nethack actuel.
Ben Jackson

Vous pouvez économiser quelques octets en utilisant une pire randomisation:a=[rand(1:5),1] c=a+1
lirtosiast

@ThomasKwa: Qu'est-ce qui est amusant si c'est toujours en première ligne? :)
Alex A.

3

Lot, 329 octets

@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

C'est très impressionnant. Je suis surpris qu'il soit possible de faire cela.
eis

Cela n’affiche pas le donjon pour moi, seulement une série de lignes indiquant [W, A, S, D] ?. Cela semble fonctionner, la marche du donjon non affiché finit par se terminer. win7 cmd.exe
Dan Pritts

Cela fonctionne pour moi avec Win7 cmd.exe - quand je tape ver je reçoisMicrosoft Windows [Version 6.1.7601]
Jerry Jeremiah

@DanPritts C'est étrange. Cela fonctionne parfaitement pour moi sous Windows 8 ( Microsoft Windows [Version 6.2.9200])
ankh-morpork le

doh, je n'avais pas copié et collé le tout, je n'ai pas fait défiler la fenêtre. Bien joué.
Dan Pritts

3

Perl, 228 222 caractères (sans compter les sauts de ligne qui ne font pas partie intégrante du fonctionnement du code) - 207 si les éléments de l'instruction printet print ifutilisés pour l'impression ne sont pas pris en compte, mais ils ne s'ajoutent pas à la logique du jeu; 144 si le code de génération de représentation de champ est également considéré comme faisant partie de l’impression, comme suggéré par Yakk dans les commentaires)

Ce code utilise wasd minuscule pour le contrôle; l'entrée doit être confirmée avec Entrée. Testé avec 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}}

Notez que pour ce code, il est impossible de séparer le calcul et l'impression, car les opérations sont effectuées directement sur la représentation imprimée à l'aide d'expressions régulières.

Explication:

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

Cette ligne détermine la position du joueur et de l'amulette. La position du joueur est déterminée par $==rand(80)et est en fait facile à comprendre: sur un tableau 5 × 16, il y a 80 positions distinctes où le joueur peut se trouver. La position est stockée dans la $=variable qui force la valeur stockée en entier; cela économise quelques octets pour ne pas avoir besoin de convertir explicitement le résultat en entier ( randfournit une valeur à virgule flottante).

Etant donné qu'une des positions est déjà occupée par le joueur, il ne reste que 79 positions pour l'amulette, donc pour la position de l'amulette $a=$==rand(79). Encore une fois, l'affectation $=force la conversion en entier, mais je l'assigne ensuite $aafin de pouvoir être réutilisée $=pour la position du joueur.

Maintenant, pour éviter que l'amulette n'occupe la même position que le joueur, elle est avancée d'une position si sa position est au moins aussi grande que celle du joueur, ce qui donne une répartition uniforme sur les places non occupées par le joueur. Ceci est réalisé par $a = ($a >= $=)$=tient ici la position du joueur. Maintenant, la première ligne est générée en insérant les deux assignations initiales au lieu du premier $a$ and the only$ = `dans cette expression.

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

Cela génère le champ initial et imprime ensuite. ("."x80)génère juste une chaîne de 80 points. =~s/(.{$=})./\1@/rremplace ensuite le $=thème par @, et =~s/(.{$=})./\1@/rle $athème par ". En raison du rmodificateur, ils n'essayent pas de modifier à la place, mais renvoient la chaîne modifiée, c'est pourquoi ils peuvent être appliqués aux expressions précédentes. Enfin, =~s/(.{16})/\1\n/grinsère une nouvelle ligne tous les 16 caractères. Notez que le champ est stocké dans la variable spéciale $_qui peut être utilisée implicitement dans les instructions ultérieures.

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

Cela crée un hachage contenant les règles de remplacement pour les différents déplacements. Une version plus lisible de ceci est

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

Les clés sont les caractères pour les déplacements et les valeurs sont des chaînes contenant la règle de remplacement correspondante.

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

C'est la boucle principale. while(/"/)vérifie s'il y a encore un "caractère dans $_(c'est-à-dire dans le champ). Si nous passons à l'amulette, son personnage est remplacé par le personnage du joueur et disparaît du champ.

eval $r{getc STDIN}lit un caractère à partir de l'entrée standard, recherche la règle de remplacement correspondante dans la règle a %ret l'applique, c'est-à $_-dire le champ. Cela est considéré comme vrai si un remplacement a été réellement effectué (c'est-à-dire que la clé a été trouvée dans le hachage et que le déplacement était possible; un déplacement impossible ne correspondra pas à la règle de remplacement). Dans ce cas, printest exécuté. Comme il est appelé sans argument, il affiche $_le champ modifié.


1
Ce n'est pas parce que vous incluez des sauts de ligne pour la lisibilité que vous devez les compter. Je vois 228 octets. En outre, conformément aux règles spécifiques de cette question, la partie imprimée de votre code ne contribue pas au nombre d'octets.
Dennis

@Dennis: Pour la partie impression, voir l'explication que j'ai maintenant ajoutée: Vous ne pouvez pas séparer de manière significative l'impression et l'évaluation dans mon code. J'ai maintenant changé le comptage comme vous l'avez suggéré.
celtschk

Y at-il des changements d'état dans votre code d'impression? Non? Eh bien, à mon avis, réutiliser les résultats de votre code d'impression pour votre logique ne devrait pas vous pénaliser. Le code de mouvement (qui est distinct!) Devrait compter, mais le code qui génère la "chaîne d'affichage" ne devrait pas compter.
Yakk

@Yakk: Quelle partie de mon code considérez-vous le code d'impression? (En fait, mon opinion est que l'exclusion du code d'impression du comptage était une mauvaise idée, précisément parce que la définition du "code d'impression" n'est pas toujours bien définie.)
celtschk

@celtschk ("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/grest assez proche au premier abord, mais mon perl-fu est rouillé depuis quelques années. J'aurais pu manquer un changement d'état là-bas.
Yakk

2

C #, 256 248 234 227 226 225 octets

Utilise les flèches NumPad avec NumLock activé pour se déplacer.

Mis en retrait et commenté pour plus de clarté:

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
Je pense que C # ints commence implicitement à zéro. Aussi (ne peut pas vérifier pour le moment) si le casting n'est pas un problème, vous pouvez convertir les littéraux de caractères en entiers, ou au moins le «a» à 97 (je pense) bien que les autres aient trois chiffres.

Seuls les champs de classe sont initialisés par défaut, ce qui nécessite leur déclaration statique dans ce cas. Les variables de méthode doivent être initialisées avant la première utilisation. Cela prend moins de caractères: 4 vs 7.
Hand-E-Food le

Merci @tolos pour l'info sur le casting implicite de char en int! Mieux encore, si j’utilise l’énumération ConsoleKey en tant que int, je peux utiliser des valeurs à 2 chiffres.
Hand-E-Food le

Techniquement, il Mainn'est pas nécessaire d'appeler la Mainméthode, vous pouvez donc supprimer trois autres caractères.
Luaan

@ Luan, je pense que vous vous trompez. Documentation C #: msdn.microsoft.com/en-us/library/acy3edy3.aspx
Hand-E-Food

2

Html + JavaScript (ES6), score peut-être 217

Trop looong, mais jouable en ligne dans les extraits ci-dessous.

La ligne 6 (T.value ...) est pour la sortie et n'est pas comptée (mais pour des raisons de simplicité, j'ai compté les balises textarea open et close, même si elles sont également affichées)

Comme pour le hasard: l'amulette est toujours dans la moitié droite de la grille et le joueur commence toujours dans la moitié gauche.

Cliquez sur la zone de texte (après l'avoir agrandie) pour démarrer et redémarrer le jeu.

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

EcmaScript 6 Snippet (Firefox uniquement)

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>

EcmaScript 5 snippet (testé dans 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 octets

Un exemple de travail est en ligne

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

Voici un programme complet (espaces inclus pour la lisibilité) utilisant la fonction de jeu:

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

Vous pouvez jouer dans l'extrait ci-dessous! Les chiffres à gauche sont juste pour que la console (chrome au moins) ne fusionne pas les lignes.

Pour exécuter le code:

  1. appuyez sur "extrait de code d'exécution"
  2. appuyez sur ctrl-shift-j pour ouvrir la console
  3. cliquez dans la section des résultats
  4. utiliser les touches fléchées et jouer

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

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

Éditer 1: Lire les règles plus attentivement et réécrire mon code en conséquence

  • la valeur y de l'amulette est maintenant aléatoire
  • le joueur ne peut plus s'échapper de la pièce
  • Je ne compte plus les personnages dans la fonction de dessin ni les appels

1

SpecBAS - 428 402 (hors impression, 466 425 lorsque compté)

Utilise Q / A / O / P pour se déplacer respectivement vers le haut, le bas, la gauche ou la droite.

La ligne pour imprimer le donjon à la ligne 1 est la seule ligne qui peut être ignorée, mais qui a également joué au golf.

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 référence à # 34 n’est qu’un moyen simple de mettre CHR $ (34) dans le code.

Merci @Thomas Kwa, je n'avais pas remarqué que la position de départ du joueur était aléatoire. Également utilisé des instructions IF distinctes pour éliminer quelques caractères.


Vous pourrez peut-être sauvegarder certains caractères en procédant moins bien au hasard: 2 LET px=1: LET py=1: LET ax=2: LET ay=INT(RND*5)et aussi en utilisant IF instead of ELSE IF.
lirtosiast

1

Un autre C #, 221 171 170

Voici une autre manière en C # avec les deux positions aléatoires. Je voulais montrer cela même si cette partie est 7 octets plus longue que la solution de Hand-E-Food.
La réponse de Hand-E-Food sera bien sûr plus courte dès qu'il utilisera Console.Read ().
L’inconvénient de Consol.Read est que le fait d’appuyer sur la touche Entrée requise entraîne l’impression du champ 2 fois de plus.
Mais je ne pense pas qu'il soit nécessaire d'imprimer uniquement sur (de vraies) entrées.

La navigation est effectuée par 8426 comme dans la solution 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;
}
}
}


Edit: (ajout d'une nouvelle solution et déplacement de PrinterClass à la fin)
Edit2: (modification d'un octet de 14 et enregistrement de l'octet en commençant par le bas à droite) En

adaptant la technique de Mauris, il est possible de le réduire à 171 octets en C # (bien sûr maintenant sans les deux positions aléatoires):

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 d'imprimante est presque la même chose, juste une nouvelle surcharge d'impression ...

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

Voici un exemple Ruby aussi.
Je suis très nouveau chez Ruby, peut-être que quelqu'un sait mieux le faire :)

J'ai compté lineFeeds à 1 puisque le programme plantera, sinon ...

La navigation est faite par 8462. Vous devez envoyer une entrée à chaque fois avec 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

0

QBasic, 103 octets

Selon les règles du défi, le Showsous-programme n'est pas inclus dans le nombre d'octets, pas plus que l' Show p, q, a, bappel (avec la nouvelle ligne suivante).

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

Pour vous déplacer, entrez un nombre et appuyez sur Entrée: 1pour aller à gauche, 2pour monter, 3pour aller à droite et 4pour descendre.

Ce code n'indique pas l'état du jeu à la fin, lorsque le joueur a trouvé l'amulette. Pour le faire, ajoutez-en un autre Show p, q, a, baprès la IFdéclaration.

Explication

Laissez a, breprésenter les coordonnées de l'amulette et p, qles coordonnées du joueur. Le joueur commence à (0, 0) et l'amulette commence à la ligne 0, avec une colonne comprise entre 1 et 9 inclus, en fonction du chiffre 1 de l'heure actuelle.

Le reste est juste un tas de math avec des conditions. La chose importante à retenir est que les conditions dans QBasic renvoient 0false, -1à true. Regardons la déclaration de mise à jour de la ligne player:

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

Si m=2nous voulons monter en soustrayant 1 de p, aussi longtemps que p>0. De même, si m=4nous voulons descendre en ajoutant 1 à p, tant que p<4. On peut obtenir le comportement souhaité en se multipliant. Si les deux facteurs sont présents -1, leur produit sera 1ce que nous pouvons soustraire ou ajouter p. Si l'une ou l'autre de ces conditions est remplie 0, le produit sera 0sans effet.

De même, la condition pour déterminer si le joueur a trouvé l'amulette est:

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

Si l'une des conditions est vraie, leur somme sera non nulle ( -1ou -2) et donc, le programme retournera à la ligne 1. Une fois pégal aet qégal b, les deux conditions seront 0, de sorte que leur somme sera 0et que le flux de contrôle pourra atteindre le fin du programme.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.