NetHack น้อยที่สุด


64

NetHackเป็นเกมโร๊คไลค์ที่ผู้เล่นจะต้องดึง Amulet of Yendor ออกจากดันเจี้ยนระดับต่ำสุด เล่นกันโดยทั่วไปผ่าน telnet เกมทั้งหมดจะแสดงด้วยกราฟิก ASCII เกมดังกล่าวมีความท้าทายอย่างยิ่งและต้องมีความรู้เกี่ยวกับกลไกต่าง ๆ ของเกมเพื่อที่จะประสบความสำเร็จ

สำหรับจุดประสงค์ของการท้าทายสมมติว่าดันเจี้ยนทั้งหมดเป็นระดับเดียวและมีเพียง 5 × 16 ตัวอักษร นอกจากนี้สมมติว่านี่เป็นดันเจี้ยนที่ "ปลอดภัย" หรือคุณกำลังใช้ต้นแบบเท่านั้น - จะไม่มีสัตว์ประหลาดความกังวลเกี่ยวกับความหิว ฯลฯ ที่จริงแล้วคุณต้องติดตามตำแหน่งของตัวละครและเครื่องรางและเกม จะจบลงอย่างมีประสิทธิภาพเมื่อผู้เล่นมาถึงสถานที่เดียวกันกับเครื่องราง

ข้อกำหนดในการท้าทาย

  • จะมีดันเจี้ยน 5 × 16 (ระดับเดียว)
  • ให้ตำแหน่งเริ่มต้นของผู้เล่น (สุ่มเลือก) และพระเครื่องจะแยกแบบสุ่ม (แตกต่างกันในแต่ละครั้งที่โปรแกรมทำงาน) เริ่มสี่เหลี่ยมภายในดันเจี้ยน นั่นคือเครื่องรางไม่ได้รับอนุญาตให้เริ่มต้นในตารางเดียวกันกับผู้เล่น
  • ยอมรับปุ่มป้อนข้อมูลสี่ปุ่มซึ่งย้ายผู้เล่นหนึ่งช่องในเวลาเดียวกัน (สี่ทิศทางสำคัญ) อนุญาตให้อ่าน / ประมวลผลอินพุตอื่น (ฟังก์ชั่น readline () ที่ต้องกด 'Enter' ฯลฯ )
  • ไม่อนุญาตให้เดินทางนอกขอบเขตของคุกใต้ดิน เช่นหากผู้เล่นอยู่บนขอบด้านขวาของดันเจี้ยนที่ถูกต้องจะไม่ทำอะไรเลย
  • หลังจากรุ่นเริ่มต้นและหลังการเคลื่อนไหวแต่ละครั้งให้พิมพ์สถานะของเกม เช่นนี้เป็นกอล์ฟรหัสและการพิมพ์ค่อนข้างจืดไม่สนใจนับจำนวนตัวอักษรสำหรับฟังก์ชั่นการพิมพ์และฟังก์ชั่นการโทรสมมติว่าไม่มีการเปลี่ยนแปลงรัฐ เซลล์ว่างควรแสดงเป็นจุด ( .), เครื่องรางเป็น"เครื่องหมายคำพูดคู่ ( ) และอักขระตามที่สัญลักษณ์ ( @)
  • เกมจะจบลงเมื่อผู้เล่น "ค้นพบ" เครื่องราง (มาถึงที่ตารางเดียวกัน)

การชนะ

นี่คือรหัสการแข่งขันกอล์ฟรหัสที่สั้นที่สุดเพื่อตอบสนองความต้องการหนึ่งสัปดาห์นับจากวันนี้จะมีการประกาศผู้ชนะ

ตัวอย่าง

นี่คือตัวอย่างโซลูชันใน C # (ungolfed) เพื่อแสดงข้อกำหนดพื้นฐานและเอาต์พุตตัวอย่าง

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

จำนวนตัวอักษรทั้งหมดคือ 1474 แต่การเพิกเฉยต่อการเรียกไปยังฟังก์ชันการพิมพ์และความหมายของจำนวนอักขระขั้นสุดท้าย 896แต่ไม่สนใจการโทรไปยังฟังก์ชั่นการพิมพ์และความหมายของมันนับจำนวนตัวอักษรสุดท้ายคือ

เอาต์พุตเมื่อรันโปรแกรม:

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

เอาต์พุต (รวมถึงด้านบน) หลังจากกดปุ่ม 'a' สองครั้ง:

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

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

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

10
ฉันรู้สึกว่านี่จะเป็นที่สนใจของ @Doorknob
Alex A.

10
Rogueเป็นเกมโร๊คไลค์ดั้งเดิมที่ผู้เล่นจะต้องดึง Amulet of Yendor ออกมาจากระดับต่ำสุดของคุกใต้ดิน ทำไมไม่เรียกเจ้านี่ว่า Rogue ที่น้อยที่สุด?
Gilles

5
@Gilles ทำไมไม่เรียกสิ่งนี้ว่างูน้อยที่สุด?
Casey Kuball

26
Psshh ไม่มีการเคลื่อนไหวในแนวทแยง? ไม่มี yubnhjkl? ไม่แม้แต่จะขึ้นบันไดเพื่อปีนขึ้นหลังจากได้รับเครื่องราง : P ( โหวตเพิ่มอย่างโกรธแค้น )
Doorknob

