Minimalny NetHack

64

NetHack to gra typu roguelike, w której gracz musi odzyskać Amulet Yendora z najniższego poziomu lochu. Cała gra, powszechnie używana przez telnet, jest reprezentowana przez grafikę ASCII. Gra jest niezwykle wymagająca i wymaga wiedzy na temat wielu mechanizmów gry, aby odnieść sukces.

Na potrzeby tego wyzwania załóż, że cały loch ma jeden poziom i tylko 5 × 16 znaków. Ponadto załóż, że jest to „bezpieczny” loch lub że wdrażasz tylko prototyp - nie będzie potworów, obaw związanych z głodem itp. W rzeczywistości musisz jedynie śledzić położenie postaci, amuletu i gry zakończy się skutecznie, gdy gracz dotrze do tego samego miejsca co amulet.

Wymagania dotyczące wyzwań

  • Będzie loch 5 × 16 (pojedynczy poziom).
  • Daj graczowi początkową lokalizację (opcjonalnie losową), a amulet osobną losową (inną przy każdym uruchomieniu programu) kwadrat początkowy w lochu. Oznacza to, że amulet nie może startować na tym samym polu co gracz.
  • Zaakceptuj cztery klawisze wprowadzania, które poruszają gracza po jednym kwadracie na raz (cztery główne kierunki). Odczytywanie / przetwarzanie innych danych jest dozwolone (funkcja readline (), która wymaga naciśnięcia „enter” itp.).
  • Podróżowanie poza granice lochu jest zabronione. Np. Jeśli gracz znajduje się na prawej krawędzi lochu, wciśnięcie w prawo nie powinno nic zrobić.
  • Po początkowym wygenerowaniu i po każdym ruchu wydrukuj stan gry. Ponieważ jest to kod golfowy, a drukowanie jest raczej nieciekawe, zignoruj ​​liczbę znaków dla funkcji drukowania i wywołania funkcji, zakładając, że nie zmieniają się żadne stany . Puste komórki powinny być pokazane jako kropka ( .), amulet jako podwójny cudzysłów ( ") i znak jak przy symbolu (@ ).
  • Gra kończy się, gdy gracz „odkrywa” amulet (przybywa na ten sam kwadrat)

Zwycięski

To jest golfowa gra w golfa, najkrótszy kod spełniający wymagania za tydzień od dzisiaj zostanie ogłoszony zwycięzcą.

Przykład

Oto przykładowe rozwiązanie w języku C # (bez golfa), które pokazuje podstawowe wymagania i przykładowe wyniki.

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

Całkowita liczba znaków wynosi 1474, ale ignorowanie wywołań funkcji drukowania i jej definicji to końcowa liczba znaków 896.

Dane wyjściowe po uruchomieniu programu:

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

Wyjście (w tym powyżej) po dwukrotnym naciśnięciu klawisza „a”:

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

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

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

źródło
10
Mam wrażenie, że będzie to interesujące dla @Doorknob.
Alex A.,
10
Łotr to oryginalna gra roguelike, w której gracz musi odzyskać Amulet Yendora z najniższego poziomu lochu. Dlaczego nie nazwać tego minimalnym Łotrem?
Gilles
5
@Gilles Dlaczego nie nazwać tego minimalnym wężem?
Casey Kuball,
26
Psshh, brak ruchu po przekątnej? Nie masz yubnhjkl? Nie ma nawet schodów, po których można się wspinać po zdobyciu amuletu? : P ( i tak wściekły głosuje )
Klamka
2
@tolos: Nadal nie jestem pewien, co jest tu przypadkowe . Naprawdę nie jest możliwe spełnienie różnych wymagań za każdym razem, gdy program jest uruchamiany , jeśli program jest uruchamiany 80 razy ... Konkretnie, w tej odpowiedzi amulet może zajmować tylko 9 ze wszystkich 79 możliwych lokalizacji. To się liczy?
Dennis

Odpowiedzi:

37

TI-BASIC, 42 41 38 36 35 bajtów

Do kalkulatora graficznego z serii TI-83 lub 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

Kierunek, w którym pójdzie odtwarzacz, jest funkcją kodu przycisku naciśniętego, ale cztery klawisze, które zdecydowanie działają, to te w górnym rzędzie:

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

Amulet zaczyna się na jednym z pięciu kwadratów w pierwszej kolumnie, a gracz zaczyna od prawego dolnego kwadratu. Na przykład możliwe ustawienie to:

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

Wyjaśnienie

Pozycja gracza jest przechowywana jako liczba zespolona od 0+0ido 15+4i, gdzie prawdziwa część idzie w prawo, a część wyobrażona spada. Ułatwia to łatwe sprawdzanie granic u góry i po lewej stronie: po prostu lekko przesuniemy liczbę i zaokrąglimy w kierunku zera. Na przykład, jeśli przesunięcie jest, 0.5a nasza pozycja jest -1+3i(poza ekranem po lewej), wówczas pozycja zostanie skorygowana iPart(-0.5+3.5i)=0+3itam, gdzie powinna. Sprawdzanie dolnej i prawej granicy jest nieco bardziej skomplikowane; musimy odjąć liczbę ze stałą C, czyli o 15.635 + 4.093i(to najkrótsza jeden udało mi się znaleźć między 15+4ii 16+5i), okrągłe, odjąć odC znowu odwrócić numer z powrotem, i znowu okrągły.

Po naciśnięciu klawisza nieskorygowana pozycja gracza przesunie się o 1 jednostkę w pewnym kierunku, ale część całkowita zmienia się tylko po naciśnięciu niektórych klawiszy. Na szczęście klucze, które działają, znajdują się w górnym rzędzie. Poniżej znajduje się wykres przesunięć w przypadkach, gdy naciśnięto klawisze 11, 12, 13 i 15, i gdy żaden klawisz nie został naciśnięty (Brak naciśnięcia to punkt w środku kwadratu, powodujący niezmienność części całkowitych; cztery naciśnięcia klawiszy „przesunięcia mają różne części całkowite). Cto czerwony krzyż w środku koła.

wprowadź opis zdjęcia tutaj

Stary kod (42 bajty):

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

Ograniczenia

Nie ma sposobu na ucieczkę od "znaku, dlatego w programie "nie można wygenerować ciągów z cyfrą . Dlatego używa to znaku umlaut ¨zamiast cudzysłowu (gdyby istniał już ciąg znaków ze znakiem cudzysłowu, mógłbym to wyświetlić). Aby uzyskać ¨i @w programie, wymagane jest poza narzędziem; jest to jednak ważne TI-BASIC.

lirtosiast
źródło
2
Dla zabawy stworzyłem ten fragment kodu, który umieszcza symbol diaeresis i @ w Str1 (w przeciwieństwie do „narzędzia zewnętrznego”). Wybierz wiersz u góry odpowiadający Twojemu kalkulatorowi, wprowadź go do nowego programu i uruchom ten program w Asm (.
MI Wright
Och, zapomniałem o kodowaniu kodu maszynowego na kalkulatorze. Nie chcę rozbijać mojego z błędnym typem, ale ufam, że to działa.
lirtosiast
44

CHIP-8 , 48 bajtów

To może nie być uważane za legalne, ale dlaczego, do diabła, nie. Mój program napisałem w CHIP-8, języku programowania opartym na kodach bajtowych dla wirtualnej konsoli do gier. Możesz wypróbować pełny program (99 bajtów) w przeglądarce za pomocą emulatora / debuggera o nazwie Octo:

Zrzut ekranu

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

Zrzut szesnastkowy tego pełnego programu jest następujący:

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

Możesz przenieść odtwarzacz za pomocą klawiszy ASWD lub 7589 na oryginalnej klawiaturze CHIP-8. Jeśli usunę cały kod i dane do rysowania tła i odtwarzacza, otrzymam zrzut 48 bajtów:

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

Niegolfowana, kompletna forma programu została napisana w języku asemblera wysokiego poziomu w następujący sposób:

: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

Zauważ, że same skompilowane bajty są językiem programowania CHIP-8; asembler to po prostu wygodniejszy sposób komponowania takich programów.

JohnE
źródło
19
Odpowiednie narzędzie do pracy.
Dennis
6
+1 za zmuszanie mnie do marnowania czasu na grę w kółko.
Alex A.,
4
@AlexA. jeśli chcesz tracić jeszcze więcej czasu, wypróbuj Cave Explorer . Ruch ASWD w overworld i QE służą do resetowania / przenoszenia bloków na poziomach platformówki.
JohnE
4
Świetnie, no cóż, idzie mój weekend.
Alex A.,
1
Na początku byłem sceptyczny, ale Cave Explorer był zabawny, a CHIP-8 był o wiele dłużej, niż się spodziewałam. Więc chyba będę musiał się tego nauczyć.
10

Python 3, 86 bajtów

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]

Licząc tylko dwie dolne linie i upuszczając d();.

Lynn
źródło
Zapisałem kolejny bajt, uruchamiając odtwarzacz w prawym dolnym rogu („ostatni” kwadrat), a następnie losowo próbkując z pierwszych 79 kwadratów.
Lynn,
Ups, przepraszam, naprawione! Chyba nie jestem niesamowity w ręcznym liczeniu bajtów. : <
Lynn,
1
Myślę, że możesz uratować inną postać, zastępując a=id(9)%79a=id(9)%p.
kirbyfan64sos
@ kirbyfan64sos Brilliant! Dzięki.
Lynn,
1
Ponadto, jeśli zrobisz to dla Python 3, możesz zmienić raw_inputwywołanie na just input.
kirbyfan64sos
10

C, 122 121 115 104 102 101 bajtów

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

Po raz pierwszy zamieszczam tutaj! Mam nadzieję, że to lubisz :)

