Buru Wumpus

39

Ketika saya masih kecil, anak-anak akan berkeliaran di toko-toko komputer dan bermain Hunt the Wumpus sampai staf mengusir kami. Itu adalah permainan sederhana, dapat diprogram di komputer rumah pada pertengahan tahun 1970-an, mesin sangat sederhana sehingga alih-alih mikroprosesor ukuran anak ayam, saya pikir beberapa dari mereka mungkin memiliki anak ayam nyata di sana.

Mari kita membangkitkan jaman dulu dengan mereproduksi game di perangkat keras modern.

  1. Pemain mulai di ruang acak di peta icosahedral (dengan demikian total ada 20 kamar, saling terhubung seperti wajah icosahedron, dan setiap kamar memiliki tiga pintu keluar yang persis).

  2. Wumpus dimulai di ruang berbeda yang dipilih secara acak. Wumpus bau, dan baunya dapat dideteksi di salah satu dari tiga kamar yang berdekatan dengan lokasinya, meskipun arah bau tidak mungkin bagi pemain untuk menentukan. Gim ini hanya melaporkan "Anda mencium wumpus."

  3. Pemain membawa busur dan panah yang tak terbatas, yang dapat dia tembak kapan saja ke ruangan di depannya. Jika wumpus ada di ruangan itu, ia mati dan pemain menang. Jika wumpus tidak ada di ruangan itu, ia terkejut dan bergerak secara acak ke salah satu dari tiga kamar yang terhubung ke lokasi saat ini.

  4. Satu, kamar yang dipilih secara acak (dijamin bukan ruangan tempat pemain memulai) berisi jurang tanpa dasar. Jika pemain berada di ruangan yang bersebelahan dengan pit, ia merasakan angin sepoi-sepoi, tetapi tidak tahu dari mana pintu angin itu berasal. Jika dia masuk ke ruangan dengan lubang, dia mati dan wumpus menang. Wumpus tidak terpengaruh oleh lubang.

  5. Jika pemain masuk ke kamar wumpus, atau jika wumpus masuk ke kamar pemain, wumpus menang.

  6. Pemain menentukan arah yang dihadapinya dengan angka (1 = kanan, 2 = kiri, 3 = belakang), dan kemudian aksi (4 = menembakkan panah, 5 = berjalan ke arah yang ditentukan).

  7. Demi mencetak gol, setiap senar permainan ("Anda merasakan angin sepoi-sepoi," "Anda mencium wumpus," "Panah Anda tidak mengenai apa pun", dll.) Dapat dianggap satu byte. Tidak menyalahgunakan ini untuk menyembunyikan kode game dalam teks; ini hanya untuk berinteraksi dengan pemain.

  8. Kurangi 10% dari jumlah byte Anda untuk mengimplementasikan megabats, yang dimulai di ruang acak yang berbeda dari pemain (meskipun mereka dapat berbagi kamar dengan wumpus dan / atau lubang). Jika pemain masuk ke ruangan dengan kelelawar, kelelawar akan membawa pemain ke ruangan lain yang dipilih secara acak (dijamin tidak akan menjadi ruangan dengan lubang atau wumpus di dalamnya), sebelum terbang ke lokasi acak baru mereka sendiri. Di tiga kamar yang bersebelahan dengan kelelawar, mereka dapat terdengar mencicit, tetapi pemain tidak diberi informasi tentang dari kamar mana suara itu berasal.

  9. Kurangi 35% dari jumlah byte Anda untuk mengimplementasikan antarmuka grafis yang menunjukkan peta icosahedral dan semacam indikasi informasi yang sejauh ini dimiliki pemain tentang lokasi lubang, wumpus, dan kelelawar (jika ada), relatif terhadap pemain. Jelas, jika wumpus bergerak atau pemain digerakkan oleh kelelawar, peta harus diatur ulang.

  10. Hitungan byte terendah, jika disesuaikan, menang.

Kode sumber BASIC untuk versi gim (tidak harus sesuai dengan aturan di atas dan, dalam hal apa pun, sama sekali tidak diklik) dapat ditemukan di situs web ini dan mungkin yang lain.

Michael Stern
sumber
Beberapa klarifikasi: 3. jika wumpus tidak ada di ruangan itu, ia terkejut dan bergerak ke salah satu dari TIGA kamar .. jadi jika Anda menembakkan panah dan meleset, wumpus itu mungkin datang dan membunuh Anda, bukan? Dan wumpus hanya akan bergerak jika dikejutkan, jika tidak, ia hanya akan tetap menempel? 6. Saya mengerti bahwa heading pemain ditentukan oleh ruangan asalnya. Jadi jika dia datang dari selatan, pilihannya adalah 1.northeast 2.northwest 3.south dan jika dia datang dari utara itu akan menjadi kebalikannya. Juga aturan Anda tampak lebih sederhana / golf daripada program referensi (yang belum saya selidiki lebih detail). Apakah saya benar?
Level River St
Argh! Saya tidak dapat menemukan setiap gambar grafik ganda dari mana saja icosahedron di internet.
Jack M
1
@steveverrill Ya, jika Anda menakut-nakuti, itu mungkin datang dan membunuh Anda. Jika Anda tidak takut, itu tidak bergerak. Ada banyak variasi dalam permainan; banyak versi memungkinkan panah untuk berputar dan membunuh Anda, misalnya. Saya sudah mengupas itu.
Michael Stern
3
@JackM peta wajah icosahedron identik dengan peta simpul dodecahedron, dan grafik itu mudah ditemukan. Coba misalnya wolframalpha.com/input/?i=DodecahedralGraph+edgerules atau perintah Mathematica yang setara GraphData ["DodecahedralGraph", "EdgeRules"]. Apa pun cara Anda mendapatkan {1 -> 14, 1 -> 15, 1 -> 16, 2 -> 5, 2 -> 6, 2 -> 13, 3 -> 7, 3 -> 14, 3 -> 19, 4 -> 8, 4 -> 15, 4 -> 20, 5 -> 11, 5 -> 19, 6 -> 12, 6 -> 20, 7 -> 11, 7 -> 16, 8 -> 12, 8 -> 16, 9 -> 10, 9 -> 14, 9 -> 17, 10 -> 15, 10 -> 18, 11 -> 12, 13 -> 17, 13 -> 18, 17 -> 19, 18 -> 20}
Michael Stern
2
@ Jackack Tidak, "kembali" menyiratkan berbalik dan berjalan kembali seperti Anda datang. Jika Anda menekan "kembali" dua kali, Anda berakhir di tempat Anda mulai. Tidak perlu menyimpan status game sebelumnya.
Michael Stern

Jawaban:

21

GolfScript, 163

:n;:`"You shot the wumpus.
""The wumpus ate you.
""The pit swallowed you.
"{19:|rand}2*0|{[:,~,4%"ftvh"=.,+,@-]{20%}%}:^{;.^.+.3$?>"You feel a breeze.
"1$6"You smell a wumpus.
"4$8{$?-1>*p}2*'"#{'|):|';`head -1`}"'++~{3%}/={=3$=|{"Your shot missed.
"p@^3rand=@@}if}{=@;}if.[|4$6$]?.)!}do])=

Skor diperoleh dengan mengambil hitungan byte (290), menambahkan jumlah string yang digunakan untuk interaksi dengan pengguna (6) dan mengurangi panjang gabungan dari string tersebut (133). Umpan baris adalah bagian dari string dan berkontribusi pada jumlah byte.

Tonggak sejarah

  1. Porting jawaban professorfish ini dari Bash ke GolfScript. Nilai: 269

  2. Bertindak atas saran Peter Taylor dalam komentar. Nilai: 250

  3. Peter Taylor refactored seluruh kode saya dan membantu saya untuk mengompres tabel pencarian. Nilai: 202

  4. Mengganti tabel pencarian kamar yang berdekatan dengan pendekatan matematika. Nilai: 182

  5. Input, output, dan fungsi yang mendukung kembali pendekatan matematika. Nilai: 163

Ucapan terima kasih yang besar ditujukan kepada Peter Taylor untuk semua bantuannya.

Bagaimana itu bekerja

Ke-20 kamar diwakili sebagai simpul dodecahedron, yang telah diberi nomor dari 0 hingga 19 dengan cara sebagai berikut:

Grafik Dodecahedral

Untuk menemukan kamar yang berdekatan dengan kamar N dan memesannya dengan cara searah jarum jam, kita harus mempertimbangkan empat kasus:

  • Jika N ≡ 0 mod 4 (verteks biru), ruang yang berdekatan adalah 19 - N , N + 2 mod 20 dan N - 2 mod 20 .

  • Jika N ≡ 1 mod 4 (titik hijau), ruang yang berdekatan adalah 19 - N , N - 4 mod 20 dan N + 4 mod 20 .

  • Jika N ≡ 2 mod 4 (titik kuning), ruang yang berdekatan adalah 19 - N , N - 2 mod 20 dan N + 2 mod 20 .

  • Jika N ≡ 3 mod 4 (red vertex), ruang yang berdekatan adalah, 19 - N , N + 4 mod 20 dan N - 4 mod 20 .

# The function “p” is implemented as “{`print n print}”. By storing an empty string in 
# “n” and nullifying “`”, “p” becomes an alias for “print”.