2
@tolos: ฉันยังไม่ชัดเจนว่าอะไรที่นับเป็นการสุ่มที่นี่ มันเป็นไปไม่ได้ที่จะเติมเต็มความแตกต่างในแต่ละครั้งที่โปรแกรมรันข้อกำหนดหากโปรแกรมรัน 80 ครั้ง ... โดยเฉพาะในคำตอบนี้เครื่องรางสามารถครอบครองได้เพียง 9 จาก 79 ตำแหน่งที่เป็นไปได้ทั้งหมด นั่นนับหรือไม่
Dennis

คำตอบ:


37

TI-BASIC, 42 41 38 36 35 ไบต์

สำหรับเครื่องคิดเลขกราฟซีรีย์ TI-83 หรือ 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

ทิศทางใดที่ผู้เล่นจะไปคือฟังก์ชั่นของรหัสกุญแจของปุ่มกด แต่ปุ่มสี่ปุ่มที่ใช้งานได้จริงจะอยู่ที่แถวบนสุด:

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

เครื่องรางเริ่มต้นที่หนึ่งในห้าของสี่เหลี่ยมในคอลัมน์แรกและผู้เล่นเริ่มต้นที่ตารางด้านล่างขวา ตัวอย่างเช่นการจัดเรียงที่เป็นไปได้คือ:

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

คำอธิบาย

ตำแหน่งของผู้เล่นจะถูกเก็บเป็นจำนวนเชิงซ้อนจาก0+0iถึง15+4iส่วนที่ส่วนจริงไปทางขวาและส่วนจินตภาพลดลง สิ่งนี้อำนวยความสะดวกในการตรวจสอบขอบเขตที่ง่าย ๆ ที่ด้านบนและซ้าย: เราเพียงแค่ชดเชยจำนวนเล็กน้อยและปัดไปทางศูนย์ ตัวอย่างเช่นหากการชดเชยคือ0.5และตำแหน่งของเราคือ-1+3i(ปิดหน้าจอไปทางซ้าย) ตำแหน่งนั้นจะได้รับการแก้ไขให้iPart(-0.5+3.5i)=0+3iตรงจุดที่ควรจะเป็น การตรวจสอบขอบเขตด้านล่างและด้านขวานั้นซับซ้อนกว่าเล็กน้อย เราต้องลบจำนวนออกจากค่าคงCที่ซึ่งเป็นเรื่องเกี่ยวกับ15.635 + 4.093i(มันสั้นที่สุดที่ฉันสามารถหาได้ระหว่าง15+4iและ16+5i) ปัดเศษลบจากCอีกครั้งเพื่อพลิกตัวเลขกลับและปัดอีกครั้ง

