Wumpus'u avla


39

Çocukluğumda çocuklar bilgisayar dükkanlarına girip, personel bizi kovuncaya kadar Hunt the Wumpus'u oynarlardı. 1970'lerin ortasındaki ev bilgisayarlarında programlanabilen basit bir oyundu, o kadar ilkel makinelerdi ki, chicklet büyüklüğündeki mikroişlemciler yerine, bazılarının muhtemelen gerçek civcivleri olduğunu düşünüyorum.

Oyunu geçmiş donanımda yeniden üreterek bu geçmiş dönemi uyandıralım.

  1. Müzikçalar, bir icosahedral harita üzerinde rastgele bir odada başlar (bu nedenle, bir ikosahedronun yüzleri gibi birbirine bağlı toplam 20 oda vardır ve her oda tam olarak üç çıkışa sahiptir).

  2. Wumpus rastgele seçilen farklı bir odada başlar. Wumpus kokar ve kokusu bulunduğu yere bitişik üç odadan herhangi birinde tespit edilebilir, ancak kokunun yönü oyuncunun belirlemesi imkansızdır. Oyun sadece "bir wumpus kokusu aldığını" bildirir.

  3. Oynatıcı, bir yay ve sınırsız sayıda ok taşıyor ve istediği zaman önündeki odaya vurabiliyor. Wumpus o odadaysa, ölür ve oyuncu kazanır. Eğer wumpus o odada değilse, ürküyor ve mevcut konumuna bağlı üç odanın herhangi birine rastgele hareket ediyor.

  4. Rastgele seçilen bir oda (oyuncunun başladığı yer olmadığı garanti edilir) dipsiz bir oyuk içerir. Oyuncu, çukura bitişik herhangi bir odadaysa, bir esinti hisseder, ancak esintinin hangi kapıdan geldiğine dair hiçbir ipucu yoktur. Odaya çukurla girerse ölür ve wumpus kazanır. Wumpus çukurdan etkilenmez.

  5. Eğer oyuncu wumpusun odasına girerse veya wumpus oyuncu odasına girerse, wumpus kazanır.

  6. Oynatıcı, bir sayı ile karşı karşıya olduğu yönü belirtir (1 = sağ, 2 = sol, 3 = geri) ve sonra bir eylem (4 = bir ok vur, 5 = belirtilen yönde yürü).

  7. Puanlama uğruna, her oyun dizesi ("Bir meltem hissediyorsunuz", "Bir wumpus kokuyorsun", "Okun hiçbir şeye çarpmadı", vb.) Bir bayt olarak kabul edilebilir. Oyun kodunu metin olarak gizlemek için kötüye kullanma; bu sadece oyuncu ile etkileşimde bulunmak içindir.

  8. Oyuncudan farklı rastgele bir odada başlayan megabatların uygulanması için bayt sayınızın% 10'unu çıkarın (bir odayı wumpus ve / veya çukurla paylaşabilirler). Eğer oyuncu odaya yarasalar ile girerse, yarasalar oyuncuları rastgele seçilen başka bir odaya taşıyacaktır (içinde çukur veya wumpus bulunan oda olmadığı garantilidir), kendi rasgele yerlerine gitmeden önce. Yarasaların bitişiğindeki üç odada, gıcırtılı sesler duyulabilir, ancak oyuncuya, sesin hangi odadan geldiği hakkında hiçbir bilgi verilmez.

  9. Ikosahedral haritasını ve oyuncunun çukurun konumu, wumpus ve yarasalar (varsa) hakkında bugüne kadar sahip olduğu bilgilerin bir tür gösterimini gösteren grafiksel bir arayüz uygulamak için bayt sayınızın% 35'ini azaltın. Oyuncu. Açıkçası, eğer wumpus hareket ederse veya oyuncu yarasalar tarafından hareket ettirilirse, haritanın buna göre sıfırlanması gerekir.

  10. Ayarlandığı gibi en düşük bayt sayısı kazanır.

Oyunun bir sürümü için temel kaynak kodu (zorunlu olarak yukarıdaki kurallara uymamak ve her halükarda tamamen yersiz) bu web sitesinde ve muhtemelen başkalarında bulunabilir.


Bazı açıklamalar: 3. eğer wumpus o odaya girmediyse ürküyor ve ÜÇ odalardan birine taşınıyorsa… yani bir ok atıp ıskalarsanız, wumpus gelip sizi öldürebilir, değil mi? Ve wumpus sadece ürküyorsa hareket eder, yoksa sadece durur mu? 6. Oyuncunun başlığının geldiği oda tarafından belirlendiğini biliyorum. Yani güneyden gelmişse, seçenekleri 1. kuzeydoğu, 2. kuzeybatı 3. güney olacak ve kuzeyden geldiyse bunun tam tersi olacaktır. Ayrıca kurallarınız referans programından daha basit / golfçü görünüyor (henüz detaylı olarak araştırmadım.) Doğru muyum?
Seviye River St

Ahh! Bulamıyorum herhangi net ikosahedron her yerde ikili grafiğin fotoğraflarını.
Jack M,