oto drukowanie, erm, funkcja. Naszego dzielnego bohatera można przemieszczać za pomocą 2, 4, 6 i 8, ale uważaj, aby nie wysyłać żadnych innych danych wejściowych (bez nowych linii!).

Aktualizacja 1: wprowadzona ai wprowadzona idomain parametrów.

Aktualizacja 2: OP po potwierdzeniu, że pojedynczy ciąg danych wejściowych jest OK, pozbyłem się scanf(którego użyłem do pominięcia nowej linii).

Aktualizacja 3: Użyłem literału tablicy złożonej i zmodyfikowałem układ wejściowy. Program wpada teraz w szaleństwo, jeśli podasz nieprawidłowy kierunek;)

Aktualizacja 4: Zauważyłem, że wywołanie funkcji drukowania się nie liczy. Zanotowałem, aby uważniej przeczytać zasady.

Aktualizacja 5: zapisano jeden bajt dzięki Mikkel Alan Stokkebye Christia.

Quentin
źródło
Może !!(p%16)być p%16>0? Nie pamiętam mojej kolejności operacji.
lirtosiast
@ThomasKwa to prawda, ale ten unary -nie może się nie poddać p, więc nawiasy są potrzebne w obu przypadkach. Podwójny huk to po prostu zaciemnianie :)
Quentin
@Quentin 3 & getchar () / 2 <getchar () / 2-25
Mikkel Alan Stokkebye Christia
@MikkelAlanStokkebyeChristia dziękuję :)
Quentin
9