เมื่อกดปุ่มตำแหน่งผู้เล่นที่ไม่ได้ทำการปรับจะย้ายไป 1 หน่วยในบางทิศทาง แต่ส่วนจำนวนเต็มจะเปลี่ยนเฉพาะเมื่อกดปุ่มบางปุ่มเท่านั้น โชคดีที่กุญแจที่ใช้งานทั้งหมดอยู่ในแถวบนสุด ด้านล่างเป็นกราฟของออฟเซ็ตในกรณีที่กดปุ่ม 11, 12, 13 และ 15 และเมื่อไม่มีการกดปุ่ม (ไม่มีการกดคือจุดภายในจัตุรัสกลางทำให้ส่วนจำนวนเต็มไม่เปลี่ยนแปลง; สี่ปุ่มกด 'ออฟเซ็ตมีส่วนจำนวนเต็มที่แตกต่างกัน) Cคือกากบาทสีแดงที่ศูนย์กลางของวงกลม

ป้อนคำอธิบายรูปภาพที่นี่

รหัสเก่า (42 ไบต์):

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

ข้อ จำกัด

ไม่มีวิธีในการหลีกเลี่ยง"อักขระดังนั้นสตริงที่"ไม่สามารถสร้างได้ภายในโปรแกรม ดังนั้นสิ่งนี้ใช้เครื่องหมาย umlaut ¨แทนเครื่องหมายคำพูด (ถ้ามีสตริงที่มีอยู่แล้วที่มีเครื่องหมายอัญประกาศฉันสามารถแสดงได้) ในการรับ¨และ@เข้าสู่โปรแกรมต้องใช้เครื่องมือภายนอก อย่างไรก็ตามมันถูกต้อง TI-BASIC


2
เพียงเพื่อความสนุกฉันได้สร้างตัวอย่างนี้ซึ่งวางสัญลักษณ์ diaeresis และ @ ใน Str1 (ซึ่งต่างจาก 'เครื่องมือภายนอก') เลือกบรรทัดที่ด้านบนที่ตรงกับเครื่องคิดเลขของคุณป้อนเข้าไปในโปรแกรมใหม่และเรียกใช้โปรแกรมด้วย Asm (.
MI Wright

โอ้ฉันลืมรหัสในเครื่องในเครื่องคิดเลข ไม่ต้องการที่จะผิดพลาดของฉันกับพิมพ์ผิด แต่ฉันเชื่อว่ามันใช้งานได้
lirtosiast

44

CHIP-8 , 48 ไบต์

สิ่งนี้อาจไม่ถือว่าถูกกฎหมาย แต่ทำไมจึงไม่เป็นเช่นนั้น ฉันเขียนโปรแกรมของฉันใน CHIP-8 ซึ่งเป็นภาษาการเขียนโปรแกรมแบบ bytecode สำหรับคอนโซลเกมเสมือนจริง คุณสามารถลองใช้โปรแกรมที่สมบูรณ์ (99 ไบต์) ในเบราว์เซอร์ของคุณโดยใช้ตัวจำลอง / ดีบั๊กเกอร์ฉันเขียนชื่อ Octo:

ภาพหน้าจอ

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

ดัมพ์เลขฐานสิบหกของโปรแกรมที่สมบูรณ์นั้นมีดังนี้:

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

คุณสามารถย้ายผู้เล่นด้วยปุ่ม ASWD หรือปุ่ม 7589 บนปุ่มกด CHIP-8 ดั้งเดิม หากฉันลบรหัสและข้อมูลทั้งหมดสำหรับการวาดพื้นหลังและเครื่องเล่นฉันจะได้รับการถ่ายโอนข้อมูล 48 ไบต์นี้แทน:

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

รูปแบบที่สมบูรณ์ของโปรแกรมถูกเขียนขึ้นในภาษาแอสเซมบลีระดับสูงดังนี้:

: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

โปรดทราบว่าไบต์ที่คอมไพล์ด้วยตัวเองคือภาษาการเขียนโปรแกรม CHIP-8 แอสเซมเบลอร์เป็นวิธีที่สะดวกกว่าในการเขียนโปรแกรมดังกล่าว


19
เครื่องมือที่เหมาะสมสำหรับงาน
Dennis

6
+1 ที่ทำให้ฉันเสียเวลาเล่นเกมของคุณซ้ำแล้วซ้ำอีก
Alex A.

4
@AlexA ถ้าคุณต้องการที่จะเสียเวลามากยิ่งขึ้นคุณควรพยายามเอ็กซ์พลอเรอร์ถ้ำ ASWD ย้ายในทางตรงข้ามและ QE ใช้เพื่อรีเซ็ต / ย้ายบล็อกในระดับ platformer
JohnE

4
เยี่ยมมากวันหยุดสุดสัปดาห์ของฉันไป
Alex A.

1
ตอนแรกฉันไม่เชื่อ แต่ Cave Explorer นั้นสนุกและ CHIP-8 นั้นนานกว่าที่ฉันคาดไว้มาก ดังนั้นฉันเดาว่าฉันจะต้องเรียนรู้สิ่งนี้

10

Python 3, 86 ไบต์

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]

นับเฉพาะสองบรรทัดด้านล่างและวางd();เท่านั้น


ฉันบันทึกไบต์อีกโดยเริ่มต้นเล่นในมุมด้านล่างขวา (ที่ "ล่าสุด" สแควร์) จากนั้นสุ่มเก็บตัวอย่างจากครั้งแรก 79 สี่เหลี่ยม
Lynn

โอ๊ะโอแก้ไขแล้ว! ฉันเดาว่าฉันไม่น่าทึ่งที่การนับไบต์ด้วยตนเอง : <
Lynn

1
ฉันคิดว่าคุณสามารถบันทึกตัวอักษรอีกโดยการแทนที่ด้วยa=id(9)%79 a=id(9)%p
kirbyfan64sos

@ kirbyfan64sos ยอดเยี่ยม! ขอบคุณ
Lynn

1
นอกจากนี้ถ้าคุณทำเช่นนี้สำหรับหลาม 3 คุณสามารถเปลี่ยนการเรียกร้องให้เพียงraw_input input
kirbyfan64sos

10

C, 122 121 115 104 102 101 ไบต์

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

โพสต์ครั้งแรกที่นี่! ฉันหวังว่าคุณจะชอบมัน :)

oคือการพิมพ์, erm, ฟังก์ชั่น ฮีโร่ผู้กล้าหาญของเราสามารถเคลื่อนที่ไปได้ด้วย 2, 4, 6 และ 8 แต่ระวังอย่าส่งอินพุตอื่น (ไม่มีบรรทัดใหม่!)

อัปเดต 1:พารามิเตอร์ที่นำมาaและiเข้าสู่main

อัปเดต 2: OP มีการยืนยันว่าอินพุตสายเดียวนั้นโอเคฉันกำจัดscanf(ซึ่งฉันเคยข้ามบรรทัดใหม่)

อัปเดต 3:ใช้อาร์เรย์แบบผสมตามตัวอักษรและปรับเปลี่ยนเค้าโครงอินพุต โปรแกรมจะไปยุ่งเหยิงถ้าคุณป้อนทิศทางที่ไม่ถูกต้อง;)

อัปเดต 4:พบว่าไม่มีการนับการโทรไปยังฟังก์ชั่นการพิมพ์ จดบันทึกเพื่ออ่านกฎอย่างละเอียดมากขึ้น

อัปเดต 5:บันทึกหนึ่งไบต์ขอบคุณ Mikkel Alan Stokkebye Christia


อาจ!!(p%16)จะเป็นp%16>0อย่างไร ฉันจำคำสั่งของฉันไม่ได้
lirtosiast