1
@steveverrill Evet, eğer onu korkutuyorsan, gelip seni öldürebilir. Eğer korkutmazsan, hareket etmiyor. Oyunda birçok farklılıklar var; Örneğin birçok sürüm okların etrafını dolaştırmasına ve seni öldürmesine izin verir. Bunu ben öğrendim.
Michael Stern,

3
@ JackMy, bir icosahedron yüzünün haritası, on iki yüzlü bir köşenin haritası ile aynıdır ve bu grafik kolayca bulunur. Örneğin wolframalpha.com/input/?i=DodecahedralGraph+edgerules veya eşdeğer Mathematica komutunu GraphData ["DodecahedralGraph", "EdgeRules"] deneyin. Her iki durumda da {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
@JackM Hayır, "geri", geri dönüp geldiğiniz şekilde geri yürümeyi ifade eder. "İki kez" geri basarsanız, başladığınız yere kadar gidersiniz. Daha önceki oyun durumlarını kaydetmeye gerek yok.
Michael Stern,

Yanıtlar:


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, bayt sayısı (290) alınarak, kullanıcı (6) ile etkileşime girmek için kullanılan dizi sayısını ekleyerek ve bu dizelerin (133) birleşik uzunluğunu çıkartarak elde edilir. Satırlar dizgilerin bir parçasıdır ve bayt sayımına katkıda bulunur.

Dönüm Noktaları

  1. Taşınmış professorfish cevabı Bash dan GolfScript için. Puan: 269

  2. Peter Taylor'ın yorumlarındaki önerileri üzerine hareket etti . Puan: 250

  3. Peter Taylor tüm kodumu yeniden düzenledi ve arama tablosunu sıkıştırmam için bana yardım etti. Skor: 202

  4. Bitişik odaların arama tablosunu matematiksel bir yaklaşımla değiştirdi. Skor: 182

  5. Refactored giriş, çıkış ve matematiksel yaklaşımı destekleyen fonksiyon. Skor: 163

Büyük bir “Teşekkürler!” Peter Taylor'a tüm yardımı için gidiyor.

Nasıl çalışır

20 oda, aşağıdaki şekilde 0 ila 19 arasında sayıları atanan bir on iki yüzlünün tepe noktaları olarak temsil edilir:

Dodecahedral grafik

N odasına bitişik olan ve saat yönünde düzenleyen odaları bulmak için dört vakayı göz önünde bulundurmalıyız:

  • Eğer N ≡ 0 mod 4 (mavi tepe noktaları) ise, bitişik oda 19 - N , N + 2 mod 20 ve N - 2 mod 20'dir .

  • Eğer N ≡ 1 mod 4 (yeşil tepe noktaları), bitişik bir oda vardır , N - 19 , N - 4 mod 20 ve N + 4 mod 20 .

  • Eğer N ≡ 2 mod 4 (sarı tepe noktaları), bitişik bir oda vardır , N - 19 , N - 2 mod 20 ve N + 2 mod 20 .

  • Eğer N ≡ 3 mod 4 (kırmızı köşeler) ise, bitişik oda, 19 - N , N + 4 mod 20 ve N - 4 mod 20'dir .

# 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”.

1
İçeri 1 kaydedebilirsiniz Qile 19rand 97+; 2'de @ile 97%3*&>... Inlining tarafından başka bir 1 Qolarak {19rand 97+}2*:,\:Hdeğiştirerek, birkaç |ile *bir yapmanın en iyi yolu sık sık olan if. Bamaç yoktur ve bence yığın kullanarak birkaç değişken daha ortadan kaldırılabilir.
Peter Taylor

1
Başka bir sık ​​numaradan bahsetmeyi unuttum: arama tabloları için temel dönüşüm. Bitişiklik listesindeki 62 karakteri 33-karakterli bir dizge ile değiştirebilir ve ardından 256base 20basemuhtemelen birkaç +/- 97'yi yok edebilirsiniz). Tek dezavantajı, yazdırılamayan karakterler gerektirmesidir.
Peter Taylor

1
Daha aptalca bir GS olmak için refactoring yaparak 13 tane daha tasarruf ettim (çoğunlukla değişkenler yerine yığını kullanarak); ve çıktıyı daha az güzel hale getirme pahasına 10 ek var. Bu önceki yorumumda belirtilen arama tablosu sıkıştırmasından ayrı.
Peter Taylor

1
Hiç de değil, zevk aldım. Arama tablosu yaklaşımının kullanmak istediğim matematiksel yaklaşımdan çok daha iyi olduğunu hayal kırıklığına uğrattım. Btw Şu anki sürümünüzde küçük bir hata olduğunu düşünüyorum, çünkü bir ok ateşlerseniz, özlüyor ve wumpus'u odanıza sokuyorsanız, o zaman sadece oklardan You were killed by the wumpussöz edilmeden çıkar. Bu yüzden hoş olmayan versiyonuna ekliyordum.
Peter Taylor

1
2*2+=>)2*
Peter Taylor

15