CJam, 46 45 44 40 39 37 bajtów

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

Pierwszy wiersz (definiuje funkcję, która drukuje bieżący stan gry), a litery P w drugim wierszu (wywołanie tej funkcji) nie wpływają na liczbę bajtów.

Zarówno pozycja początkowa, jak i pozycja amuletu są wybierane pseudolosowo. Rozkład jest równomierny i pozwala na to podstawowy PRNG.

Wejście jest E, 6, 9i Bna górę , dół , lewo i prawej , z Caps Lockaktywowana, a następnie Enter.

Alternatywna wersja

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

Kosztem kolejnych czterech bajtów format wejściowy został znacznie ulepszony:

  • Ta wersja akceptuje 8, 2, 4i 6na górę , dół , lewo i prawa , które pasuje odpowiednie klawisze strzałek na klawiaturze numerycznej się.
  • Przyjmuje się również 7, 9, 1a 3także do odpowiednich ruchów przekątnej.

Testowanie

Ponieważ operacje wejścia / wyjścia są interaktywne, powinieneś wypróbować ten kod z interpreterem Java .

Pobierz najnowszą wersję i uruchom program w następujący sposób:

java -jar cjam-0.6.5.jar nethack.cjam

Aby uniknąć naciskania Enterpo każdym klawiszu i do aktualizacji danych wyjściowych w miejscu, możesz użyć tego opakowania:

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