@ThomasKwa เป็น แต่ผู้ที่-ไม่สามารถช่วยเหลือได้ แต่ติดอยู่pดังนั้นจำเป็นต้องใช้วงเล็บด้วยวิธีใดวิธีหนึ่ง คู่ปังเป็นเพียง obfuscation :)
เควนติน

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

@MikkelAlanStokkebyeChristia ขอบคุณ :)
Quentin

9

CJam, 46 45 44 40 39 37 ไบต์

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

บรรทัดแรก (กำหนดฟังก์ชั่นที่พิมพ์สถานะเกมปัจจุบัน) และPในบรรทัดที่สอง (เรียกใช้ฟังก์ชันนั้น) ไม่ได้มีส่วนช่วยนับไบต์

ทั้งตำแหน่งเริ่มต้นและตำแหน่งของเครื่องรางจะถูกสุ่มหลอก การกระจายนั้นเหมือนกันและ PRNG พื้นฐานอนุญาต

การป้อนข้อมูลเป็นE, 6, 9และBสำหรับขึ้น , ลง , ซ้ายและขวาที่มีCaps Lockการเปิดใช้งานตามมาด้วยEnterการเปิดใช้งานตามมาด้วย

รุ่นอื่น

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

ด้วยค่าใช้จ่ายที่เพิ่มขึ้นอีกสี่ไบต์รูปแบบอินพุตจะได้รับการปรับปรุงอย่างมีนัยสำคัญ:

  • รุ่นนี้ยอมรับ8, 2, 4และ6สำหรับขึ้น , ลง , ซ้ายและขวาซึ่งตรงกับปุ่มลูกศรที่สอดคล้องกันใน numpad
  • นอกจากนี้ยังยอมรับ7, 9, 1และ3สำหรับการเคลื่อนไหวที่สอดคล้องกันในแนวทแยง

การทดสอบ

เนื่องจาก I / O เป็นแบบโต้ตอบคุณควรลองใช้รหัสนี้กับล่าม Javaล่าม

ดาวน์โหลดเวอร์ชันล่าสุดและรันโปรแกรมดังนี้:

java -jar cjam-0.6.5.jar nethack.cjam

เมื่อต้องการหลีกเลี่ยงการกดEnterหลังจากแต่ละคีย์และสำหรับการอัปเดตผลลัพธ์แบบแทนที่คุณสามารถใช้ 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"

เรียกใช้สิ่งนี้:

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

เวอร์ชั่นหลัก

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.

รุ่นอื่น

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.

ฟังก์ชั่น 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
ฉันอยู่บนหางของคุณด้วย TI-BASIC! ฉันจะโพสต์เมื่อฉันตรวจสอบการแก้ไขของฉัน
lirtosiast

8

Java, 231 ไบต์ (196 ถ้าฟังก์ชัน)

นี่คือรหัสโปรแกรมเต็มรูปแบบที่ 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":""));}}}

หากไม่มีฟังก์ชั่นการพิมพ์ 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);}}

ถ้าเพียงแค่ฟังก์ชั่นก็โอเค (ฉันไม่ชัดเจนจากสเป็ค) จากนั้นฉันสามารถลดขนาดลงไปอีก 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);}

และด้วยการขึ้นบรรทัดใหม่เพื่อความชัดเจน ...

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

โปรดทราบว่าฉันไม่ได้นับฟังก์ชั่นการพิมพ์p(p,y)แต่ฉันเป็นนับจำนวนการโทรเข้าเนื่องจากฉันมีสิ่งที่เปลี่ยนแปลงภายในคำสั่งการโทร

ASDWจะทำงานร่วมกับตัวอักษร เนื่องจากวิธีการตรวจสอบสำหรับตัวอักษรอื่น ๆ บางตัวอาจทำงานได้เช่นกัน แต่สเป็คไม่ได้พูดอะไรเกี่ยวกับสิ่งที่จะเกิดขึ้นถ้าฉันกดปุ่มที่แตกต่างกัน


ฉันชอบการจัดรูปแบบตัวดำเนินการประกอบไปด้วยสามระดับในระดับของการเยื้องเดียวกันเช่นเดียวกับที่คุณใช้โซ่ของ if / else หาก มันอ่านง่ายขึ้น
lirtosiast

@ThomasKwa ใช่ฉันทำทั้งสองครั้ง นี่เป็นเหมือนคำสั่งซ้อนกันมากกว่าข้อความที่ถูกล่ามโซ่ ฉันรู้สึกดีขึ้นเพราะแบ่งออกเป็นสองส่วนเท่า ๆ กันในระดับเดียวกัน แต่แตกต่างจากคนอื่น ๆ
Geobits

หากฟังก์ชั่นที่ไม่ระบุชื่อเป็นที่ยอมรับคุณสามารถตัดคำตอบของคุณเป็น 192 ไบต์: void m()กลายเป็น()->
ankh-morpork

@ dohaqatar7 ใช่แล้ว แต่ฉันไม่ได้ใช้ฟังก์ชั่นอานนท์ของ Java สำหรับการเขียนโค้ดกอล์ฟ โดยหลักการแล้วฉันรู้สึกร่มรื่นไม่ว่าคนอื่นจะรู้สึกเหมือนกันหรือไม่
Geobits