:n;:`

# Push the messages corresponding to the three possible outcomes of the game.

"You shot the wumpus.\n""The wumpus ate you.\n""The pit swallowed you.\n"

# Place the wumpus and the pit in randomly selected rooms different from room 19; place 
# the player in room 19, with his back to room 0.

{19:|rand}2*0|

# Function “^” takes a single number as its argument and returns an array of all the
# adjacent rooms to the room that number corresponds to.

{

  [

    :,~       # Store the room number in “,” and negate it ( ~N ≡ 19 - N mod 20 )

    ,4%       # Push the room number modulus 4.

    "ftvh"=   # If it is equal to 0|1|2|3, push 102|116|118|104 ≡ 2|-4|-2|4 mod 20.

    .,+,@-    # Determine the room number plus and minus the integer from above.

  ]{20%}%     # Take all three room numbers modulus 20.

 }:^

{             # STACK: Strings Pit Wumpus Previous Current Function|Index

  ;           # STACK: Strings Pit Wumpus Previous Current

  # Find the adjacent rooms to the current room, duplicate them and remove the rooms 
  # before the first occurrence of the previous room. Since the rooms are ordered in
  # clockwise fashion, the array of adjacent rooms will begin with the rooms 
  # corresponding to the following directions: “Back Left Right”

  .^.+.3$?>   # STACK: Strings Pit Wumpus Previous Current Adjacent

  # Push two more messages and their respective triggers.

  "You feel a breeze.\n"1$6"You smell a wumpus.\n"4$8

  # STACK: ... Pit Wumpus Previous Current Adjacent String Adjacent 6 String Adjacent 8

  # Do the following twice: Duplicate the nth stack element and check if it's present in 
  # the array of adjacent rooms. If so, print the string below it.

  {$?-1>*p}2*

  # Read one line (direction, action, LF) from STDIN. The counter “|” is needed so the 
  # result won't get cached.

  '"#{'|):|';`head -1`}"'++~

  {3%}/       # Replace 1|2|3|4|5|LF with their character codes modulus 3 (1|2|0|1|2|1).

  ={          # If the player shoots an arrow:

    =3$=      # Determine the specified room and check if it corresponds to the wumpus.

      |       # If it does, push and invalid room number ( | > 19 ).

      # If it does not, say so and move the wumpus to a randomly selected adjacent room.

      {"Your shot missed."p@^3rand=@@}

    if

  }{           # If the player moves:

    =@;        # Place him into the selected room.

  }if

  # STACK: Pit Wumpus Previous Current Invalid?

  # Determine if the player's current room number is either invalid, the wumpus's room
  # number or the pit's room number (first match).

  .[|4$6$]?

  # If there is no match, the index is -1 and incrementing and negating it yields “true”.

  # STACK: Strings Pit Wumpus Precious Current Invalid? Index Boolean

# Repeat loop is the boolean is falsy. If repeated, the first instruction of the loop 
# will pop the index.

}do      

# Consolidate the entire stack into an array. And pop its last element: the index.
# Replace the array with the element corresponding to that index.

])=

# GolfScript will execute “print n print”.
Dennis
sumber
1
Anda dapat menyimpan 1 Qdengan 19rand 97+; 2 di @dengan 97%3*&>..., lebih lanjut 1 oleh inlining Qsebagai {19rand 97+}2*:,\:H, beberapa dengan mengganti |dengan *, yang sering cara terbaik untuk melakukan if. Btidak ada gunanya, dan saya pikir beberapa variabel lagi bisa dihilangkan dengan menggunakan stack.
Peter Taylor
1
Lupa menyebutkan trik lain yang sering: konversi basis untuk tabel pencarian. Anda dapat mengganti 62 karakter untuk daftar adjacency dengan string 33-char diikuti oleh 256base 20base(dan mungkin juga menghilangkan beberapa +/- 97). Satu-satunya downside adalah bahwa itu akan memerlukan karakter yang tidak dapat dicetak.
Peter Taylor
1
Saya telah menyimpan 13 lebih lanjut dengan refactoring untuk menjadi lebih idiomatik GS (terutama menggunakan stack daripada variabel); dan ada 10 tambahan dengan biaya membuat output kurang cantik. Itu terlepas dari kompresi tabel pencarian yang disebutkan dalam komentar saya sebelumnya.
Peter Taylor
1
Tidak sama sekali, saya menikmatinya. Saya hanya kecewa bahwa pendekatan tabel pencarian jauh lebih baik daripada yang lebih matematis yang ingin saya gunakan. BTW Saya pikir versi Anda saat ini memiliki bug kecil, karena jika Anda menembakkan panah, meleset, dan mengejutkan wumpus ke kamar Anda maka itu hanya menghasilkan You were killed by the wumpustanpa menyebutkan panah yang hilang. Itu sebabnya saya menambahkan dalam versi yang tidak cantik.
Peter Taylor
1
2*2+=>)2*
Peter Taylor
15

REV0 C ++ (Visual Studio pada Windows) 405

#include"stdafx.h"
#include<stdlib.h>
#include<time.h>
int main(){srand(time(NULL));char i,h=rand()%19,w=rand()%19,p=19,d=0,q,e,m[]="e@LwQMQOSOLT";while(p-h&&p-w){for(i=3;i--;){q=(p+m[p%4*3+i])%20;if(q==w)puts("you smell a wumpus");if(q==h)puts("you feel a breeze");}scanf_s("%d",&i);e=(d+i/10)*m[p%4]%3;q=(p+m[p%4*3+e])%20;if(i%5){if(q==w){puts("YOU KILLED THE WUMPUS!");h=p;}else{puts("arrow missed");w=(w+m[w%4*3+rand()%3])%20;}}else{p=q;d=e;if(p==h)puts("YOU FELL IN A HOLE!");}if(p==w)puts("THE WUMPUS GOT YOU!");}}

Di bawah ini adalah permainan, menunjukkan bahwa (asalkan Anda tidak memulai tepat di sebelah bahaya) dengan permainan yang benar Anda selalu bisa menang. Pemain merasa mudah, berbalik dan melakukan putaran berlawanan arah jarum jam yang lengkap. Saat ia membutuhkan tepat 5 gerakan untuk merasakan angin sepoi-sepoi lagi, ia tahu lubang di sebelah kanannya, dan berada sejauh mungkin. Demikian pula, ketika dia mencium wumpus, tidak tahu apakah itu benar atau kiri, dia berbalik dan melakukan putaran searah jarum jam. Dibutuhkan 5 langkah untuk mencium wumpus lagi, jadi dia tahu itu ke kiri dan menembak dengan pasti.

Jika dia memutar ke arah lain, dia akan menemukan wumpus lebih cepat dan tahu itu ke arah yang sama dengan yang dia putar.

masukkan deskripsi gambar di sini

REV1 C (GCC di Cygwin), 431-35% bonus = 280,15

#define u(t,s,c) if(t){puts(s);c;}
i,d,e,a,b;main(){srand(time(0));char q,p=19,h=rand()%p,w=rand()%p,*m="e@LwQMQOSOLT-\\/\n \v ";  
while(p-h&&p-w){
  for(i=3;i--;){q=(p+m[p%4*3+i])%20;u(q==w,"you smell a wumpus",a|=2<<p)u(q==h,"you feel a breeze",b|=1<<p)}
  for(i=20;i--;)printf("%c%c",i==p?m[d+12]:48+(a>>i&2)+(b>>i&1),m[i%4+15]);
  scanf("%d",&i);e=(d+i/10)*m[p%4]%3;q=(p+m[p%4*3+e])%20;
  if(i%5){u(q-w,"arrow missed",w=(w+m[w%4*3+rand()%3])%20;a=0)else u(1,"YOU KILLED THE WUMPUS!",h=p)}
  else{p=q;d=e;u(p==h,"YOU FELL IN A HOLE!",)}
  u(p==w,"THE WUMPUS GOT YOU!",)}}

Baris baru ditambahkan untuk kejelasan. Perubahan dari Rev 0 adalah sebagai berikut:

Terima kasih banyak kepada @Dennis karena merekomendasikan kompiler GCC pada emulator Cygwin Linux untuk Windows. Kompiler ini tidak memerlukan includes dalam program rev 0, dan memungkinkan defaultint tipe untuk variabel dan main.Ini adalah tip golf yang mengubah hidup!

Selain itu berjalan di Linux berarti itu \f menyebabkan kursor bergerak ke bawah tanpa melakukan carriage return (tidak seperti di Windows di mana ia hanya menghasilkan simbol yang dapat dicetak.) Ini telah memungkinkan pemendekan pernyataan printf yang mencetak papan.

Beberapa tips tambahan dari Dennis di komentar, dan salah satu dari saya: perubahan kondisi saat memeriksa apakah panah mengenai wumpus: if(q==w) > if(q-w)(..else .. dibalik)

Penambahan tampilan grafis menunjukkan informasi yang pemain ketahui tentang di mana wumpus dilebur / angin sepoi-sepoi terasa untuk mengklaim bonus 35%. (Saya menghapus versi debug yang lama ini yang menunjukkan posisi persis wumpus dan lubang. Hal ini dapat dilihat pada riwayat edit.)

REV2 C (GCC di Cygwin), bonus 389-35% = 252,85

#define Q(N) (N+"QTLOQMQOSOLT"[N%4*3+e])%20
#define P printf(
i,d,e,a,b;main(){int p=19,q=srand(&p),h=rand()%p,w=rand()%p;
while(p-h&&p-w){
  for(e=3;e--;){q=Q(p);q-w||P"You smell a wumpus\n",a|=2<<p);q-h||P"You feel a breeze\n",b|=1<<p);}
  for(i=20;i--;)P"%c%c",i-p?48+(a>>i&2)+(b>>i&1):"-\\/"[d],"\n \v "[i%4]);
  scanf("%d",&i);e=(d+i/9)*"edde"[p%4]%3;q=Q(p);
  if(i%5){e=rand()%3;w=q-w?P"Your arrow didn't hit anything\n",a=0)&Q(w):(p=20);}
  else p=q,d=e;
}
P p-20?p-w?"YOU FELL IN A HOLE!\n":"THE WUMPUS GOT YOU!\n":"YOU KILLED THE WUMPUS!\n");}

Sekali lagi terima kasih kepada Dennis untuk refactoring kode saya:

Konstanta Char m[]diganti dengan literal (saya tidak tahu Anda bisa mengindeks literal.)

Pembibitan angka acak dengan variabel tumpukan (ketergantungan sistem, beberapa sistem mengacak alokasi memori sebagai ukuran keamanan.)

Makro dengan putsdiganti dengan makro dengan printfdan kode tambahan yang harus dijalankan ketika pesan yang ditampilkan ditempatkan di dalam printfargumen (keuntungan diambil dari wajah bahwa printf tidak mencetak beberapa argumen terakhir jika tidak ada cukup penentu format dalam string format.) ifdigantikan oleh||

Perhitungan posisi baru pemain / wumpus ditempatkan di dalam makro baru.

Menang / kalah pesan yang ditempatkan di luar whilelingkaran. ifdiganti oleh operator kondisional.

Gunakan operator bersyarat untuk menembakkan panah. Jika pemain absen, ini membutuhkan baik mencetak pesan dan menyesuaikan posisi wumpus. Dennis menawarkan beberapa cara untuk menggabungkan printfdan menghitung posisi wumpus menjadi satu ekspresi, tetapi saya telah menggunakan salah satu dari cara saya sendiri. printfmengembalikan jumlah karakter yang dicetak, yang Your arrow didn't hit anything\nadalah 31 (11111 biner.) Jadi 31&Q(w)==Q(w),.

Kontribusi saya yang lain untuk pengeditan ini adalah menghilangkan beberapa tanda kurung yang tidak perlu.

Keluaran

Di sini pemain telah menemukan di mana Wumpus berada, tetapi memilih untuk melakukan penjelajahan menyeluruh untuk mencari tahu persis di mana lubang itu juga. Tidak seperti versi debug lama saya yang menunjukkan di mana wumpus dan lubang berada di sepanjang permainan, ini hanya menunjukkan kamar di mana pemain telah mengunjungi dan merasakan angin sepoi-sepoi (1) mencium wumpus (2) atau keduanya (3). (Jika pemain menembak panah dan meleset, variabel yang aberisi info posisi wumpus diatur ulang.)

masukkan deskripsi gambar di sini

REPRESENTASI ICOSAHEDRON

Catatan: bagian ini didasarkan pada rev 1

Fitur bintang saya! Tidak ada grafik dalam kode saya. Untuk menjelaskan cara kerjanya, lihat peta dunia di bawah ini. Setiap titik pada icosahedron dapat diwakili oleh garis lintang 0-3 dan garis bujur 0-4 (atau satu angka long*4+lat,.) Garis bujur yang ditandai pada peta hanya melewati wajah-wajah dengan garis bujur nol, dan garis garis lintang melewati pusat wajah dengan garis lintang nol.

Pemain dapat berorientasi pada 3 kemungkinan sumbu, diwakili oleh simbol-simbol sebagai berikut: utara-selatan --timur laut-barat daya \-tenggara /. Di setiap ruangan tertentu ia memiliki tepat satu pintu keluar pada masing-masing kapak yang tersedia untuknya. Pada layar yang ditampilkan, pemain membuat putaran searah jarum jam lengkap. Secara umum mudah untuk mengidentifikasi dari pemain yang menandai dari mana ia berasal, dan oleh karena itu ia boleh pergi ke mana.

Satu kasus yang agak sulit bagi mata yang belum diinisiasi adalah yang keempat. Ketika Anda melihat kemiringan pada salah satu baris kutub ini, pemain telah datang dari sel kutub terdekat ujung luar kemiringan dan umumnya menghadap ke arah khatulistiwa. Dengan demikian pemain menghadap tenggara dan opsinya adalah: 15 (SELATAN, sel ke kanan) 25 (northEAST, sel di atas) atau 35 (northWEST, sel di bawah.)

Jadi, pada dasarnya saya memetakan icosahedron ke kisi 5x4, dengan sel-sel bernomor 19 hingga 0 dalam urutan dicetak. Langkah ini dilakukan dengan menambah atau mengurangi dari posisi saat ini, tergantung pada garis lintang dan arah pemain, per tabel di bawah ini.

Jika pemain keluar dari bawah (barat) papan, ia kembali ke sisi atas (timur) dan sebaliknya, sehingga posisinya diambil modulo 20. Secara umum gerakan dikodekan ke dalam m [] dengan menambahkan ascii 80 ( P) ke nilai mentah memberikan karakter yang ditunjukkan di bawah ini, tetapi prinsip kelipatan 20 dapat ditambahkan tanpa mempengaruhi operasi.

Table of addition values for moves

Direction Symbol Latitude 0  1  2  3     Latitude 0 1 2 3

0, N-S      -             1 -1  1 -1              Q O Q O  
1, NE-SW    \            -4  1 -1  4              L Q O T
2, NW-SE    /             4 -3  3 -4              T M S L

Input pemain (dibagi 10 untuk menghapus digit kedua) ditambahkan ke arah saat ini dan diambil modulo 3 untuk mendapatkan arah baru. Ini berfungsi dengan baik di sebagian besar kasus. Namun ada masalah ketika dia berada di ruang kutub dan bergerak menuju kutub. Ini akan menjadi jelas ketika melipat peta di bawah ini bahwa jika dia meninggalkan ruangan menghadap "timur laut" dia akan memasuki alun-alun baru yang menghadap "tenggara" sehingga koreksi harus dilakukan. Ini dilakukan di baris e=(d+i/10)*m[p%4]%3;dengan perkalian dengan m[p%4]. Empat nilai pertama m [] dipilih sedemikian rupa sehingga, selain fungsinya di atas, mereka juga memiliki karakteristik m[1]%3==m[2]%3==1dan m[0]%3==m[3]%3==2. Ini meninggalkan arah sendirian untuk kamar khatulistiwa dan menerapkan koreksi yang diperlukan untuk kamar kutub.

Waktu logis untuk melakukan koreksi adalah setelah pindah. Namun untuk menyimpan karakter itu dilakukan sebelum pindah. Karenanya nilai-nilai tertentu dalam m [] harus ditransformasikan. Jadi 2 karakter terakhir LTbukan TLper tabel di atas misalnya.

masukkan deskripsi gambar di sini

KODE TIDAK TERGERAK

ini adalah kode rev 1, yang kurang dikaburkan daripada rev 2.

Ini akan berjalan di GCC / Linux. Saya telah memasukkan dalam komentar kode tambahan yang diperlukan untuk membuatnya berjalan di Visual studio / Windows. Itu perbedaan besar!

//Runs on gcc/linux. For visual studio / windows, change printf(...) 
//to printf(" %c%c%c",9*(i%4==1),i==p?m[d+12]:48+(a>>i&2)+(b>>i&1),10*!(i%2)) and uncomment the following lines
//#include"stdafx.h"
//#include<stdlib.h>
//#include<time.h>
//#pragma warning(once:996;once:430) //allow the use of scanf instead of scanf_s, allow default type=int. 
//Though rather than using the pragma, it is shorter to follow compiler recommendation and use scanf_s and int.

#define u(t,s,c) if(t){puts(s);c;}  //if(test){puts(string);additional code;}

i,     //player input, loop counter
d,e,   //current and proposed direction
a,b;   //bit flags for where wumpus smelt / breeze felt

main(){
    srand(time(0));
    char q,p=19,h=rand()%p,w=rand()%p,  //Initialise player, hole and wumpus. q stores proposed player position.
    *m="e@LwQMQOSOLT-\\/\n \f ";        //Chars 0-11: movetable. Chars 12-14:symbol for player. Chars 15-18: graphics format.   

    while(p-h&&p-w){

        // Print warnings
        for(i=3;i--;){q=(p+m[p%4*3+i])%20;u(q==w,"you smell a wumpus",a|=2<<p)u(q==h,"you feel a breeze",b|=1<<p)}

        // graphic display 
        for(i=20;i--;)printf("%c%c",i==p?m[d+12]:48+(a>>i&2)+(b>>i&1),m[i%4+15]);

        // Get player input and work out direction and room 
        scanf("%d",&i);
        e=(d+i/10)*m[p%4]%3;
        q=(p+m[p%4*3+e])%20;

        // i%5 is false if player inputs 5 (move player) otherwise true (shoot arrow) 
        if(i%5)
        {u(q-w,"arrow missed",w=(w+m[w%4*3+rand()%3])%20;a=0)else u(1,"YOU KILLED THE WUMPUS!",h=p)}
        else{p=q;d=e;u(p==h,"YOU FELL IN A HOLE!",)}
        u(p==w,"THE WUMPUS GOT YOU!",)
    }

}

ISU DAN KURIOISITAS

Saya telah mengambil keuntungan dari poin yang disebutkan oleh @professorfish, jika wumpus dan pit mulai di tempat acak, tidak ada kebutuhan bagi pemain untuk memulai di tempat acak. Pemain selalu mulai di kamar 19 menghadap ke utara.

Saya mengerti bahwa ketika wumpus "tidak terpengaruh oleh lubang", wumpus dapat mulai masuk, atau memasuki ruangan di mana lubang itu berada. Secara umum ini menyederhanakan hal-hal kecuali satu poin. Saya tidak memiliki variabel khusus untuk menunjukkan bahwa permainan telah berakhir; itu berakhir ketika pemain bertepatan dengan wumpus atau lubang. Jadi, ketika pemain menang, saya menampilkan pesan yang menang tetapi memindahkan lubang ke pemain untuk keluar dari lingkaran! Saya tidak bisa menempatkan pemain di lubang karena wumpus mungkin ada di sana dan saya akan mendapatkan pesan tentang wumpus yang tidak saya inginkan.

Program rev0 bekerja dengan sempurna di studio visual, tetapi IDE mengatakan "tumpukan rusak di sekitar variabel i" saat keluar. Hal ini karena scanf sedang mencoba untuk menempatkan intke dalam char.Dennis melaporkan perilaku yang salah pada mesin Linux nya karena hal ini. Pokoknya itu diperbaiki dengan menggunakan tipe yang benar di rev 1.

Garis untuk menampilkan papan di rev 0 adalah canggung dan muncul sedikit berbeda pada platform lain. Di printf(" %c%c%c")tengah% c adalah karakter yang dapat dicetak ditampilkan. % C terakhir adalah ASCII 0 atau ASCII 10 (\ n, baris baru dengan carriage return di Windows.) Tampaknya tidak ada karakter di Windows yang bekerja di konsol, yang akan turun baris tanpa memberikan carriage return. Jika ada, saya tidak memerlukan tab c% pertama (ASCII 0, atau ASCII 9 sebelum karakter lintang 1. Tab terkenal tidak terdefinisi dalam perilakunya.) Ruang terdepan meningkatkan pemformatan (menempatkan karakter 3 & 2 lebih dekat dengan karakter lintang 1 lebih dekat dengan karakter 1 .) Rev 1 memiliki revisi garis ini yang menggunakan karakter formfeed dan karenanya tidak memerlukan karakter format pada awal printf. Ini membuatnya lebih pendek, tetapi \ f tidak berfungsi di Windows.

Level River St
sumber
1
Saya suka Langgan.
Michael Stern
Saya tidak yakin apakah itu karena modifikasi yang harus saya lakukan untuk mengompilasinya dengan GCC di Linux (hapus yang pertama termasuk, ganti scanf_sdengan scanfdan sertakan stdio.hjika saya kompilasi sebagai C ++ rater daripada C), tetapi tidak cukup berfungsi untuk saya. Misalnya, jika saya ke kiri, lalu kembali tepat di awal ( 15 35), saya berada di ruangan yang berbeda dari yang saya mulai.
Dennis
@ Dennis Saya telah melacak sumber kesalahan saat keluar. itu adalah scanf_s (seharusnya aman!) yang "merusak tumpukan variabel i" ketika mencoba untuk menempatkan apa yang saya asumsikan adalah integer 32 bit ke dalam char. Jadi hal pertama yang saya sarankan adalah memeriksa tipe yang digunakan scanf untuk "% d" dan ubah variabel i menjadi tipe itu. Saya mendapatkan jawaban yang benar w / error keluar untuk char, jawaban yang benar w / o error keluar untuk int, dan jawaban yang salah dengan tipe Microsoft __int64 (panjang yang setara, kecuali saya masukkan "% lld".) Anda juga sudah menjalankan versi ungolfed dan apakah Anda memiliki masalah dengan tampilan?
Level River St
@steveverrill: Ya, saya sudah mencoba kedua versi. Jenis imemang masalahnya. The halaman manual mengatakan: " d Cocok integer desimal opsional ditandatangani; pointer berikutnya harus menjadi pointer ke int ." Mengubah jenis membuatnya berfungsi dengan baik.
Dennis
@steveverrill: Saya tidak tahu bagaimana VS menangani banyak hal, tetapi jika Anda mengkompilasi dengan GCC (seperti C, bukan C ++), Anda dapat menyimpan banyak karakter. Tidak satu pun dari menyertakan diperlukan jika Anda mengganti NULLdengan 0dan scanf_sdengan scanf, Anda tidak perlu intsebelumnya maindan Anda dapat pindah idan dkeluar dari main (mereka default ke intdan diinisialisasi ke 0). Juga, Anda dapat mendefinisikan p=19,h=rand()%p,w=rand()%p, mengganti m[]dengan *mdan itu harus mungkin untuk mendefinisikan makro untuk semua contoh if(...==...)puts(...);.
Dennis
9

GolfScript, 269 karakter

{puts}:|;20,{;9{rand}:r~}$3<(:>"B:%d`w85>2n+Fup`y/>@D-=J7ldnx/W5XsLAb8~"{32-}%"`\24"{base}/3/{[.[~@].[~@]]}%:A=3r=0=:F;~:W;:P;{>A={0=F=}?:^P&!!{"You feel a breeze"|}*^W&!!{"You smell a wumpus"|}*'"#{'9.?r';STDIN.gets()}"'++~);(3%^=\4`={W={"Your arrow hit the wumpus"|0}{"Your arrow didn't hit anything"|W A=0=3r=:W>=.!\{"The wumpus catches you"|}*}if}{>:F;:>W=.!\{"You ran into the wumpus"|}*>P=.!\{"You fell into the pit"|}*&}if}do