Wywołaj w ten sposób:

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

Wersja główna

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.

Alternatywna wersja

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.

Funkcja P

'.80*  e# Push a string of 80 dots.
W$Gb   e# Copy the amulet's position and convert from base 16 to integer.
'"t    e# Set the corresponding character of the string to '"'.
1$Gb   e# Copy the player's position and convert from base 16 to integer.
'@t    e# Set the corresponding character of the string to '@'.
G/     e# Split into chunks of length 16.
W%     e# Reverse the chunks (only needed for the alternate program).
N*     e# Join the chunks, separating by linefeeds.
oNo    e# Print the resulting string and an additional linefeed.
Dennis
źródło
2
Jestem na twoim ogonie z TI-BASIC! Wyślę po zweryfikowaniu mojego rozwiązania.
lirtosiast
8

Java, 231 bajtów (196, jeśli funkcja)

Oto pełny kod programu pod adresem 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":""));}}}

Bez funkcji drukowania, 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);}}

Jeśli tylko funkcja jest w porządku (jestem niejasny w specyfikacji), to mogę obniżyć to nieco do 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);}

I z pewnymi podziałami linii dla pewnej przejrzystości ...

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

Zauważ, że nie liczę funkcji drukowania p(p,y)się, ale ja jestem licząc rozmowę z nim, ponieważ mam rzeczy zmieniających wewnątrz zestawienia połączenia.

Działa z dużymi literami ASDW. Ze względu na sposób, w jaki je sprawdza, niektóre inne litery mogą również działać, ale specyfikacja tak naprawdę nie mówi nic o tym, co powinno się stać, jeśli naciskam inne klawisze.

Geobity
źródło
Wolę formatować zagnieżdżone operatory trójskładnikowe na tym samym poziomie wcięcia, jak w przypadku łańcucha if / else if. Jest bardziej czytelny.
lirtosiast
@ThomasKwa Tak, czasami robiłem to w obie strony. To bardziej przypomina zagnieżdżone, jeśli instrukcje niż łańcuchowe. Czuję się lepiej, ponieważ obie połówki każdej trójki są na tym samym poziomie, ale różnią się od pozostałych.
Geobits
Jeśli anonimowa funkcja jest akceptowalna, możesz void m()()->
skrócić
@ dohaqatar7 Tak, ale nie używam funkcji anonowych Javy do gry w golfa kodu. Zasadniczo wydaje mi się to podejrzane, niezależnie od tego, czy inni czują to samo.
Geobits
Można to zrobić p+=?
lirtosiast
5

Java, 574 bajty

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

Zasadniczo taki sam jak wersja C #, z wyjątkiem zaciemnionego i zminimalizowanego.

faza
źródło
tyle niepotrzebnych miejsc ...;)
Czy
@ Czy właśnie to naprawiłem: P
faza
1
Używaj także liter i nazw trójskładnikowych.
lirtosiast
@ThomasKwa naprawiono: D
faza
6
Wciąż jest dużo niepotrzebnych miejsc i brak trójskładników;)
Czy
5

Julia, 161 bajtów

Korzysta w, a, s, id aby poruszać się w górę, w lewo, w dół iw prawo.

Pełny kod, w tym drukowanie (330 bajtów):

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

Kod punktowany, z wyłączeniem drukowania (161 bajtów):

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

Różnica polega na tym, że nie zapisujemy stanu gry jako matrycy; wszystkie istotne informacje są zawarte w tablicach ci a. I oczywiście nic nie jest drukowane. Użytkownik nie będzie już monitowany o podanie, gdy gracz osiągnie amulet.


Ungolfed + objaśnienie (pełny kod):

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

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

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

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

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

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

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

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

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

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

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

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

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