คุณสามารถทำp+=อะไร
lirtosiast

5

Java, 574 ไบต์

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

โดยพื้นฐานแล้วเหมือนกับรุ่น C # ยกเว้นการทำให้สับสนและย่อเล็กสุด


ช่องว่างที่ไม่จำเป็นมากมาย ... ;)
จะ

@ ฉันจะแก้ไขสิ่งนั้น: P
เฟส

1
นอกจากนี้ให้ใช้ชื่อและตัวอักษรหนึ่งตัว
lirtosiast

@ThomasKwa ได้รับการแก้ไข: D
เฟส

6
ยังมีช่องว่างที่ไม่จำเป็นจำนวนมากและยังขาด ternaries;)
จะ

5

Julia, 161 ไบต์

ใช้w, a, sและdจะเลื่อนขึ้นซ้ายลงและขวาตามลำดับ

รหัสเต็มรวมถึงการพิมพ์ (330 ไบต์):

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

โค้ดที่ได้รับยกเว้นการพิมพ์ (161 ไบต์):

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

ความแตกต่างที่นี่คือเราไม่ได้บันทึกสถานะของเกมเป็นเมทริกซ์ ข้อมูลที่เกี่ยวข้องทั้งหมดที่มีอยู่ในอาร์เรย์และc aและแน่นอนไม่มีอะไรถูกพิมพ์ออกมา ผู้ใช้จะไม่ได้รับแจ้งให้ป้อนข้อมูลอีกต่อไปเมื่อผู้เล่นมาถึงเครื่องราง


คำอธิบาย Ungolfed + (รหัสเต็ม):

# 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

ฉันคิดว่า

3
+1 สำหรับรุ่นที่บีบอัด / งงมองคล้ายกับสิ่งที่ฉันจำได้จากซอร์สโค้ด nethack จริง
เบ็คแจ็คสัน

คุณสามารถบันทึกไม่กี่ไบต์โดยใช้การสุ่มแบบแย่ลง:a=[rand(1:5),1] c=a+1
lirtosiast

@ThomasKwa: สนุกไหมถ้าหากมันอยู่ในบรรทัดแรกเสมอ :)
Alex A.

3

รุ่นที่ 329 ไบต์

@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

มันน่าประทับใจมาก ฉันประหลาดใจที่เป็นไปได้ที่จะทำเช่นนี้
eis

สิ่งนี้ไม่แสดงดันเจี้ยนสำหรับฉันมีเพียงชุดของบรรทัดที่แจ้งให้ [W, A, S, D]? ดูเหมือนจะเป็น "งาน" - เดินดันเจี้ยนที่ไม่แสดงในที่สุดก็ออกไป win7 cmd.exe
Dan Pritts

มันใช้งานได้สำหรับฉันด้วย Win7 cmd.exe - เมื่อฉันพิมพ์ ver ฉันจะได้รับMicrosoft Windows [Version 6.1.7601]
Jerry Jeremiah

@DanPritts มันแปลกมาก มันทำงานได้อย่างสมบูรณ์แบบสำหรับฉันบน Windows 8 ( Microsoft Windows [Version 6.2.9200])
ankh-morpork

ใช่ฉันไม่ได้คัดลอกและวางสิ่งของทั้งหมดฉันไม่ได้เลื่อนลงไปที่หน้าต่าง ทำได้ดี.
Dan Pritts

3

Perl, 228 222 ตัวอักษร (ไม่นับการขึ้นบรรทัดใหม่ที่ไม่สำคัญกับการทำงานของรหัส) - 207 ถ้าไม่นับprintและprint ifชิ้นส่วนข้อความสั่งที่ใช้สำหรับการพิมพ์ แต่ไม่เพิ่มตรรกะของเกม 144 หากพิจารณารหัสการสร้างตัวแทนภาคสนามเป็นส่วนหนึ่งของการพิมพ์ตามที่ Yakk แนะนำในข้อคิดเห็น)

รหัสนี้ใช้ตัวพิมพ์เล็ก wasd สำหรับการควบคุม อินพุตต้องได้รับการยืนยันด้วยป้อน ทดสอบกับ 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}}

โปรดทราบว่าสำหรับรหัสนี้มันเป็นไปไม่ได้ที่จะแยกการคำนวณและการพิมพ์เนื่องจากการดำเนินการเสร็จสิ้นโดยตรงกับการเป็นตัวแทนพิมพ์ที่พิมพ์โดยใช้การแสดงออกปกติ

คำอธิบาย:

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

บรรทัดนี้เป็นตัวกำหนดตำแหน่งของผู้เล่นและเครื่องราง ตำแหน่งของผู้เล่นนั้นถูกกำหนดโดย$==rand(80)และง่ายต่อการเข้าใจ: บนกระดาน 5 × 16 มี 80 ตำแหน่งที่แตกต่างกันซึ่งผู้เล่นสามารถ ตำแหน่งจะถูกเก็บไว้ใน$=ตัวแปรที่บังคับให้ค่าที่เก็บไว้เป็นจำนวนเต็ม สิ่งนี้ช่วยประหยัดสองสามไบต์สำหรับการไม่จำเป็นต้องแปลงผลลัพธ์เป็นจำนวนเต็มอย่างชัดเจน ( randส่งค่าทศนิยม)