REV0 C ++ (Windows'ta Visual Studio) 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!");}}

Aşağıda, bir tehlikenin hemen yanında başlamamanız şartıyla) doğru oyunla her zaman kazanabileceğinizi gösteren bir oyundur. Müzikça bir meltem hissediyor, geri dönüyor ve saat yönünün tersine tam bir döngü yapıyor. Yine bir esinti hissetmesi için tam olarak 5 hamle yapmasıyla sağındaki deliği bilir ve mümkün olduğunca uzağa gider. Benzer şekilde, sağ ya da sol olup olmadığını bilmeden, wumpus kokladığında geri döner ve saat yönünde bir döngü yapar. Yine wumpusu koklamak için 5 hamle yapması gerekiyor, bu yüzden sola doğru olduğunu biliyor ve kesin bir şekilde vuruyor.

Eğer öbür tarafa ilmek etmiş olsaydı, wumpusu daha erken bulurdu ve döndüğü yönde olduğunu biliyordu.

görüntü tanımını buraya girin

REV1 C (Cygwin'deki GCC),% 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!",)}}

Netlik için Newlines eklendi. Rev 0'dan gelen değişiklikler aşağıdaki gibidir:

Windows için Cygwin Linux emülatöründe GCC derleyicisini önerdiğiniz için @Dennis 'e teşekkür ederiz. Bu derleyici includerev 0 programında s gerektirmez ve intdeğişkenler için varsayılan tipe izin verir ve main.bu hayat değiştiren bir golf ipucudur!

Ek olarak, Linux'ta çalıştırmak \f, imlecin satır başı yapılmadan aşağı doğru hareket etmesine neden olduğu anlamına gelir (Windows'ta yalnızca basılabilir bir sembol ürettiği gibi).

Dennis'den yorumlarda birkaç ipucu ve kendi yorumlarımdan biri: ok wumpus'a çarpıp çarpmadığını kontrol ederken durum değişikliği: if(q==w)> if(q-w)(..else .. tersine döndü)