Perhatikan bahwa 163 dikurangkan dari jumlah karakter untuk string hard-coded. Jika Anda ingin men-debug output yang menunjukkan nomor kamar tambahkan baris berikut tepat setelah kejadian pertama ^:

'  YOU 'F'->'>+++puts'  DIRECTIONS [BRL] '^`+puts'  PIT 'P+puts'  WUMPUS 'W+puts 

Sesi contoh (dengan output debug tambahan):

  YOU 6->11
  DIRECTIONS [BRL] [6 7 16]
  PIT 7
  WUMPUS 5
You feel a breeze
25
  YOU 11->16
  DIRECTIONS [BRL] [11 17 15]
  PIT 7
  WUMPUS 5
35
  YOU 16->11
  DIRECTIONS [BRL] [16 6 7]
  PIT 7
  WUMPUS 5
You feel a breeze
15
  YOU 11->6
  DIRECTIONS [BRL] [11 10 1]
  PIT 7
  WUMPUS 5
15
  YOU 6->10
  DIRECTIONS [BRL] [6 15 5]
  PIT 7
  WUMPUS 5
You smell a wumpus
14
Your arrow didn't hit anything
  YOU 6->10
  DIRECTIONS [BRL] [6 15 5]
  PIT 7
  WUMPUS 0
25
  YOU 10->5
  DIRECTIONS [BRL] [10 14 0]
  PIT 7
  WUMPUS 0
You smell a wumpus
24
Your arrow hit the wumpus
Howard
sumber
Ini adalah kode kerja pertama. Kembali lagi nanti untuk bermain golf lagi.
Howard
Kode saya saat ini 1 karakter lebih panjang. Saya mencari cara yang memungkinkan untuk bermain golf lebih jauh!
Timtech
Bukan berarti Anda membutuhkan bantuan saya, tetapi Anda dapat menyimpan 14 karakter dengan mendefinisikan {puts}:|;, 5 karakter dengan mengganti Rdan Wdengan -dan >(memungkinkan untuk menghilangkan spasi di sekitarnya) dan 9 karakter dengan menjatuhkan '> 'print(tampaknya tidak diperlukan oleh pertanyaan).
Dennis
@ Dennis Terima kasih. Saya pasti akan menerapkan beberapa saran Anda.
Howard
9

JavaScript (ECMAScript 6) - 2197 1759 -45% = 967,45 Karakter

Golfnya hampir selesai ...

Termasuk GUI dengan Peta Icosahedral dan Mega-Bats untuk bonus penuh.

Wumpus GUI

  • Setiap kamar memiliki 4 tombol: X (lubang); B(Mega-Bat); W(Wumpus); dan P(Kamu).
  • Lokasi Anda saat ini berwarna biru.
  • Tombol-tombol berwarna merah jika objek yang diwakilinya bisa berada di lokasi itu dan hijau jika itu pasti tidak di lokasi itu.
  • Itu W dan Ptombol dapat diklik hanya di kamar yang berdekatan dengan lokasi Anda saat ini.
  • Jika Anda menang, latar belakang berubah hijau dan jika Anda mati latar belakang berubah merah.

Kode:

P=x=>parseInt(x,36);Q=(y,a=4)=>[P(x)<<a for(x of y)];e=Q("def45c6di7ej1ai1bj2af3bf9dg8eh46b57a1gh0280390678ci9cj24g35h",0);X=Q("o6fl6afnik27bloscfaf");Y=Q("icp8i8t4jej4encjjan6");A='appendChild';C='createElement';W='width';H='height';G='background-color';L='disabled';I='innerHTML';N='className';D=document;R=Math.random;B=D.body;E=[];F=1<0;T=!F;Z="XBWP";s=D[C]('style');s.type='text/css';t='.A{position:absolute;left:25px;top:25px}.D{'+W+':50px;'+H+':50px}.D button{'+W+':25px;'+H+':25px;float:left}.R{'+G+':red}.G{'+G+':green}.B{'+G+':blue}';for(i in X)t+='#D'+i+'{left:'+X[i]+'px;top:'+Y[i]+'px}';s[A](D.createTextNode(t));D.head[A](s);c=D[C]('canvas');c[N]='A';c[W]=c[H]=500;B[A](c);x=c.getContext('2d');x.beginPath();d=(i,b,v)=>{for(j=0;j<3;j++){E[e[3*i+j]][b][L]=v}};a=(i,l,v)=>{t=F;for(j=0;j<3;j++)t=e[3*i+j]==l?T:t;if(t)M[v]++;b=E[i][v];b.c=-1;for(j=0;j<3;j++)E[e[3*i+j]][v].c+=t?1:-1;for(j of E)j[v][N]=j[v].c==M[v]?'R':'G';};M=[0,0,0];S=v=>{M[v]=0;for(i of E){i[v][N]='';i[v].c=0}};for(i in X){for(j=3*i;j<3*i+3;j++)x.moveTo(X[i],Y[i])|x.lineTo(X[e[j]],Y[e[j]]);B[A](v=D[C]('div'));v[N]='A D';v.id='D'+i;E[i]=[];for(j in Z){b=E[i][j]=v[A](D[C]('button'));b[L]=T;b.i=i;b.c=0;b[I]=Z[j];}E[i][4][O='onclick']=function(){d(P,2,T);d(P,3,T);if(this.i==W)c[N]+=' G';else{S(2);W=e[3*W+R()*3|0];if(W==P)c[N]+=' R';else{a(P,W,2);d(P,2,F);d(P,3,F)}}};E[i][3][O]=function(){d(P,2,T);d(P,3,T);E[P][3][N]='';P=this.i;if(W==P||Q==P){c[N]+=' R';return}else if(Z==P){j=P;do{P=R()*20|0}while(P==W||P==Q||P==j);do{Z=R()*20|0}while(Z==j||Z==P);S(1)}d(P,2,F);d(P,3,F);E[P][3][N]='B';a(P,Q,0);a(P,Z,1);a(P,W,2)}}x.stroke();P=R()*20|0;do{W=R()*20|0}while(W==P);do{Q=R()*20|0}while(Q==P);do{Z=R()*20|0}while(Z==P);E[P][3][N]='B';a(P,Q,0);a(P,Z,1);a(P,W,2);d(P,2,F);d(P,3,F)
MT0
sumber
Anda mendapatkan 1066 tanpa ECMA 6 menggunakan kompilator penutupan.
AMK
Saya bertanya-tanya seberapa mudahnya bila Anda memiliki representasi grafis untuk membantu mengurangi di mana semuanya berada. 1+ tapi agak terlalu mudah :)
Sylwester
9

Bash, 365 (versi kerja pertama 726!)

MENCARI DENGAN GOLFSCRIPT?

@Dennis pada dasarnya telah melakukan semua golf untuk saya. Terima kasih!

Program mengasumsikan input yang valid. Input yang valid adalah arah yang Anda pilih (1 untuk kanan, 2 untuk kiri, 3 untuk belakang) diikuti oleh tindakan Anda (4 untuk menembak, 5 untuk berjalan).

Beberapa Penjelasan

Saya biasanya melakukan penjelasan verbose besar, tapi ini mungkin agak terlalu rumit bagi saya untuk diganggu.

Setiap simpul pada grafik dodecahedron dikodekan sebagai huruf (a = 1, b = 2, ... t = 20).

Posisi awal pemain selalu 20 (dan mereka berdiri dengan punggung ke 18), karena itu tidak masalah dalam dirinya sendiri, hanya posisi relatif pemain, lubang dan masalah wumpus.

Variabel $p menyimpan lokasi pemain. $rmenyimpan lokasi pemain sebelumnya. $wadalah wumpus dan $h(H untuk lubang) adalah lubang.

Kode

p=t
r=r
j=echo
Z=npoemfsgnohtksblbtpckdpljqnriogelfhkbqrcaiadjhagimsmjtqecrdf
q(){ $j ${Z:RANDOM%19*3:1};}
C(){ [[ ${!1} =~ ${!2} ]];}
d(){ s=${Z:30#$1*3-30:3};}
w=`q`
h=`q`
for((;;));{
b=$p
d $p
u=u${s#*$r}$s
C w p&&$j The wumpus ate you&&exit
C h p&&$j You fell in the pit&&exit
C u w&&$j You smell the wumpus
C u h&&$j You feel a breeze from a pit
read i
F=5
y=${u:i/10:1};C i F&&p=$y&&r=$b||{ d $w;C y w&&$j You killed the wumpus&&exit;$j You missed;w=${s:RANDOM%3:1};};}

Riwayat Versi

  1. Rilis awal, 698 karakter
  2. Memperbaiki bug di mana "Anda merasakan angin sepoi-sepoi" dan "Anda mencium wumpus" tidak dapat ditampilkan secara bersamaan; disimpan 39 karakter dengan membuat pembuatan nomor acak fungsi.
  3. Ingat bahwa wumpus bergerak jika Anda menembak dan meleset. 726 karakter.
  4. Membuat grep -oEvariabel. Disimpan 5 karakter.
  5. Membuat [a-z]{3}variabel. Disimpan 3 karakter.
  6. Membuat echovariabel. Disimpan 5 karakter.
  7. Bertindak atas sebagian besar saran @Dennis. Disimpan 72 karakter.
  8. Menambahkan semua saran yang tersisa. Disimpan 68 karakter.
  9. Disimpan 2 karakter dari saran @DigitalTrauma.
  10. Memperbaiki bug utama di mana Anda hanya bisa menembak wumpus jika ada di kanan. Jumlah karakter yang sama.
  11. Ekspansi parameter yang digunakan untuk mengurangi 2 karakter menggunakan $m.
  12. Mencukur banyak karakter dengan cara membolos grepdan menjadi sedikit lebih masuk akal.
  13. Didefinisikan Csebagai fungsi pencarian regexp untuk digunakan dalam pernyataan if, dan Esebagai fungsi mencetak "Anda membunuh wumpus" dan keluar.
  14. Disimpan 1 char oleh pengaturan ulang "jika pernyataan".
  15. Menyimpan banyak karakter dengan menyingkirkan d , dan menghapus tanda kurung yang tidak perlu.
  16. Memperbaiki bug. Menambahkan banyak karakter :(
  17. TABUNGAN MOARR ( http://xkcd.com/1296/ )
  18. Lain dari ide @Dennis (menyimpan beberapa karakter), dan licik saya (ab) penggunaan tipuan (menyimpan 1 char).
  19. Perbaikan gaya untuk q ().
  20. menambahkan kembali output yang tepat

Contoh dijalankan

"In:" is input, "Out: is output".

Pemain berkeliaran sebentar, mencium wumpus dan menembak. Mereka rindu, dan wumpus masuk ke kamar mereka dan memakannya.

Dalam: 15

Dalam: 15

Dalam: 25

Dalam: 25

Dalam: 15

Keluar: Anda mencium wumpus

Dalam: 14

Keluar: Anda ketinggalan

Keluar: Wumpus memakanmu


sumber
1
Saya pikir Anda dapat membuat kode Anda setidaknya 100 byte lebih pendek. 1. exithanya satu byte lebih panjang dari g=1itu dan menghilangkan kebutuhan untuk menguji non-nol gdan beberapa elifpernyataan. 2. Anda bisa menggunakan ((i==35))sebagai ganti [ $i = 35 ]dan ...&&...bukan if ... then ... fi. 3. q(){ L=({a..s});$j ${L[RANDOM%19]};}dan n=`$k $w$m<<<$d`;w=${n:RANDOM%2+1:1}keduanya menghemat beberapa byte.
Dennis
1
Ganti while :;do... donedengan for((;;);{...} untuk penghematan 3 char
Digital Trauma
1
@professorfish: Saya pikir fungsi akan bekerja lebih baik daripada pendekatan string-grep-cut saat ini. Misalnya, d(){ x=npoemfgnshtoksblbtckpdpljqniorelgfhkbqraicadjaghimsmjtqecrdf;s=${x:3*30#$1-30:3};}akan memungkinkan Anda untuk mengganti definisi dari sdan ndengan d $pdan d $w. Jika Anda selanjutnya mendefinisikan u=${s#*$r}$s(dan menyesuaikan definisi ldan fsesuai), Anda tidak perlu $kdan $mlagi. Menghemat 83 byte, saya pikir. Juga, ruang dalam q ()tidak diperlukan.
Dennis
1
@professorfish: Dan Anda dapat menyimpan 3 byte tambahan dengan mendefinisikan c(){ [[ $1 =~ $2 ]];}dan mengganti, misalnya, baris kedua hingga terakhir c $r $b||{ $j You missed;d $w;w=${s:RANDOM%2+1:1};}.
Dennis
1
@professorfish: Menggunakan fungsi yang saya sarankan harus lebih pendek 3 byte. Anda dapat menyimpan 106 byte tambahan dengan mengganti empat baris setelah b=$pdengan d $p;u=u${s#*$r}$s, garis setelah read idengan, y=${u:i/10:1};C $i 5&&{ p=$y;r=$b;}||{ d $w;C $y $w&&$j You killed the wumpus&&exit;$j You missed;w=${s:RANDOM%2:1};}dan menghilangkan E().
Dennis
6

GolfScript ( 206 198)

[5:C,]{{.{[~@]}:>~.{-1%}:<~}%.&}8*({[.<><.<><]}:F~-{99rand}$~5,{.<{>.'You smell a wumpus.\n'4{$F@?~!!*}:Q~{print}:,~}3*{>.'You feel a breeze.\n'5Q,}3*'"#{'C):C';STDIN.gets()}"'++~~:&9/{>}*&5%{'You killed the wumpus.'3Q{\<{>}3rand*\"Your arrow didn't hit anything.\n",0}or}{\;.'You fell into the pit.'4Q}if\.'You were killed by the wumpus.'4Q@or:n!}do];

Akhirnya menyusul versi tabel pencarian Dennis, dari mana ia meminjam sedikit. Hal yang menarik tentang versi ini adalah tidak memiliki tabel pencarian untuk tata letak ruangan.

The 60 simetri rotasi dari icosahedron isomorfik ke grup alternating pada 5 huruf, A_5. Setelah mencoba semua jenis pendekatan untuk mewakili grup secara kompak, saya kembali ke yang paling sederhana: setiap elemen adalah permutasi dari paritas genap. Grup dapat dihasilkan dari dua generator dengan lebih dari satu cara: pendekatan yang saya gunakan menggunakan generator 3dan 3 1. Ini memungkinkan kita untuk menghasilkan 1 = 3 3 1, 2 = 3 3 1 3 1dan3 = 3 .

Perhatikan arah yang 3sesuai dengan elemen orde 2, karena setelah melewati pintu di belakang Anda, pintu itu ada di belakang Anda lagi. Arah 1sesuai dengan elemen urutan 5, berjalan di sekitar puncak icosahedron. (Demikian pula elemen 2). Dan kombinasinya 3 1adalah orde 3, karena putaran mengelilingi kamar yang berdekatan dengan yang dimulai di belakang Anda.

Jadi kami sedang mencari permutasi orde 2 untuk mewakili arah 3dan permutasi orde 5 untuk mewakili arah 1sehingga 3 1orde 3.

Ada 15 permutasi urutan 2 di A_5, dan untuk masing-masing ada 8 permutasi kandidat untuk 1(dan karenanya untuk 3 1). Ada daya tarik yang jelas [4 3 2 1 0]untuk 3: membalikkan array itu adil-1% . Dari kemungkinan permutasi pendamping yang 3 1saya pilih [0 1 3 4 2], yang mengakui implementasi yang cukup singkat sebagai [~@].

Tidak disatukan

# Generate the 60 permutations by repeated application of `3 1` and `3`
[5:C,]{{.{[~@]}:>~.{-1%}:<~}%.&}8*
# Remove [0 1 2 3 4] and its equivalence class (apply 3 (3 1)^n 3 for n in 0,1,2)
({[.<><.<><]}:F~-
# Shuffle the remaining 57 options to select random starting points for wumpus and pit
# Note that this introduces a slight bias against them being in the same room,
# but it's still possible.
{99rand}$~
# Start player at [0 1 2 3 4]
5,
{
    # Stack: Pit Wumpus Player
    .<
    # The adjacent rooms to the player are Player<> , Player<>> , and Player<>>>
    # If the wumpus is in one of those rooms, say so.
    {
        >."You smell a wumpus.\n"4
        {
            # ... X str off
            $F@?~!!*
            # ... str off$F X ?~!! *
            # Which means that we leave either str (if off$ and X are equivalent)
            # or the empty string on the stack
        }:Q~
        {print}:,~
    }3*
    # Ditto for the pit
    {>."You feel a breeze.\n"5Q,}3*
    # Read one line from STDIN.
    '"#{'C):C';STDIN.gets()}"'++~~
    # Stack: Pit Wumpus Player Player< Input
    # Find the room corresponding to the specified direction.
    :&9/{>}*&
    # Stack: Pit Wumpus Player TargetRoom Input
    5%{
        # Shoots:
        "You killed the wumpus."3Q
        {
            \<{>}3rand*\ # Move the wumpus to an adjacent room
            "Your arrow didn't hit anything.\n", # Inform
            0 # Continue
        }
        or
    }{
        # Moves:
        \;
        # If player and pit share a room, say so.
        ."You fell into the pit."4Q
    }if
    # If player and wumpus share a room, say so.
    # NB If the player walks into a room with the pit and the wumpus,
    # the `or` favours the pit death.
    \."You were killed by the wumpus."4Q@or
    # Save the topmost element of the stack for output if we break the loop. Loop if it's falsy.
    :n!
}do
# Ditch the junk.
];
Peter Taylor
sumber
Pendekatan aljabar yang bagus! Namun ada bug minor: 10/@3%=mencoba mengakses elemen keempat array dengan panjang 3 jika inputnya 35.
Dennis
@ Dennis, ya, saya sadar setelah saya pergi tidur. Saya dapat memikirkan berbagai cara untuk memperbaikinya, semua biayanya 2.
Peter Taylor
Anda bisa mendapatkan satu char kembali 9/3%@3%=.
Dennis
Saat ini saya 7 chars dengan beberapa restrukturisasi yang lebih drastis. Tapi itu 1 karakter 9/bukannya 10/masih berfungsi, jadi terima kasih.
Peter Taylor
5

Wumpus , 384 - 129 (string) = 255 byte

1SDL2vSD70L?.;;3AL1a!?,9)".supmuw a llems uoY"99+1.
II5x?,&WC2.           L2a!?,9)".ezeerb a leef uoY"93*2.
L1a!,FCFC[&WCL1a!?,"!supm",AW#16#[(=]?.;;l(&o1.
    ?,".uoy eta ",".gnih","uw eht dellik uoY"#22&oN@
     #15#L2a!?. ,"supmu","tyna tih t'ndid worra ruoY"#31&oND";"4L1a!?.;;L1xSUL1xSD=F-#81~4~?.;;;CCWC=F-#97~4~?.;;;2.
 ,"nto the pit."|       "w ehT"l&oN@
 |"i llef uoY"l2-&oN@

Cobalah online! (Tentu saja, TIO tidak masuk akal, karena Anda tidak dapat menggunakan program secara interaktif di sana, dan begitu program kehabisan instruksi pada STDIN, ia akan membaca 0 0, yang setara dengan 3 4, sehingga Anda akan berakhir menembakkan panah sampai Wumpus bergerak ke sana atau membunuhmu.)

Ketika menjalankan ini secara lokal, pastikan bahwa linefeed setelah nomor kedua dari setiap input memerah (karena Wumpus membutuhkannya untuk menentukan bahwa nomor tersebut sudah lewat). Dalam Powershell, saya entah bagaimana harus memasukkan satu karakter lagi setelah linefeed untuk membuatnya berfungsi (tidak masalah karakter mana, tapi saya hanya menggunakan double linefeeds untuk pengujian).

Ada banyak ruang untuk bermain golf lebih jauh, tetapi mencoba tata letak yang sama sekali baru membutuhkan waktu. Skor akhir juga sangat tergantung pada string aktual yang saya gunakan, karena dalam bahasa 2D, string N byte cenderung lebih mahal daripada N byte kode sumber, karena itu menempatkan kendala signifikan pada tata letak kode, dan Anda sering perlu membaginya menjadi beberapa bagian (menimbulkan tanda kutip ganda tambahan). Pada akhirnya, jika saya mengurangi setiap string menjadi satu huruf (dan -129 menjadi -12), saya mungkin akan menghemat satu ton byte.

Penjelasan

Pertama, penafian: terlepas dari nama bahasa, itu tidak dirancang untuk membuat penerapan Hunt the Wumpus sangat mudah. Sebagai gantinya, saya pertama-tama merancang bahasa di sekitar tema segitiga, berakhir dengan struktur data icosahedral, dan memutuskan untuk menyebutnya Wumpus karena itu.

Jadi ya, sementara Wumpus terutama berbasis stack, ia juga memiliki 20 register yang disusun di sekitar wajah icosahedron. Itu artinya, kami mendapatkan struktur data untuk mewakili peta secara gratis. Satu-satunya hal yang tidak dapat kita lakukan dengan mudah adalah menemukan wajah tertentu pada icosahedron, jadi untuk mencarinya, kita perlu "menggulung d20" hingga kita berakhir pada wajah yang kita cari. (Dimungkinkan untuk melakukan ini dengan cara deterministik, tetapi itu akan membutuhkan lebih banyak byte.) Mencari wajah seperti ini berakhir hampir pasti (yaitu dengan probabilitas 1), sehingga pencarian yang berjalan selamanya tidak menjadi perhatian dalam praktiknya).

Kode di atas adalah versi golf dari implementasi pertama ini dengan tata letak yang lebih waras:

1SDL2vSD70L?.;;2.  < Setup; jumps to third line which starts the main loop

3AL1a! ?,".supmuw a llems uoY"#19&oN03.          < This section checks the player's surroundings.
        L2a!?,".ezeerb a leef uoY"#18&oN04.
             AW(=12[?.;;7.

    }&WC#11.                                     < This section reads the input. The top branch moves, the bottom branch shoots
II5x^                                              and kills or moves the wumpus.
     {FCFC[&WCL1a !?,"!supmuw eht dellik uoY"#22&oN@
                    ".gnihtyna tih t'ndid worra ruoY"#31&oND#59 9L1a!?.;;L1xSUL1xSD=F-#82~9~?.;;;CCWC=F-#98~9~?.;;;#11.

L1a!?,".uoy eta supmuw ehT"#19&oN@               < This section checks whether the player dies.
     L2a!?,".tip eht otni llef uoY"#22&oN@         Otherwise, we return back to the third line.
          2.

Karena golf sebagian besar melibatkan mengompresi tata letak, saya hanya akan menjelaskan versi ini untuk saat ini (sampai saya menambahkan trik golf yang melampaui restrukturisasi kode).

Mari kita mulai dengan kode pengaturan:

1SDL2vSD70L?.;;2.

Awalnya, semua wajah diatur ke 0 . Kami akan menyandikan wumpus dengan mengatur 1-bit dari wajah yang sesuai, dan lubang dengan mengatur 2-bit. Dengan cara ini, keduanya bisa berada di ruangan yang sama. Posisi pemain tidak akan direkam pada icosahedron sama sekali, melainkan akan selalu berupa wajah aktif (hanya satu dari 20 register yang aktif pada satu waktu).

1S     Store a 1 in the initially active face to put the wumpus there.
D      Roll the d20. Applies a uniformly random rotation to the icosahedron.
L2vS   Load the value of that face (in case it's the wumpus's), set the 2-bit
       and store the result back on that face.

Sekarang kita perlu menemukan wajah kosong acak untuk memasukkan pemain.

D      Roll the D20.
70     Push 7 and 0 which are the coordinates of the D in the program.
L      Load the value of the current face.
?.     If that value is non-zero (i.e. the active face has either the
       wumpus or the pit), jump back to the D to reroll the die.
;;2.   Otherwise, discard the 0 and the 7 and jump to (0, 2), which is
       the beginning of the main loop.

Bagian selanjutnya ini memeriksa lingkungan pemain dan mencetak peringatan yang sesuai:

3AL1a! ?,".supmuw a llems uoY"#19&oN03.
        L2a!?,".ezeerb a leef uoY"#18&oN04.
             AW(=12[?.;;7.

Ini adalah loop yang kami jalankan melalui 3 kali. Setiap kali, kita melihat tetangga sebelah kanan, mencetak string yang sesuai jika ada bahaya dan kemudian memutar icosahedron sebesar 120 °.

3    Push a 3 as a loop counter.
A    Tip the icosahedron onto the NW neighbour of the active face, which
     will be used to represent the right-hand room.
L1a  Extract the 1-bit of the value on that face.
!?,  If that value is zero, strafe to the next line, otherwise continue.

  ".supmuw a llems uoY"#19&oN03.
     Print "You smell a wumpus.", a linefeed and then jump to the next line.

L2a  Extract the 2-bit of the value on that face.
!?,  If that value is zero, strafe to the next line, otherwise continue.

  ".ezeerb a leef uoY"#18&oN04.
     Print "You feel a breeze.", a linefeed and then jump to the next line.
A    Tip back to the original active room (where the player is).
W    Rotate the icosahedron by 120°, so that the next iteration checks
     another neighbour.
(=   Decrement the loop counter and duplicate it.
12   Push 1, 2, the coordinates of the cell after the 3 (the loop counter).
[    Pull up one copy of the loop counter.
?.   If it's non-zero, jump to the beginning of the loop, otherwise continue.
;;7. Discard the 2 and the 1 and jump to (0, 7), which reads the player's
     input for this turn.

Bagian selanjutnya membaca dua angka dari pemain dan kemudian menggerakkan pemain atau menembakkan panah. Yang pertama sepele, yang terakhir kurang begitu. Masalah utama untuk menembak panah adalah kasus di mana ia meleset. Dalam hal ini kita a) perlu mencari wumpus untuk memindahkannya, dan kemudian b) kembali ke kamar pemain dan orientasi yang benar dari icosahedron (sehingga "kembali" tetap "kembali"). Ini adalah bagian paling mahal dari keseluruhan program.

    }&WC#11.
II5x^
     {FCFC[&WCL1a !?,"!supmuw eht dellik uoY"#22&oN@
                    ".gnihtyna tih t'ndid worra ruoY"#31&oND#59 9L1a!?.;;L1xSUL1xSD=F-#82~9~?.;;;CCWC=F-#98~9~?.;;;#11.

Titik masuk ke bagian ini adalah Idi sebelah kiri.

II   Read the integers from STDIN.
5x   XOR the second one with 5.
^    Turn either left or right, depending on the previous result. If the
     second input is 4, XORing with 5 gives 1 and the IP turns right.
     Otherwise, we get 0 and the IP turns left.

If the player entered 5, move:

}    Turn right so that the IP moves east again.
&W   If the room indicator is X, rotate the icosahedron by X*120°. This
     puts the target room south of the active face (where the back room
     normally is).
C    Tip the icosahedron onto the southern face. This moves the player there.
     Due to the way tipping works, the formerly active face will now be
     the southern neighbour, i.e. correctly at the back of the player.
#11. Jump to (0, 11), the final section which checks whether the player
     stepped into the pit or onto the wumpus.

If the player entered 4, move:

{    Turn left so that the IP moves east again.
F    Store the active face index (the player's position) on the stack.
CFC  Also store the face index of the southern neighbour (the back room)
     on the stack, so that we can recover the correct orientation if
     we need to.
[    Pull up the player's room choice.
&WC  Tip the icosahedron onto the corresponding face (same as for the move action)
L1a  Extract the 1-bit of the value on that face to check whether the arrow
     hit the wumpus.
!?,  If that value is zero, strafe to the next line, otherwise continue.

  "!supmuw eht dellik uoY"#22&oN@
     Print "You killed the wumpus.", a linefeed, and terminate the program.

".gnihtyna tih t'ndid worra ruoY"#31&oN
     Print "Your arrow didn't hit anything." and a linefeed.

This next bit is a loop which searches for the wumpus:

D    Roll the d20. The easiest way to search for the wumpus is to look at
     random faces.
#59 9
     Push 59 and 9, the coordinates of the beginning of this loop.
L1a  Extract the 1-bit of the value on the current face.
!?.  If that value is zero, jump back to the beginning of this loop to
     try another face, otherwise continue.
;;   Discard the 9 and the 59.
L1xS Unset the 1-bit of the current face to remove the wumpus there.
U    Tip the icosahedron onto a random neighbouring face. This moves us
     to a random adjacent room.
L1xS Set the 1-bit of the current face to put the wumpus there.

This next bit contains two loops which get us back to the player's room
with the correct orientation. We do this by first searching for the room
at the player's back, and then looking through its neighbours to find the
player's room.

D    Roll the d20.
=F-  Duplicate the back room index and subtract the current face index.
#82~9~
     Push 82 and 9 and pull up the difference we just computed.
?.   If the difference is non-zero (we've got the wrong room), jump back
     to the D to try again. Otherwise continue.
;;;  We've found the back room. Discard the 9, the 82 and the back room index.
C    Tip the icosahedron onto the southern face (one of the candidate
     neighbours which might be the player's room).
CWC  This begins the loop that searches for the player's room. Tip onto
     the back room, rotate by 120°, tip back. This cycles through the
     neighbours of the back room, while keeping the active face on those
     neighbours.
=F-  Duplicate the player's room index and subtract the current face index.
#98~9~
     Push 98 and 9 and pull up the difference we just computed.
?.   If the difference is non-zero (we've got the wrong room), jump back
     to the CWC to try again. Otherwise continue.
;;;  We've found the player's room and since we entered from the back room
     via C, we've also got the correct orientation. Discard the 9, the 98
     and the player's room index.
#11. Jump to (0, 11), the final section which checks whether the player
     stepped into the pit or onto the wumpus.

Fiuh, itu bagian yang sulit. Sekarang kita hanya perlu memeriksa apakah pemain mati dan memulai dari loop utama:

L1a!?,".uoy eta supmuw ehT"#19&oN@
     L2a!?,".tip eht otni llef uoY"#22&oN@
          2.

Struktur bagian ini pada dasarnya identik dengan struktur yang kami gunakan ketika memeriksa lingkungan pemain: kami memeriksa 1-bit dari wajah saat ini (ruang pemain) dan jika diatur kami mencetak The wumpus ate you.dan menghentikan program. Kalau tidak, kita periksa 2-bit dan sudah diatur kita mencetak You fell into the pit.dan mengakhiri program. Kalau tidak, kita mencapai 2.yang melompat kembali ke awal loop utama (pada koordinat (0, 2)).

Martin Ender
sumber
1

awk - besar

Ini tidak berjalan sesingkat yang saya harapkan, tetapi saya mengambil pendekatan yang sedikit berbeda untuk berurusan dengan grafik, jadi saya tetap memposting versi yang tidak diklik.

Saya mengambil keuntungan dari fakta bahwa icosahedron (20 sided polyhedron) di bawah rotasi menjaga orientasi isomorfik untuk kelompok bolak-balik derajat 5 (permutasi elemen 5 memiliki jumlah genap dari siklus panjang genap). Saya kemudian memilih dua permutasi dengan panjang siklus 5 sebagai "kiri" dan "kanan", dan saya memilih satu permutasi dengan panjang siklus 2 sebagai "kembali". Menggunakan ini, saya membangun grafik dari satu ruangan dengan berjalan di jalur Hamiltonian (2xRRRLLLRLRL, menggunakan 3xRB di setiap kamar untuk menangkap 3 kemungkinan arah).

function meta(z,a,b,c,d) {
    if(z==COMPOSE) {
        split(a,c,"");
        split(b,d,"");
        return c[d[1]]c[d[2]]c[d[3]]c[d[4]]c[d[5]];
    }
    if(z==WALK) {
        split(R" "R" "R" "L" "L" "L" "R" "L" "R" "L,c);
        for(b = 1; b <= 20; b++) {
            map[a] = b;
            a = meta(COMPOSE,meta(COMPOSE,a,R),B);
            map[a] = b;
            a = meta(COMPOSE,meta(COMPOSE,a,R),B);
            map[a] = b;
            a = meta(COMPOSE,meta(COMPOSE,a,R),B);
            a = meta(COMPOSE, a, c[b % 10 + 1]);
        }
    }
    if(z==TEST) {
        a = map[meta(COMPOSE,U,L)];
        b = map[meta(COMPOSE,U,R)];
        c = map[meta(COMPOSE,U,B)];
        if(a==W||b==W||c==W) print "You smell the wumpus";
        if(a==P||b==P||c==P) print "You feel a breeze";
        if(map[U]==W) {
            print "You have been eaten by the wumpus";
            exit;
        }
        if(map[U]==P) {
            print "You have fallen into a bottomless pit";
            exit;
        }
    }
    if(z==ARROWTEST) {
        if(A==W) {
            print "You have slain the wumpus!";
            exit;
        } else {
            for(a in p) if(map[a]==W) break;
            W=map[meta(COMPOSE,a,v[int(rand()*3)+1])];
        }
    }
}

BEGIN {
    COMPOSE = 0;
    WALK = 1;
    TEST = 2;
    ARROWTEST = 3;
    L = 35214;
    R = 35421;
    B = 35142;
    split(R" "L" "B,V);
    meta(WALK,L);
    W = int(rand()*19)+2;
    P = int(rand()*19)+2;
    U = L;
    meta(TEST);
}

{
    d=int($0/10);
    m=$0%10;
    if(m==5) U = meta(COMPOSE,U,V[d]);
    else if(m==4) {
        A = map[meta(COMPOSE,U,V[d])];
        meta(ARROWTEST);
    }
    meta(TEST);
}
laindir
sumber