เนื่องจากเป็นหนึ่งในตำแหน่งที่ถูกครอบครองอยู่แล้วโดยผู้เล่นมีเพียง 79 ตำแหน่งที่เหลือสำหรับพระเครื่องดังนั้นสำหรับตำแหน่งพระเครื่องที่$a=$==rand(79)ถูกนำมาใช้ อีกครั้งการมอบหมายให้$=บังคับให้แปลงเป็นจำนวนเต็ม แต่ฉันกำหนดเพิ่มเติมให้$aเพื่อนำมาใช้ใหม่$=สำหรับตำแหน่งของผู้เล่น

ตอนนี้เพื่อหลีกเลี่ยงเครื่องรางที่จะครอบครองตำแหน่งเดียวกันกับผู้เล่นมันเป็นขั้นสูงโดยตำแหน่งหนึ่งถ้าตำแหน่งอย่างน้อยใหญ่เป็นผู้เล่นให้กระจายเครื่องแบบในสถานที่ไม่ได้ครอบครองโดยผู้เล่น นี่คือความสำเร็จโดย$a = ($a >= $=)ที่$=นี่อยู่ในตำแหน่งของผู้เล่น ตอนนี้บรรทัดแรกถูกสร้างขึ้นโดยการใส่การกำหนดค่าเริ่มต้นสองรายการแทนที่จะเป็น$a$ and the only$ = ` แรกในนิพจน์นี้

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

สิ่งนี้จะสร้างฟิลด์เริ่มต้นและหลังจากนั้นจะทำการพิมพ์ ("."x80)เพียงสร้างสตริง 80 จุด =~s/(.{$=})./\1@/rแล้วแทนที่$=ตัวอักษร TH ด้วย@และตัวอักษร TH กับ เนื่องจากโมดิฟายเออร์จะไม่พยายามแก้ไข แต่ส่งคืนสตริงที่แก้ไขนั่นคือสาเหตุที่พวกเขาสามารถนำไปใช้กับนิพจน์ก่อนหน้าได้ ในที่สุดแทรกบรรทัดใหม่ทุก 16 ตัวอักษร โปรดทราบว่าฟิลด์จะถูกเก็บไว้ในตัวแปรพิเศษซึ่งสามารถนำมาใช้โดยนัยในคำสั่งในภายหลัง=~s/(.{$=})./\1@/r$a"r=~s/(.{16})/\1\n/gr$_

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

สิ่งนี้จะสร้างแฮชที่มีกฎการแทนที่สำหรับการเคลื่อนไหวที่แตกต่างกัน เวอร์ชันที่อ่านง่ายกว่านี้คือ

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

กุญแจคือตัวอักษรสำหรับการเคลื่อนไหวและค่าเป็นสตริงที่มีกฎการแทนที่ที่สอดคล้องกัน

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

นี่คือวงหลัก while(/"/)ตรวจสอบว่ายังมี"อักขระใน$_(นั่นคือในฟิลด์) ถ้าเราย้ายไปที่พระเครื่องตัวละครของมันก็จะถูกแทนที่ด้วยตัวละครของผู้เล่นดังนั้นมันจะหายไปจากสนาม

eval $r{getc STDIN}อ่านอักขระจากอินพุตมาตรฐานค้นหากฎการแทนที่ที่สอดคล้องจาก has %rและนำไปใช้กับ$_นั่นคือฟิลด์ สิ่งนี้ประเมินว่าเป็นจริงหากมีการแทนที่จริง (นั่นคือพบกุญแจในแฮชและการย้ายเป็นไปได้การย้ายที่เป็นไปไม่ได้จะไม่ตรงกับในกฎการแทนที่) ในกรณีprintนั้นจะถูกดำเนินการ เนื่องจากมันถูกเรียกโดยไม่มีอาร์กิวเมนต์มันจะพิมพ์$_นั่นคือฟิลด์ที่ถูกแก้ไข


1
เพียงเพราะคุณมี linefeeds สำหรับการอ่านไม่ได้หมายความว่าคุณต้องนับพวกเขา ฉันเห็น 228 ไบต์ นอกจากนี้ตามกฎเฉพาะของคำถามนี้ส่วนการพิมพ์ของรหัสของคุณไม่ได้มีส่วนช่วยนับจำนวนไบต์
Dennis

@Dennis: สำหรับส่วนการพิมพ์ให้ดูคำอธิบายที่ฉันได้เพิ่ม: คุณไม่สามารถแยกการพิมพ์และการประเมินในรหัสของฉันได้ ตอนนี้ฉันเปลี่ยนการนับตามที่คุณแนะนำ
celtschk

มีการเปลี่ยนแปลงสถานะในรหัสการพิมพ์ของคุณหรือไม่? ไม่มี? ในความคิดของฉันการนำเอาท์พุทของรหัสการพิมพ์กลับมาใช้ใหม่สำหรับตรรกะของคุณไม่ควรลงโทษคุณ รหัสการเคลื่อนไหว (ซึ่งแตกต่าง!) ควรนับ แต่รหัสที่สร้าง "display string" ไม่ควรนับ
Yakk

@Yakk: ส่วนใดของรหัสที่คุณใช้ในการพิจารณารหัสการพิมพ์ (อันที่จริงความคิดของฉันคือการยกเว้นของรหัสที่พิมพ์จากนับเป็นความคิดที่ไม่ดีที่ว่าเพราะมันไม่เคยกำหนดไว้อย่างดีสิ่งที่ "รหัสการพิมพ์" คือ.)
celtschk

@celtschk ("."x80)=~s/(.{$=})./\1@/r=~s/(.{$a})./\1"/r=~s/(.{16})/\1\n/grใกล้เข้ามาแล้วในตอนแรก แต่ perl-fu ของฉันก็เต็มไปด้วยสนิม ฉันอาจพลาดการเปลี่ยนแปลงสถานะที่นั่น
Yakk

2

C #, 256 248 234 227 226 225 ไบต์

ใช้ลูกศร NumPad โดยเปิดใช้ NumLock เพื่อย้าย

เยื้องและแสดงความคิดเห็นเพื่อความชัดเจน:

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
ฉันคิดว่า C # ints เริ่มต้นเป็นศูนย์โดยปริยาย นอกจากนี้ (ไม่สามารถตรวจสอบได้ในขณะนี้) หากการคัดเลือกนักแสดงไม่ใช่ปัญหาคุณสามารถแปลงตัวอักษรเป็น ints หรืออย่างน้อย 'a' ถึง 97 (ฉันคิดว่า) แม้ว่าคนอื่น ๆ จะเป็นตัวเลขสามหลัก

เฉพาะคลาสของฟิลด์เท่านั้นที่จะถูกเตรียมใช้งานโดยค่าเริ่มต้นและต้องมีการประกาศให้คงที่ในกรณีนี้ ตัวแปรวิธีการจะต้องเริ่มต้นก่อนใช้งานครั้งแรก ที่ใช้ตัวละครน้อยลง: 4 vs 7
Hand-E-Food

ขอบคุณ @tolos สำหรับเคล็ดลับในการส่งถ่านไปยัง int! ยังดีกว่าถ้าฉันใช้ ConsoleKey enum cast เป็น int ฉันสามารถใช้ค่า 2 หลักได้
Hand-E-Food

ในทางเทคนิคแล้วMainไม่จำเป็นต้องเรียกวิธีMainนี้ดังนั้นคุณสามารถกำจัดอักขระสามตัวออกไปได้
Luaan

@ Luaan ฉันคิดว่าคุณเข้าใจผิด เอกสาร C #: msdn.microsoft.com/en-us/library/acy3edy3.aspx
Hand-E-Food

2

Html + JavaScript (ES6) อาจมีคะแนน 217

looong เกินไป แต่สามารถเล่นออนไลน์ในตัวอย่างด้านล่าง

บรรทัด 6 (T.value ... ) ใช้สำหรับเอาท์พุทและไม่นับ (แต่สำหรับความเรียบง่ายฉันนับ textarea แท็กเปิดและปิดแม้ว่ามันจะเอาท์พุทด้วย)

สำหรับการสุ่ม: เครื่องรางมักจะอยู่ในครึ่งขวาของกริดและผู้เล่นจะเริ่มต้นในครึ่งซ้ายเสมอ

คลิกที่ textArea (หลังจากขยายใหญ่ขึ้น) เพื่อเริ่มและเริ่มเกมใหม่

<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 เท่านั้น)

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 (ทดสอบใน 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 ไบต์

ตัวอย่างการทำงานออนไลน์

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

ต่อไปนี้เป็นโปรแกรม (ช่องว่างรวมสำหรับการอ่าน) ที่สมบูรณ์โดยใช้ฟังก์ชั่นเกม:

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

คุณสามารถเล่นในตัวอย่างด้านล่าง! ตัวเลขด้านซ้ายเป็นเพียงคอนโซล (อย่างน้อยหนึ่ง chrome) ไม่รวมแถว

ในการเรียกใช้รหัส:

  1. กดปุ่ม "เรียกใช้ข้อมูลโค้ด"
  2. กด ctrl-shift-j เพื่อเปิดคอนโซล
  3. คลิกในส่วนผลลัพธ์
  4. ใช้ปุ่มลูกศรและเล่น

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

ยกเลิกแข็งแรงเล่นกอล์ฟ:

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

แก้ไข 1:อ่านกฎอย่างละเอียดและเขียนรหัสของฉันอีกครั้ง

  • ตอนนี้ค่า amulet ของ amulet ถูกสุ่ม
  • ผู้เล่นไม่สามารถหลบหนีออกจากห้องได้อีกต่อไป
  • ฉันไม่นับตัวอักษรในฟังก์ชั่นการวาดหรือการเรียกใช้อีกต่อไป

1

SpecBAS - 428 402 (ไม่รวมการพิมพ์466 425 เมื่อนับ)

ใช้ Q / A / O / P เพื่อเลื่อนขึ้น / ลง / ซ้าย / ขวาตามลำดับ

บรรทัดที่จะพิมพ์ดันเจี้ยนที่บรรทัดที่ 1 เป็นบรรทัดเดียวที่สามารถละเว้นได้

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

การอ้างอิงถึง # 34 เป็นเพียงวิธีสั้น ๆ ในการวาง CHR $ (34) ในรหัส

ขอบคุณ @Thomas Kwa ฉันไม่ได้สังเกตว่าตำแหน่งผู้เล่นเริ่มต้นที่สุ่มนั้นเป็นตัวเลือก ใช้คำสั่ง IF แยกต่างหากเพื่อกำจัดอักขระบางตัว


คุณอาจบันทึกอักขระบางตัวได้โดยการสุ่มให้น้อยลง2 LET px=1: LET py=1: LET ax=2: LET ay=INT(RND*5)และใช้IF instead of ELSE IFเช่นกัน
lirtosiast

1

อีก C #, 221 171 170

นี่เป็นอีกวิธีใน C # ที่มีทั้งตำแหน่งสุ่ม ต้องการแสดงสิ่งนี้แม้ว่าส่วนนี้จะยาวกว่าโซลูชันของ Hand-E-Food 7 ไบต์
คำตอบของ Hand-E-Food จะสั้นลงทันทีที่ใช้ Console.Read ()
ข้อเสียของ Consol.Read คือการกด Enter ที่จำเป็นจะทำให้ฟิลด์พิมพ์อีก 2 ครั้ง
แต่ฉันไม่คิดว่ามีความต้องการที่จะพิมพ์เพียงแค่อินพุต (ของจริง)

การนำทางทำได้โดย 8426 เช่นเดียวกับใน 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;
}
}
}


แก้ไข: (เพิ่มโซลูชันใหม่และย้าย PrinterClass ไปที่จุดสิ้นสุด)
Edit2: (เปลี่ยน 14 เป็น 15 และบันทึก byte โดยเริ่มจากด้านล่างขวา)

ปรับเทคนิคของ Mauris ให้เป็นละลายได้ถึง 171 bytes ใน C # (แน่นอนว่าตอนนี้ไม่มีทั้งตำแหน่งสุ่ม):

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

Printer Class นั้นเกือบจะเหมือนกันเพียงแค่มีการพิมพ์มากเกินไป ...

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

ทับทิม, 185

นี่คือตัวอย่างทับทิมด้วย
ฉันใหม่กับรูบี้บางทีอาจมีบางคนรู้วิธีที่จะทำให้ดีขึ้น :)

ฉันนับ lineFeeds เป็น 1 เนื่องจากโปรแกรมจะขัดข้องเป็นอย่างอื่น ...

การนำทางเสร็จสิ้นโดย 8462 คุณต้องส่งอินพุตทุกครั้งด้วยการป้อน

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 ไบต์

ตามกฎของการท้าทายShowโปรแกรมย่อยจะไม่รวมอยู่ในจำนวนไบต์และไม่มีการShow p, q, a, bเรียก (ด้วยการขึ้นบรรทัดใหม่ต่อไปนี้)

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

ที่จะย้ายเข้าจำนวนและกด Enter: 1ไปทางซ้าย, 2ขึ้นไป3ที่จะไปขวาและ4เพื่อลง

รหัสนี้จะไม่แสดงสถานะของเกมในตอนท้ายเมื่อผู้เล่นพบเครื่องราง หากต้องการให้เพิ่มอีกShow p, q, a, bหลังIFคำสั่ง

คำอธิบาย

Let a, bแทนพิกัดของพระเครื่องและp,qพิกัดของผู้เล่น ผู้เล่นเริ่มต้นที่ (0, 0) และเครื่องรางเริ่มต้นที่แถว 0 โดยมีคอลัมน์ระหว่าง 1 ถึง 9 รวมอยู่ด้วยโดยยึดตามตัวเลขหลัก 1 ของเวลาปัจจุบัน

ส่วนที่เหลือเป็นเพียงคณิตศาสตร์ที่มีเงื่อนไข สิ่งสำคัญที่ต้องจำไว้คือเงื่อนไขในการคืน QBasic 0สำหรับเท็จ-1สำหรับจริง ลองดูที่คำสั่งการอัพเดตแถวผู้เล่น:

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

ถ้าm=2เราต้องการที่จะย้ายขึ้นโดยการลบ 1 จากตราบเท่าที่p p>0ในทำนองเดียวกันถ้าm=4เราต้องการที่จะย้ายลงโดยการเพิ่ม 1 ถึงตราบใดที่p p<4เราสามารถรับพฤติกรรมที่ต้องการได้โดยการคูณ หากปัจจัยทั้งสอง-1ผลิตภัณฑ์ของพวกเขาจะซึ่งเราสามารถลบออกจากหรือเพิ่ม1 pหากเงื่อนไขเป็นอย่างใดอย่างหนึ่ง0ผลิตภัณฑ์จะเป็น0ไม่มีผลใด ๆ

ในทำนองเดียวกันเงื่อนไขในการพิจารณาว่าผู้เล่นพบเครื่องรางหรือไม่:

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

หากเงื่อนไขอย่างใดอย่างหนึ่งเป็นจริงผลรวมของพวกเขาจะไม่ใช่ศูนย์ (อย่างใดอย่างหนึ่ง-1หรือ-2) และทำให้เป็นจริงและโปรแกรมกลับไปที่บรรทัดที่ 1 เมื่อpเท่ากับaและqเท่ากับbทั้งสองเงื่อนไขจะเป็น0ดังนั้นผลรวมของพวกเขาจะเป็น0และ ในตอนท้ายของโปรแกรม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.