Oyuncunun bildiği bilgiyi gösteren grafik ekranın eklenmesi, bir wumpusun nerede koktuğunu / bir esinti hissettiğini,% 35 ikramiyeyi talep ettiğini hissediyor. (Bunun eski hata ayıklama sürümünü sildim, bu da wumpus ve hole'nin tam konumunu gösterdi. Düzenleme geçmişinde görülebilir.)

REV2C (Cygwin'deki GCC),% 389-35 bonus = 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");}

Kodumu yeniden düzenlemesi için Dennis'e tekrar teşekkürler:

Char sabiti m[]değişmezlerle değiştirildi (değişmez dizini indeksleyebileceğinizi bilmiyordum.)

Yığın değişkeni ile rasgele sayıların tohumlanması (sisteme bağlı, bazı sistemler bellek tahsisini bir güvenlik önlemi olarak rastgele ayarlar.)

İleti, argümanların içine yerleştirildiğinde görüntülendiğinde çalıştırılması gereken putsbir makro printfve ek kod ile değiştirilen makro printf(format dizesinde yeterli format belirteci yoksa, printf'nin son birkaç argümanı yazdırmadığı avantajı.) ifile ikame edilmiş||

Yeni makro içine yerleştirilen yeni oyuncu / wumpus pozisyonunun hesaplanması.

Dış whiledöngüye yerleştirilen mesajları kazan / kaybet . ifkoşullu operatör tarafından değiştirildi.

Ok atma için koşullu operatörün kullanılması. Müzikçalar özlüyorsa, bu hem mesaj yazdırmayı hem de wumpus konumunu ayarlamayı gerektirir. Dennis, birleştirme printfve wumpus pozisyonunun hesaplanmasını tek bir ifadeyle bir kaç yöntemle teklif etti , ancak ben kendimden biriyle gittim. 31 printfolan basılan karakter sayısını döndürür Your arrow didn't hit anything\n(11111 ikili) 31&Q(w)==Q(w).

Bu düzenlemeye diğer katkım, gereksiz parantezlerin ortadan kaldırılması olmuştur.

Çıktı

Burada oyuncu Wumpus'un nerede olduğunu çoktan buldu, ancak çukurun nerede olduğunu bulmak için kapsamlı bir keşif yapmayı seçti. Wumpus ve pit'in oyun boyunca nerede olduğunu gösteren eski hata ayıklama versiyonumun aksine, bu sadece oyuncunun ziyaret ettiği ve bir esinti hissettiği odaları (1) wumpusu (2) veya her ikisini (3) kokladığını gösteriyor. (Oynatıcı bir ok atar ve ıskalarsa, awumpus konum bilgisini içeren değişken sıfırlanır.)

görüntü tanımını buraya girin

ICOSAHEDRON TEMSİLİ

Not: Bu bölüm rev 1'e dayanmaktadır

Benim yıldız özelliğim! Kodumda grafik yok. Nasıl çalıştığını açıklamak için aşağıdaki dünya haritasına bakınız. İkosahedron üzerindeki herhangi bir nokta, 0-3 enlem ve boylam 0-4 (veya tek bir sayı long*4+lat) ile temsil edilebilir . Sıfır enlemli yüzlerin merkezi.

Oyuncunun şu şekilde sembollerle temsil, 3 olası eksenlerde yönlendirilebilir: kuzey-güney -kuzeydoğu-güneybatı \, kuzeybatı-güneydoğu /. Herhangi bir odada, kendisi için mevcut olan bu eksenlerin her birinde bir çıkışa sahiptir. Gösterilen ekranda oynatıcı tam bir saat yönünde döngü yapar. Nereden geldiğini ve dolayısıyla nereye gitmesine izin verildiğini belirten oyuncudan genel olarak anlaşılması kolaydır.

Başlatılmamış göz için biraz zor olan bir vaka dördüncü. Bu kutup sıralarından birinde bir eğik gördüğünüzde, oyuncu eğimin dış ucuna en yakın olan kutupsal hücreden gelmiş ve genel olarak ekvatora doğru bakmaktadır. Böylece oyuncu güneydoğuya bakar ve seçenekleri şunlardır: 15 (GÜNEY, sağdaki hücre) 25 (kuzeydoğu, üstteki hücre) veya 35 (kuzeybatı, aşağıdaki hücre).

Bu nedenle, temel olarak, icosahedron'u 5x4 ızgaraya eşlerim, 19 ila 0 numaralı hücreler basıldıkları sırada eşler. Hareket, oyuncunun enlemine ve yönüne bağlı olarak aşağıdaki tabloya göre mevcut konumdan toplama veya çıkarma yoluyla yapılır.

Eğer oyuncu tahtanın altından (batıdan) dışarı çıkarsa, üst (doğu) tarafa geri döner ve tam tersi olur, bu yüzden pozisyonu modulo 20'ye alınır. P) Aşağıda gösterilen karakterleri veren ham değere, ancak prensibi işlemi etkilemeden 20 katından herhangi biri eklenebilir.

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

Oyuncunun girişi (ikinci basamağı çıkarmak için 10'a bölünmüş) geçerli yönüne eklenir ve yeni yönünü almak için modulo 3 alınır. Bu, çoğu durumda iyi çalışıyor. Ancak kutup odasındaki ve direğe doğru ilerlerken bir sorun var. Aşağıdaki haritayı katlarken, odayı "kuzeydoğuya" doğru bıraktığı takdirde, "güneydoğuya" bakan yeni kareye gireceği için bir düzeltme yapılması gerektiği açıktır. Bu satırda e=(d+i/10)*m[p%4]%3;çarpma ile yapılır m[p%4]. M [] nin ilk dört değeri, yukarıdaki fonksiyonlarına ek olarak, aynı zamanda karakteristik m[1]%3==m[2]%3==1ve m[0]%3==m[3]%3==2. Bu, ekvator odaları için tek başına yön bırakır ve kutup odaları için gerekli düzeltmeyi uygular.

Düzeltme yapmak için mantıksal zaman hamle sonrası olacaktır. Ancak karakterleri kaydetmek için hamle öncesi yapılır. Bu nedenle m [] cinsinden belirli değerler aktarılmalıdır. Bu nedenle, örneğin son 2 karakter yukarıdaki tablo başına LTdeğil TL.

görüntü tanımını buraya girin

UNUTMAYAN KOD

bu rev ​​1 kodudur, rev 2'den daha az karışıktır.

Bu GCC / Linux üzerinde çalışacak. Yorumlara Visual Studio / Windows'ta çalışması için gereken ekstra kodu ekledim. Bu büyük bir fark!

//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!",)
    }

}

SORUNLAR VE CURIOISITIES

@Professorfish tarafından belirtilen noktadan yararlandım, eğer wumpus ve pit rastgele yerlerde başlarsa, oyuncunun rastgele bir yerde başlamasına gerek kalmaz. Oyuncu daima oda 19'da kuzeye bakacak şekilde başlar.

Wumpus'un “çukurdan etkilenmemiş” olması nedeniyle, wumpus'un başlayabileceğini veya çukurun bulunduğu odaya girebildiğini anlıyorum. Genel olarak bu, bir nokta dışındaki şeyleri basitleştirir. Oyunun bittiğini gösteren özel bir değişkenim yok; oyuncu wumpus veya pit ile çakıştığında biter. Bu yüzden oyuncu kazandığında, kazananı belirten mesajı görüntülerim, ancak çukuru oyuncunun dışına çıkarmak için çukuru oynatın! Wumpus orda olabileceği için oyuncuyı çukura koyamıyorum ve istemediğim wumpus hakkında bir mesaj alacağım.

Rev0program görsel stüdyosunda kusursuz bir şekilde çalıştı, ancak IDE çıkışta "i değişkeni etrafında bozuk yığılmış" dedi. Scanf bir koymak için çalışıyor olmasıdır intbir içine char.Dennis bu nedenle onun Linux makine yanlış davranışı bildirildi. Neyse, rev 1'de doğru tip kullanılarak sabitlenir.

Tahtayı rev 0'da gösterme çizgisi sakardır ve diğer platformlarda biraz farklı görünür. Gelen printf(" %c%c%c")orta% c görüntülenen yazdırılabilir karakterdir. Son% c, ASCII 0 veya ASCII 10'dur (\ n, Windows'ta satır başı olan yeni satır.) Windows'ta, konsolda çalışan ve satır başı gelmeden satır aşağı gidecek bir karakter bulunmuyor. Olsaydı ilk c% 'ye (ASCII 0 ya da ASCII 9 sekmesi enlem 1 karakterinden önce ihtiyacım olmazdı. Sekmeler davranışlarında açıkça tanımsızdı.) Baştaki boşluk biçimlendirmeyi geliştirir (enlem 3 ve 2 karakterleri enlem 1 karakterine yaklaştırır) .) Rev 1, \ f formfeed karakteri kullanan ve bu nedenle printf'in başında herhangi bir format karakteri gerektirmeyen bu satırın bir revizyonuna sahiptir. Bu daha kısa yapar, ancak \ f Windows'ta çalışmaz.


1
Yazmayı seviyorum.
Michael Stern

Modifikasyonlar ben (yerine, ilk şunlardır kaldırmak Linux'ta GCC ile derlemeye yapmak zorunda çünkü emin eğer değilim scanf_sile scanfve şunları stdio.hBen C'nin C ++ değerlendirici olarak derlemek varsa), ancak oldukça işi yapmaz ben mi. Örneğin, sola gidersem, sonra sağa dönün ( 15 35), başladığımdan farklı bir
Dennis

@Dennis Çıkışta hatanın kaynağını buldum. Bu, 'i değişkeni etrafındaki yığını bozan' scanf_s (sözde güvenli!), bir karaktere 32 bit bir tamsayı olduğunu varsaymaya çalıştığımda. Bu yüzden önereceğim ilk şey scanf'in "% d" için kullandığı tipi kontrol etmek ve i değişkenini bu tip olarak değiştirmek. Char için doğru cevap w / exit hatası, int için doğru cevap w / o çıkış hatası ve Microsoft tipi ile yanlış cevap __int64 ("% lld" koymadığım sürece uzun süre eşdeğeri.) ungolfed versiyonu ve ekran ile herhangi bir sorun yaşadınız mı?
Seviye River St

@steveverrill: Evet, iki versiyonu da denedim. Türü igerçekten sorun. Adam sayfa diyor ki: " d bir işaretli ondalık tamsayı ile eşleşir; bir sonraki işaretçi bir gösterici olmalıdır int ." Türünü değiştirmek onu iyi çalışır hale getirir.
Dennis,

@steveverrill: VS'in işleri nasıl yürüttüğünü bilmiyorum, ancak GCC ile derlerseniz (C, C ++ değil) çok fazla para tasarrufu yapabilirsiniz. Eğer değiştirirseniz gereklidir içerir hiçbiri NULLile 0ve scanf_sile scanf, sen gerekmez intönce mainve hareket edebilir ive dana dışında (onlar varsayılan intve başlatılır 0). Ayrıca, tanımlayabilirsiniz p=19,h=rand()%p,w=rand()%pdeğiştirin m[]ile *mve tüm örneklerini bir makro tanımlamak mümkün olmalıdır 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

163'ün, kodlanmış dizgilerin karakter sayısından çıkarıldığına dikkat edin. Oda numaralarını gösteren hata ayıklama çıktısı almak istiyorsanız, ilk oluşumundan hemen sonra aşağıdaki satırı ekleyin ^:

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

Örnek bir oturum (ek hata ayıklama çıktısı ile):

  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

İşte ilk çalışma kodu. Biraz daha golf oynamak için daha sonra geliyor.
Howard,

Kodum şu anda 1 karakter daha uzun. Daha fazla golf oynamak için mümkün bir yol arıyorum!
Timtech

Değil yardımıma ihtiyacın ancak tanımlayarak 14 karakter kurtarabilir {puts}:|;değiştirerek, 5 karakter Rve Wbirlikte -ve >veya bırakarak 9 karakter (çevreleyen boşluk ortadan kaldırmak için izin verir) '> 'print(Söz gerektirdiği gibi görünmüyor).
Dennis,

@Dennis Teşekkürler. Kesinlikle bazı önerilerinizi uygulayacağım.
Howard

9

JavaScript (ECMAScript 6) - 2197 1759 -45% = 967.45 Karakterler

Neredeyse bu golf oynamak bitti ...

İkramiye için bir Icosahedral Harita ve Mega-Bats içeren bir GUI içerir.

Wumpus GUI

  • Her odada 4 düğme bulunur: X(Çukur); B(Mega-Bat); W(Wumpus); ve P(Siz).
  • Geçerli konumunuz mavi renktedir.
  • Düğmeleri, temsil ettiği nesne bu konumda ise kırmızı, kesinlikle o konumda değilse yeşil renktedir.
  • WVe Pdüğmeler sadece mevcut konumunuza bitişik odalarda tıklanabilir.
  • Kazanırsanız arka plan yeşile döner ve ölürseniz arka plan kırmızı olur.

Kod:

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)

Kapatma derleyicisini kullanarak ECMA 6 olmadan 1066 elde edersiniz.
AMK,

İşlerin nerede olduğunu çıkarmaya yardımcı olacak grafiksel bir gösterime sahip olmanın ne kadar kolay olacağını merak ediyordum. 1+ ama biraz fazla kolay :)
Sylwester

9

Bash, 365 (ilk çalışan sürüm 726!)

GOLFSCRIPT İLE YAKALAMAK?

@Dennis temelde benim için bütün golf oyunlarını yaptı. Teşekkürler!

Program geçerli bir girdi kabul ediyor. Geçerli giriş, seçtiğiniz yöndür (sağ için 1, sol için 2, arka için 3) ve ardından hareketiniz (4 atış, 5 yürüme).

Bazı açıklama

Normalde büyük ayrıntılı açıklamalar yaparım, ancak bu benim için rahatsız olması için biraz karmaşık.

Dodecahedron grafiğindeki her köşe bir harf olarak kodlanır (a = 1, b = 2, ... t = 20).

Oyuncunun başlangıç ​​pozisyonu her zaman 20'dir (ve sırtı 18'e kadar dururlar), çünkü bu kendi başına önemli değildir, sadece oyuncunun göreceli pozisyonları, pit ve wumpus önemlidir.