end
Alex A.
źródło
Myślę, że to w porządku
3
+1 za wersję skompresowaną / zaciemnioną, wyglądającą bardzo podobnie do tego, co pamiętam z faktycznego kodu źródłowego nethacka.
Ben Jackson
Możesz zaoszczędzić kilka bajtów, używając gorszej randomizacji:a=[rand(1:5),1] c=a+1
lirtosiast
@ThomasKwa: Co to za zabawa, jeśli jest zawsze w pierwszej linii? :)
Alex A.,
3

Partia, 329 bajtów

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

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


:: Two empty lines are required here
cls
set "display="
for /l %%r in (0,1,4) do (
    set "line="
    for /l %%c in (0,1,15) do (
        set "char=."
        if %3 EQU %%r (
            if %4 EQU %%c (
                set char="
            )
        )
        if %1 EQU %%r (
            if %2 EQU %%c (
                set "char=@"
            )
        )
        set "line=!line!!char!"
    )
    set "display=!display!!line!!NL!"
)
echo !display!
exit /b
ankh-morpork
źródło
To bardzo imponujące. Dziwię się, że można to zrobić.
eis
To nie wyświetla dla mnie lochu, tylko serię wierszy monitujących [W, A, S, D] ?. Wygląda na to, że „działa” - chodzenie po nie wyświetlonym lochu ostatecznie kończy się. win7 cmd.exe
Dan Pritts,
Działa dla mnie z Win7 cmd.exe - kiedy piszę, że dostajęMicrosoft Windows [Version 6.1.7601]
Jerry Jeremiah
@DanPritts To dziwne. Działa idealnie dla mnie w systemie Windows 8 ( Microsoft Windows [Version 6.2.9200])
ankh-morpork
doh, nie skopiowałem i nie wkleiłem całej rzeczy, nie przewinąłem okna w dół. Dobra robota.
Dan Pritts,
3

Perl, 228 222 znaków (nie licząc znaków nowej linii, które nie są integralną częścią działania kodu) - 207, jeśli nie liczącprint iprint if instrukcji, które są używane do drukowania, ale nie dodają się do logiki gry; 144, jeśli rozważa również kod generowania reprezentacji pola w ramach drukowania, jak sugeruje Yakk w komentarzach)

W tym kodzie do kontroli użyto małych liter; dane wejściowe należy potwierdzić za pomocą Enter. Testowane z Perlem 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}}

Zauważ, że dla tego kodu nie można oddzielić obliczeń i drukowania, ponieważ operacje są wykonywane bezpośrednio na drukowanej reprezentacji przy użyciu wyrażeń regularnych.

Wyjaśnienie:

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

Ta linia określa pozycję gracza i amuletu. Pozycja gracza jest określona przez $==rand(80)i jest łatwa do zrozumienia: na planszy 5 × 16 istnieje 80 różnych pozycji, w których gracz może być. Pozycja jest przechowywana w $=zmiennej, która wymusza zapisanie wartości na liczbę całkowitą; oszczędza to kilka bajtów, dzięki czemu nie trzeba jawnie rzutować wyniku na liczbę całkowitą ( randzapewnia wartość zmiennoprzecinkową).

Ponieważ jedna z pozycji jest już zajęta przez gracza, dla amuletu pozostało tylko 79 pozycji, dlatego dla pozycji amuletu $a=$==rand(79)używana jest pozycja . Ponownie, przypisanie do $=wymuszenia konwersji na liczbę całkowitą, jednak dodatkowo przypisuję to $aw celu ponownego użycia$= dla pozycji gracza.