Değişken $poyuncunun konumunu saklar. $royuncunun önceki konumunu saklar. $wWumpus ve $h(delik için H) ise çukurdur.

kod

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

Sürüm Geçmişi

  1. İlk sürüm, 698 karakter
  2. "Bir meltem hissediyorsunuz" ve "Wumpus kokusunu alıyorsunuz" aynı anda görüntülenememesi sorunu düzeltildi; rastgele sayı üretme işlevini yaparak 39 karakter kaydetti.
  3. Ateş edersen ve kaçıramazsan, wumpusun hareket ettiğini hatırladım. 726 karakter.
  4. Yapılan grep -oEbir değişken. 5 karakter kurtarıldı.
  5. Yapılan [a-z]{3}bir değişken. 3 karakter kaydedildi.
  6. Yapılan echobir değişken. 5 karakter kurtarıldı.
  7. @Dennis'in önerilerinin çoğunda görev aldı. 72 karakter kaydedildi.
  8. Kalan tüm öneriler eklendi. 68 karakter kaydedildi.
  9. @DigitalTrauma 'nin önerisi üzerine 2 karakter kurtarıldı.
  10. Sadece sağda ise wumpusu vurabileceğiniz önemli bir hata düzeltildi. Aynı karakter sayısı.
  11. Kullanarak 2 karakteri tıraş etmek için parametre genişletme kullanılır $m.
  12. Kazarak grepve biraz daha mantıklı olarak birçok karakterden sıyrılın .
  13. Cİf ifadelerinde kullanmak için bir regexp arama işlevi olarak tanımlanmış ve E"Wumpus'u öldürdünüz" yazıp çıkaran bir işlev olarak tanımlanmıştır.
  14. "If deyimi" düzenlemesi ile 1 karakter kaydedildi.
  15. Kurtularak birçok karakter kurtardı dve gereksiz parantezleri kaldırın.
  16. Sabit hatalar. Çok sayıda karakter eklendi :(
  17. MOARR TASARRUFU ( http://xkcd.com/1296/ )
  18. @Dennis'in fikirlerinden bir diğeri (birkaç kuruş tasarruf) ve kurnazlığım (ab) dolaylı kullanım (1 kuruş tasarruf).
  19. Q () için stil düzeltme.
  20. uygun çıktı yeniden eklendi

Örnek çalışma

"In:" girdi, "Out: çıktı".

Oyuncu bir süreliğine dolaşır, wumpus kokar ve vurur. Özlüyorlar ve wumpus odalarına giriyor ve onları yiyor.

İçinde: 15

İçinde: 15

İçinde: 25

İçinde: 25

İçinde: 15

Dışarı: Wumpus kokusu

İçinde: 14

Out: Kaçırdın

Out: Wumpus seni yedi


1
Kodunuzu en az 100 bayt daha kısa hale getirebileceğinizi düşünüyorum. 1. exitsadece bir bayttan daha uzundur g=1ve sıfır olmayan gve bazı elififadeler için test etme ihtiyacını ortadan kaldırır . 2. ((i==35))yerine [ $i = 35 ]ve ...&&...yerine kullanabilirsiniz if ... then ... fi. 3. q(){ L=({a..s});$j ${L[RANDOM%19]};}ve n=`$k $w$m<<<$d`;w=${n:RANDOM%2+1:1}her ikisi de birkaç byte tasarruf eder.
Dennis,

1
Değiştirin while :;do... doneile for((;;);{... }3 karaktere kadar tasarruf edin
Digital Trauma

1
@professorfish: Bir fonksiyonun mevcut string-grep-cut yaklaşımından daha iyi çalışacağını düşünüyorum. Örneğin, d(){ x=npoemfgnshtoksblbtckpdpljqniorelgfhkbqraicadjaghimsmjtqecrdf;s=${x:3*30#$1-30:3};}sen tanımlarını değiştirmek sağlayacak sve nbirlikte d $pve d $w. Eğer ayrıca tanımlarsanız u=${s#*$r}$s(ve tanımlarını ayarlamak lve fbuna göre), ihtiyacınız olmayacak $kve $martık. Sanırım 83 bayt kurtarır. Ayrıca, boşluk bırakmak q ()gerekli değildir.
Dennis

1
@professorfish: c(){ [[ $1 =~ $2 ]];}Örneğin, sondan ikinci çizgiyi tanımlayıp değiştirerek 3 ilave bayttan tasarruf edebilirsiniz c $r $b||{ $j You missed;d $w;w=${s:RANDOM%2+1:1};}.
Dennis,

1
@professorfish: Önerdiğim işlevi 3 bayt daha kısa tutmalıyım. Sen sonra dört satır değiştirerek 106 ek bayt kaydedebilirsiniz b=$pile d $p;u=u${s#*$r}$s, sonra çizgileri read iile 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};}ve kurtulmak 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];

Sonunda Dennis'in arama masasının versiyonunu yakaladı. Bu sürümle ilgili ilginç olan şey, oda düzeni için bir arama tablosuna sahip olmamasıdır.

Bir İkosahedronun 60 dönme simetri 5 harf, A_5 üzerindeki zaman içinde değişen grubuna izomorfik. Grubu kompakt bir şekilde temsil etmek için her türlü yaklaşımı denedikten sonra, en basitine geri döndüm: her eleman eşitlik için bir permütasyondur. Grup iki jeneratörden birden fazla şekilde oluşturulabilir: Aldığım yaklaşım jeneratörler 3ve kullanır 3 1. Bunlar bize oluşturmasını sağlar 1 = 3 3 1, 2 = 3 3 1 3 1ve 3 = 3.

Bu yönün 32. sıradaki bir öğeye karşılık geldiğine dikkat edin , çünkü arkanızdaki kapıdan geçtikten sonra o kapı tekrar arkanda kalır. Yön 1, icosahedronun bir tepe noktasında dolaşan 5. düzeneğe karşılık gelir. (Benzer şekilde element 2). Ve kombinasyon 3 13. sıradadır, çünkü arkanızda başlayan odaya bitişik odaların etrafında döner.

Bizim yönlendirmeye temsil etmek amacıyla 2'nin bir permütasyon arıyorsanız Yani 3ve yönünü temsil etmek amacıyla 5 bir permütasyon 1böyle 3 1sırayla 3 taşımaktadır.

A_5'te 2. derece 2. derece izin vardır ve her biri için 1(ve dolayısıyla 3 1) 8 aday izin vardır . İçin bariz bir cazibe var [4 3 2 1 0]için 3bir dizi ters adildir: -1%. 3 1Seçtiğim olası eşlik etme izinleri arasında [0 1 3 4 2]ki bu, oldukça kısa bir uygulama kabul ediyor [~@].

Ungolfed

# 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.
];

Güzel cebirsel yaklaşım! Yine de küçük bir hata var: 10/@3%=giriş ise, bir uzunluk dizisinin dördüncü öğesine erişmeye çalışır 35.
Dennis,

@Dennis, evet, yatağa gittikten sonra farkettim. Sabitlemenin çeşitli yollarını düşünebilirim, hepsi maliyete 2.
Peter Taylor

Bir char karakterini geri alabilirsin 9/3%@3%=.
Dennis,

Şu anda biraz daha sert bir yeniden yapılanma ile 7 karakter. Ama hala işe yaramaz 9/yerine 1 karakter, 10/teşekkürler.
Peter Taylor

5

Wumpus , 384 - 129 (karakter) = 255 bayt

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@

Çevrimiçi deneyin! (Elbette, TIO çok fazla anlam ifade etmiyor, çünkü programı orada etkileşimli olarak kullanamıyorsunuz ve program STDIN ile ilgili talimatlar tükendiğinde okur 0 0, buna eşdeğer bir şey olur 3 4, böylece sona erersiniz Wumpus oraya taşınana veya seni öldürene kadar okları vurmak.)

Bunu yerel olarak çalıştırırken, her girişin ikinci sayısından sonra satır beslemesinin temizlendiğinden emin olun (çünkü Wumpus, sayının bittiğini belirlemek için buna ihtiyaç duyar). Powershell'de, bir şekilde satır beslemesinden sonra çalışmasını sağlamak için bir karakter daha girmem gerekiyor (hangi karakterin önemi yok, ancak test için çift satır beslemesini kullandım).

Bunu daha da golf oynamak için çok yer var, ancak tamamen yeni düzen denemek biraz zaman alıyor. Son puan ayrıca kullandığım gerçek dizgelere de çok fazla bağlı. Çünkü 2B dilde bir N bayt dizisi size kaynak kodun N baytından daha fazlaya mal olma eğilimindedir, çünkü kod düzeninde önemli kısıtlamalar vardır ve Birden çok bölüme ayırmanız gerekir (ek çift tırnak işareti). Aşırı sonunda, her dizgiyi tek bir harfe (ve -129'dan -12'ye) düşürürsem, muhtemelen bir ton bayt tasarruf ediyor olurdum.

açıklama

Önce bir uyarı: dilin adı rağmen, bu oldu değil uygulayıcı hale getirmek için tasarlanmış Hunt Wumpus özellikle kolay. Bunun yerine, dili ilk önce üçgenler teması etrafında tasarladım, bir icosahedral veri yapısıyla bitirdim ve bundan dolayı Wumpus olarak adlandırmaya karar verdim.

Bu yüzden evet, Wumpus temel olarak yığın temelli olsa da, aynı zamanda bir icosahedron yüzünün etrafına yerleştirilmiş 20 registerı vardır. Bu, haritayı ücretsiz olarak temsil etmek için bir veri yapısı elde ettiğimiz anlamına gelir. Kolayca yapamayacağımız tek şey, icosahedron'da belirli yüzleri bulmak, bu yüzden onları aramak için, aradığımız yüze ulaşana kadar "d20" yuvarlamamız gerekiyor. (Bunu deterministik bir şekilde yapmak mümkündür, ancak bu çok daha fazla bayt alacaktır.) Bunun gibi yüzleri aramak neredeyse kesin bir şekilde sona ermektedir (yani olasılık 1 ile), bu yüzden sonsuza dek süren arama pratikte bir endişe değildir).

Yukarıdaki kod, bu ilk uygulamanın daha düzenli bir düzenlemeye sahip golf versiyonudur:

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.

Golf oynama düzeni çoğunlukla sıkıştığı için, şu an için bu sürümü açıklayacağım (kodu yeniden yapılandırmanın ötesine geçen herhangi bir golf oyunu ekleyene kadar).

Kurulum koduyla başlayalım:

1SDL2vSD70L?.;;2.

Başlangıçta, tüm yüzler 0 olarak ayarlanır . Karşılık gelen yüzün 1 bitini ayarlayarak wumpusu ve 2 bit'i ayarlayarak çukuru kodlayacağız. Bu şekilde ikisi de aynı odada olabilir. Oyuncunun pozisyonu, icosahedron'da hiç kaydedilmeyecek, bunun yerine daima aktif bir yüz olacaktır (20 kayıttan sadece biri bir anda aktif).

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.

Şimdi oyuncuyu yerleştirmek için rastgele boş bir yüz bulmamız gerekiyor.

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.

Bu sonraki bölüm oyuncunun çevresini kontrol eder ve uygun uyarıları yazdırır:

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

Bu, 3 kez denediğimiz bir döngüdür. Her seferinde, sağ komşuya bakarız, bir tehlike varsa uygun ipleri yazdırır ve sonra icosahedron'u 120 ° döndürür.

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.

Bir sonraki bölüm oyuncudan iki sayı okur ve ardından oynatıcıyı hareket ettirir veya bir ok vurur. Eski önemsiz, ikincisi daha az. Oku çekmek için asıl mesele, özlüyor olduğu durumdur. Bu durumda a) hareket ettirmek için wumpus'u aramaya gitmemiz ve b) oyuncunun odasına ve icosahedron'un doğru oryantasyonuna dönmesi gerekir (böylece "geri" geri "kalır). Bu, tüm programın en pahalı kısmı.

    }&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.

Bu bölümün giriş noktası Isol tarafta.

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.

Phew, bu zor kısmıydı. Şimdi sadece oyuncunun ölüp ölmediğini kontrol etmemiz ve ana döngüden başlamamıza gerek var:

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

Bu bölümün yapısı esasen oyuncunun çevresini kontrol ederken kullandığımız yapı ile aynıdır: mevcut yüzün 1 bitini (oyuncunun odası) kontrol ederiz ve eğer ayarlanmışsa The wumpus ate you.programı yazdırır ve sonlandırırız. Aksi takdirde, 2 bit'i kontrol ederiz You fell into the pit.ve programı yazdırır ve sonlandırırız. Aksi halde 2.ana döngünün başlangıcına (koordinatlarda (0, 2)) atlayana ulaşırız .


1

awk - büyük

Bu, umduğum kadar kısa olmadı, ancak grafikle başa çıkmak için biraz farklı bir yaklaşım benimsedim, bu yüzden zaten ungolfed versiyonunu gönderiyorum.

Oryantasyonu koruyan rotasyonlar altında bir ikosahedronun (20 taraflı polihedron), 5 derece değişken grubuna izomorfik olduğu gerçeğinden (eşit sayıda çift döngülere sahip 5 element permütasyonu) faydalandım. Daha sonra "sol" ve "sağ" olarak döngü uzunluğu 5 olan iki permütasyon seçiyorum ve "geri" olarak döngü uzunluğu 2 olan bir permütasyon seçiyorum. Bunları kullanarak, Hamiltonian yolunu (2xRRRLLLRLRL, her odada 3xRB kullanarak 3 olası yönü yakalamak için) kullanarak grafiği bir odadan oluşturuyorum.

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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.