Aby uniknąć sytuacji, w której amulet będzie zajmował tę samą pozycję co gracz, przesuwa się o jedną pozycję, jeśli jego pozycja jest co najmniej tak duża jak pozycja gracza, co zapewnia równomierny rozkład na miejscach, które gracz nie zajmuje. Osiąga się to tutaj, $a = ($a >= $=)gdzie $=tutaj znajduje się pozycja gracza. Teraz pierwszy wiersz jest generowany przez wstawienie dwóch początkowych przypisań zamiast pierwszego $a$ and the only$ = `w tym wyrażeniu.

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

To generuje początkowe pole, a następnie drukuje. ("."x80)po prostu generuje ciąg 80 kropek. =~s/(.{$=})./\1@/rnastępnie zastępuje $=th znak z @i =~s/(.{$=})./\1@/rna $ath znak z ". Z powodu rmodyfikatora nie próbują modyfikować w miejscu, ale zwracają zmodyfikowany ciąg, dlatego można je zastosować do poprzednich wyrażeń. Na koniec =~s/(.{16})/\1\n/grwstawia nowy wiersz co 16 znaków. Zauważ, że pole jest przechowywane w specjalnej zmiennej, $_której można użyć pośrednio w późniejszych instrukcjach.

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

Tworzy to skrót zawierający reguły zastępowania dla różnych ruchów. Bardziej czytelna wersja tego jest

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

Klucze są znakami ruchów, a wartości są łańcuchami zawierającymi odpowiednią regułę zastępowania.

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

To jest główna pętla. while(/"/)sprawdza, czy w "znaku nadal znajduje się znak $_(to znaczy w polu). Jeśli przejdziemy na amulet, jego postać zostanie zastąpiona postacią gracza, więc zniknie z pola.

eval $r{getc STDIN}odczytuje znak ze standardowego wejścia, wyszukuje odpowiednią regułę zamiany z has %ri stosuje ją do $_pola. To sprawdza, czy rzeczywiście dokonano zamiany (to znaczy klucz został znaleziony w haszu i ruch był możliwy; ruch niemożliwy nie pasuje do reguły wymiany). W takim przypadku printjest wykonywany. Ponieważ jest wywoływany bez argumentów, wypisuje $_zmodyfikowane pole.

celtschk
źródło
1
To, że podałeś wiersze dla zwiększenia czytelności, nie oznacza, że ​​musisz je policzyć. Widzę 228 bajtów. Ponadto, zgodnie ze szczegółowymi regułami tego pytania, drukowana część kodu nie ma wpływu na liczbę bajtów.
Dennis
@Dennis: Aby zapoznać się z częścią dotyczącą drukowania, zobacz wyjaśnienie, które dodałem: Nie można w sposób znaczący oddzielić drukowania i oceny w moim kodzie. Teraz zmieniłem liczenie, jak zasugerowałeś.
celtschk
Czy są jakieś zmiany stanu w kodzie drukowania? Nie? Cóż, moim zdaniem, ponowne użycie wyjściowego kodu drukowania dla twojej logiki nie powinno cię karać. Kod ruchu (który jest odrębny!) Powinien się liczyć, ale kod, który generuje „ciąg wyświetlania” nie powinien się liczyć.
Yakk,
@Yakk: Którą część mojego kodu uważasz za kod do drukowania? (Właściwie uważam, że wykluczenie drukowania kodu z liczenia było złym pomysłem, właśnie dlatego, że nie zawsze jest dobrze zdefiniowane, co to jest „kod drukowania”.)
celtschk
@celtschk ("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/grna pierwszy rzut oka jest dość blisko, ale mój perl-fu jest kilka lat zardzewiały. Mogłem tam nie zauważyć zmiany stanu.
Yakk,
2

C #, 256 248 234 227 226 225 bajtów

Używa strzałek NumPad z włączonym NumLock do poruszania się.

Wcięte i skomentowane dla jasności:

using System;
class P{
    static void Main(){
        int a=0,b=0,c,d,e;
        var r=new Random();
        while(0<((c=r.Next(16))&(d=r.Next(5))));
        Draw(a,b,c,d); // Excluded from the score.
        while(a!=c|b!=d){
            e=Console.ReadKey().KeyChar-48;
            a+=e==4&a>0?-1:e==6&a<15?1:0;
            b+=e==8&b>0?-1:e==2&b<4?1:0;
            Draw(a,b,c,d); // Excluded from the score.
        }
    }
    // The following method is excluded from the score.
    static void Draw(int a, int b, int c, int d){
        Console.Clear();
        for (int y = 0; y < 5; y++)
        {
            for (int x = 0; x < 16; x++)
            {
                Console.Write(
                    x == a && y == b ? '@' :
                    x == c && y == d ? '"' :
                                       '.'
                );
            }
            Console.WriteLine();
        }
    }
}
Hand-E-Food
źródło
1
Myślę, że C # ints domyślnie inicjuje do zera. Ponadto (obecnie nie mogę sprawdzić), czy rzutowanie nie jest problemem, możesz przekonwertować literały znakowe na ints lub przynajmniej „a” na 97 (myślę), chociaż pozostałe to trzy cyfry.
Domyślnie inicjowane są tylko pola klas, co w tym przypadku wymaga zadeklarowania ich jako statycznych. Zmienne metod należy zainicjować przed pierwszym użyciem. To wymaga mniejszej liczby postaci: 4 vs 7.
Hand-E-Food
Dzięki @tolos za wskazówkę dotyczącą niejawnego rzucania char na int! Jeszcze lepiej, jeśli użyję wyrzucania enum ConsoleKey jako int, mogę użyć 2-cyfrowych wartości.
Hand-E-Food
Technicznie Mainnie trzeba wywoływać tej metody Main, abyś mógł ogolić kolejne trzy znaki.
Luaan,
@Luaan, myślę, że się mylisz. Dokumentacja w C #: msdn.microsoft.com/en-us/library/acy3edy3.aspx
Hand-E-Food
2

HTML + JavaScript (ES6), wynik może być 217

Zbyt długi, ale można grać online w poniższych fragmentach.

Wiersz 6 (T.value ...) jest dla danych wyjściowych i nie jest liczony (ale dla uproszczenia policzyłem tagi otwierające i zamykające obszar tekstowy, nawet jeśli są one również wyjściowe)

Co do losowości: amulet jest zawsze w prawej połowie siatki, a gracz zawsze zaczyna w lewej połowie.

Kliknij textArea (po powiększeniu), aby rozpocząć i ponownie uruchomić grę.

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

Fragment kodu EcmaScript 5 (testowany w Chrome)

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

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

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

edc65
źródło
2

ActionScript 3: 267 bajtów

Działający przykład jest dostępny 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()}

Oto kompletny (dostępny dla ułatwienia czytelności) program korzystający z funkcji gry:

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

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

        public function MiniRogue()
        {
            g();
        }

        function g(){
            var r=Math.random;
            while(p==a){
                a=r()*80;
                p=r()*80
            }
            addEventListener("keyDown",function(e){
                if(a==p)
                    return;
                if(e.keyCode==87&&p>15)
                    p-=16
                if(e.keyCode==83&&p<64)
                    p+=16
                if(e.keyCode==65&&p%16>0)
                    p--
                if(e.keyCode==68&&(p+1)%16>0)
                p++
                print()
            });
            print()
        }

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

JavaScript: 307 216

Możesz zagrać we fragmencie poniżej! Liczby po lewej stronie są tylko po to, aby konsola (przynajmniej chromowana) nie scalała wierszy.

Aby uruchomić kod:

  1. kliknij „uruchom fragment kodu”
  2. naciśnij ctrl-shift-j, aby otworzyć konsolę
  3. kliknij sekcję wyników
  4. używaj klawiszy strzałek i graj

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

Bez golfa:

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

Edycja 1: Przeczytaj uważniej reguły i odpowiednio przepisaj mój kod

  • Wartość amuletu y jest teraz losowa
  • gracz nie może już uciec z pokoju
  • Nie liczę już znaków w funkcji rysowania ani wywołań do niej
Eric Vincent
źródło
1

SpecBAS - 428 402 (z wyłączeniem drukowania, 466 425 po policzeniu)

Używa Q / A / O / P do poruszania się odpowiednio w górę / w dół / w lewo / w prawo.

Linia do wydrukowania lochu na linii 1 jest jedyną linią, którą można zignorować, ale nieco ją też zignorowała.

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

Odniesienie do # 34 to tylko krótki sposób na umieszczenie CHR $ (34) w kodzie.

Dzięki @Thomas Kwa, nie zauważyłem, że początkowa pozycja gracza jest losowa. Użyłem także osobnych instrukcji IF, aby zgolić kilka znaków.

Brian
źródło
Możesz być w stanie uratować niektóre postacie, losowo gorzej: 2 LET px=1: LET py=1: LET ax=2: LET ay=INT(RND*5)a także używając IF instead of ELSE IF.
lirtosiast
1

Kolejny C #, 221 171 170

Oto inny sposób w C # z losowymi obiema pozycjami. Chciałem to pokazać, nawet jeśli ta część jest o 7 bajtów dłuższa niż rozwiązanie Hand-E-Food.
Odpowiedź Hand-E-Food będzie oczywiście krótsza, gdy tylko użyje Console.Read ().
Minusem Consol.Read jest to, że naciśnięcie wymaganego Enter powoduje wydrukowanie pola jeszcze 2 razy.
Ale nie sądzę, że istnieje wymóg drukowania tylko na (rzeczywistych) danych wejściowych.

Nawigacja jest wykonywana przez 8426 jak w rozwiązaniu 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;
}
}
}


Edycja: (dodano nowe rozwiązanie i przeniesiono PrinterClass na koniec)
Edycja2: (zmieniono 14 na 15 i zapisano bajt, zaczynając od prawego dolnego rogu)

Dostosowując technikę Maurisa, można stopić go do 171 bajtów w C # (oczywiście teraz bez losowości obu pozycji):

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

Klasa drukarek jest prawie taka sama, tylko nowe przeciążenie wydruku ...

class Printer
{
    public static void Print(int ax, int ay, int px, int py)
    {
        Console.Write('\n');
        for (int y = 0; y < 5; y++)
        {
            for (int x = 0; x < 16; x++)
            {
                if (x == px && y == py)
                    Console.Write('@');
                else if (x == ax && y == ay)
                    Console.Write('"');
                else
                    Console.Write('.');
            }
            Console.Write('\n');
        }
    }

    public static void Print(int p, int a)
    {
        Print(p/5,p%5,a/5,a%5);
    }
}
Phil
źródło
1

Ruby, 185

Oto także Rubinowy przykład.
Jestem bardzo nowa w Ruby, może ktoś wie, jak to zrobić lepiej :)

Zaliczyłem lineFeeds jako 1, ponieważ w przeciwnym razie program ulegnie awarii.

Nawigacja jest wykonywana przez 8462. Za każdym razem, naciskając Enter, musisz wysłać dane wejściowe.

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


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

QBasic, 103 bajty

Zgodnie z regułami wyzwania Showpodprogram nie jest wliczany do liczby bajtów, podobnie jak Show p, q, a, bwywołanie (z następującą nową linią).

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

Aby przejść, wprowadź liczbę i naciśnij Enter: 1aby przejść w lewo, 2aby przejść w górę,3 aby przejść w prawo i4 zejść w dół.

Ten kod nie wyświetla stanu gry na końcu, gdy gracz znajdzie amulet. Aby to zrobić, dodaj kolejną Show p, q, a, bpoIF instrukcji.

Wyjaśnienie

Pozwól a, breprezentują współrzędne i amulet p,q współrzędne odtwarzacza. Gracz zaczyna od (0, 0), a amulet zaczyna się w rzędzie 0, z kolumną od 1 do 9 włącznie, na podstawie cyfry 1 aktualnego czasu.

Reszta to tylko matematyka z warunkami warunkowymi. Ważną rzeczą do zapamiętania jest to, że warunki warunkowe w QBasic zwracają wartość „ 0fałsz”, „ -1prawda”. Spójrzmy na instrukcję aktualizacji wiersza odtwarzacza:

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

Jeśli m=2chcemy przejść w górę, odejmując 1 od p, o ile p>0. Podobnie, jeśli m=4chcemy przejść w dół, dodając 1 do p, o ile p<4. Możemy uzyskać pożądane zachowanie poprzez pomnożenie. Jeśli oba czynniki są -1, ich produktem będzie 1, który możemy odjąć lub dodać do p. Jeśli którykolwiek jest warunkowy0 , produkt będzie0 bez skutku.

Podobnie warunkiem ustalenia, czy gracz znalazł amulet, jest:

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

Jeżeli którykolwiek z warunkowych jest prawdą, ich suma będzie różna od zera (albo -1albo -2), a zatem truthy, a program wraca do linii 1. Gdy pjest równy ai qwynosi bobie warunkowe będzie 0, więc ich suma będzie 0i przepływ sterowania można osiągnąć koniec programu.

DLosc
źródło