ハンプスを狩る


39

私が若者だったとき、子供たちはコンピュータ店に迷い込んで、スタッフが私たちを追い出すまでハンプ・ザ・ワンプスをプレイしました。シンプルなゲームで、1970年代半ばの家庭用コンピューターでプログラム可能で、非常に初歩的なもので、ひよこサイズのマイクロプロセッサーではなく、おそらく実際のひよこが入っていたと思います。

ゲームを最新のハードウェアで再現することで、その過ぎ去った時代を呼び起こしましょう。

  1. プレイヤーは、二十面体マップ上のランダムな部屋で開始します(したがって、合計20の部屋があり、20面体の顔のように互いに接続されており、各部屋には正確に3つの出口があります)。

  2. しこりは、ランダムに選択された別の部屋で始まります。しびれが悪臭を放ち、その臭いはその場所に隣接する3つの部屋のいずれかで検出できますが、臭いの方向はプレイヤーが判断することはできません。このゲームでは、「おかしな匂いがする」としか報告されません。

  3. プレイヤーは弓と無数の矢を持ち、いつでも自分の前の部屋に撃つことができます。しわがその部屋にある場合、それは死に、プレイヤーが勝ちます。Wumpusがその部屋になかった場合、驚いたことになり、現在の場所に接続されている3つの部屋のいずれかにランダムに移動します。

  4. ランダムに選択された1つの部屋(プレーヤーが開始する部屋ではないことを保証)には、底なしの穴があります。プレイヤーがピットに隣接する部屋にいる場合、彼はそよ風を感じますが、そよ風がどのドアから来たのかはわかりません。彼が穴のある部屋に入ると、彼は死に、wumpusが勝ちます。くぼみはピットの影響を受けません。

  5. プレイヤーが突風の部屋に足を踏み入れた場合、または突進がプレイヤーの部屋に足を踏み入れた場合、突風が勝ちます。

  6. プレイヤーは自分が向いている方向を数字で指定し(1 =右、2 =左、3 =戻る)、次にアクション(4 =矢を放つ、5 =指定した方向に歩く)を指定します。

  7. スコアリングのために、各ゲーム文字列(「風を感じます」、「こぶを嗅ぐ」、「あなたの矢は何もヒットしませんでした」など)を1バイトと見なすことができます。テキスト内のゲームコードを隠すためにこれを悪用しないでください。これは、プレーヤーと対話するためだけのものです。

  8. メガバットを実装するために、バイトカウントの10%を差し引きます。メガバットは、プレーヤーとは異なるランダムな部屋から始まります(ただし、部屋はwumpusやピットと共有できます)。プレイヤーがコウモリと一緒に部屋に入った場合、コウモリはプレイヤーを別のランダムに選択された部屋に移動させます(ピットまたはその中にあるくぼみのある部屋ではないことを保証します)。コウモリに隣接する3つの部屋では、きしむ音を聞くことができますが、プレーヤーにはどの部屋から音が聞こえるかについての情報は与えられません。

  9. 二十面体マップと、プレイヤーがこれまでに持っているピット、ウンプス、コウモリ(該当する場合)の位置に関する情報の表示を表示するグラフィカルインターフェイスを実装するために、バイトカウントの35%を差し引きますプレーヤー。明らかに、しこりが動くか、プレイヤーがコウモリに動かされた場合、マップはそれに応じてリセットする必要があります。

  10. 調整された最低バイト数が優先されます。

ゲームのバージョンのBASICソースコード(上記のルールに必ずしも準拠しておらず、いずれにしても完全に無制限)は、このWebサイトおよびおそらく他のWebサイトで見つけることができます。


いくつかの明確化:3.突拍がその部屋になかった場合、驚いて3つの部屋の1つに移動します。そして、wumpusは驚いた場合にのみ移動します。6.プレーヤーの進行方向は、来た部屋によって決まります。もし彼が南から来たなら、彼の選択肢は1.northeast 2.northwest 3.southであり、彼が北から来たならそれは反対です。また、あなたのルールは、参照プログラム(まだ詳細に調査していません)よりもシンプル/ゴルファーに見えます。私は正しいですか?
レベルリバーセント14

ああ!私は見つけることができません任意のネット上の正二十面体のどこかの双対グラフの写真を。
ジャックM 14

1
@steveverrillはい、あなたがそれを怖がらせると、それはあなたを殺してしまうかもしれません。あなたがそれを怖がらなければ、動かない。ゲームには多くのバリエーションがあります。多くのバージョンでは、矢印を一周して、あなたを殺すことができます。私はそれを切り取った。
マイケルスターン14

3
@JackM二十面体の面のマップは、十二面体の頂点のマップと同一であり、そのグラフは簡単に見つかります。たとえば、wolframalpha.com / input / ?i = DodecahedralGraph + edgerulesまたは同等のMathematicaコマンドGraphData ["DodecahedralGraph"、 "EdgeRules"]を試してください。いずれにしても、{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}
マイケルスターン14

2
@JackMいいえ、「戻る」とは、あなたが来た道を振り返って戻ることを意味します。「戻る」を2回押すと、開始した場所に戻ります。以前のゲームの状態を保存する必要はありません。
マイケルスターン14

回答:


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])=

スコアは、バイトカウント(290)を取得し、ユーザーとの対話に使用される文字列の数を加算し(6)、これらの文字列の合計長を減算します(133)。改行は文字列の一部であり、バイトカウントに寄与します。

マイルストーン

  1. BashからGolfScriptへprofessorfishの回答を移植しました。スコア:269

  2. コメント内のPeter Taylorの提案に基づいて行動しました。スコア:250

  3. Peter Taylorはコード全体をリファクタリングし、ルックアップテーブルの圧縮を支援しました。スコア:202

  4. 隣接する部屋のルックアップテーブルを数学的なアプローチに置き換えました。スコア:182

  5. 入力、出力、および数学的なアプローチをサポートする関数をリファクタリングしました。スコア:163

大きな「ありがとう」がピーター・テイラーに彼のすべての助けを求めて行きます。

使い方

20個の部屋は12面体の頂点として表され、次のように0から19までの番号が割り当てられています。

十二面体グラフ

部屋Nに隣接する部屋を見つけて時計回りに並べるには、4つのケースを考慮する必要があります。

  • 場合N≡0 MOD 4(青頂点)、隣接する部屋である19 - NN + 2 MOD 20及びN - 2 MOD 20

  • 場合N≡1 MOD 4(緑色頂点)、隣接する部屋である19 - NN - 4 MOD 20N + 4 MOD 20

  • 場合N≡2 MOD 4(黄色の頂点)は、隣接する部屋である19 - NN - 2 MOD 20及びN + 2 MOD 20

  • 場合N≡3 MOD 4(赤頂点)、隣接する部屋であり、19 - NN + 4 MOD 20N - 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”.

1
あなたには1を保存することができますQ19rand 97+; 2 in @with 97%3*&>...、さらに1をinline Qとして{19rand 97+}2*:,\:H、いくつかを|with *に置き換えることで、を行うのが最良の方法ですifB目的を果たさず、スタックを使用することでさらにいくつかの変数を削除できると思います。
ピーターテイラー14

1
別のよくあるトリックに言及するのを忘れました:ルックアップテーブルのベース変換。隣接リストの62文字を、その後に続く33文字の文字列で置き換えることができます256base 20base(また、おそらく+/- 97をいくつか削除します)。唯一の欠点は、印刷できない文字が必要になることです。
ピーターテイラー14

1
より慣用的なGS(主に変数ではなくスタックを使用)にリファクタリングすることで、さらに13を節約ました。さらに、出力の見栄えを悪くする代償として10が追加されます。これは、以前のコメントで言及したルックアップテーブルの圧縮とは異なります。
ピーターテイラー14

1
まったくありませんが、楽しんでいます。ルックアップテーブルアプローチが、私が使用するつもりだったより数学的なアプローチよりもはるかに優れていることに失望しています。ところで、あなたの現在のバージョンには小さなバグがあると思います。矢印を放って、ミスし、部屋に驚ifを驚かせると、矢印が失われていることにYou were killed by the wumpus言及せずに出力されるだけだからです。そういうわけで、私はきれいでないバージョンに追加していました。
ピーターテイラー14

1
2*2+=>)2*
ピーターテイラー

15

REV0 C ++(Windows上の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!");}}

以下はプレイスルーであり、(ハザードのすぐ近くでスタートしない場合)正しいプレイでいつでも勝つことができることを示しています。プレイヤーはそよ風を感じ、背を向け、完全な反時計回りのループを行います。再び微風を感じるのにちょうど5手かかるので、彼は彼の右の穴を知っていて、できるだけ遠くに行きます。同様に、彼が右か左かを知らずに、こぶの臭いがするとき、彼は後ろに戻り、時計回りのループを行います。彼が再びこぶの臭いを嗅ぐのに5回かかるので、彼はそれが左にあることを知っており、確実に撃ちます。

もし彼が他の方法でループしていたなら、彼はすぐにwumpusを見つけ、それが彼が回っていたのと同じ方向にあることを知っていただろう。

ここに画像の説明を入力してください

REV1 C(CygwinのGCC)、431-35%のボーナス= 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!",)}}

明確にするために改行が追加されました。Rev 0からの変更点は次のとおりです。

Windows用Cygwin LinuxエミュレーターでGCCコンパイラーを推奨してくれた@Dennisに感謝します。このコンパイラはincluderev 0プログラムでsを必要とせずint、変数のデフォルトの型を許可します。main.これは人生を変えるゴルフのヒントです!

さらに、Linuxで実行すると\f、キャリッジリターンを行わずにカーソルが下に移動します(Windowsで印刷可能なシンボルを生成するだけの場合とは異なります)。これにより、ボードを印刷するprintfステートメントを大幅に短縮できます。

コメントでデニスからいくつかの追加のヒント、および私自身の1つ:矢印がこぶに当たったかどうかを確認するときの条件の変更:if(q==w)> if(q-w)(..else ..は逆です)

35%のボーナスを獲得するために、プレイヤーがしこり/ワカサギがどこにいるのか/そよ風が感じられる情報を示すグラフィック表示を追加しました。(これの古いデバッグバージョンを削除しました。これは、こぶと穴の正確な位置を示していました。編集履歴で確認できます。)

REV2 C(CygwinのGCC)、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");}

コードをリファクタリングしてくれたデニスに感謝します。

文字定数m[]がリテラルに置き換えられました(リテラルにインデックスを付けることができるとは知りませんでした。)

スタック変数を使用した乱数のシード(システムに依存、一部のシステムはセキュリティ対策としてメモリ割り当てをランダム化します。)

で表示されるメッセージが引数内に配置されたときに実行する必要がある追加のコードと追加のコードでputs置き換えられたマクロ(書式文字列に十分な書式指定子がない場合、printfが最後のいくつかの引数を出力しないという面の利点)と取り換えるprintfprintfif||

新しいマクロ内に配置されたプレーヤー/バンプの新しい位置の計算。

whileループの外側に置かれた勝ち/負けメッセージ。if条件演算子に置き換えられました。

矢を射るための条件付き演算子の使用。プレイヤーがミスした場合、これはメッセージの印刷とwumpus位置の調整の両方を必要とします。デニスは、2つの方法を組み合わせprintfて、しこりの位置を1つの式に計算する方法を提供しましたが、私は自分の方法の1つを使いました。printfは、印刷された文字数を返しますYour arrow didn't hit anything\n。これは31(バイナリ11111)31&Q(w)==Q(w)です。

この編集に対する私の他の貢献は、不必要な括弧の削除です。

出力

ここでは、プレーヤーはすでにWumpusの場所を見つけていますが、徹底的な探索を行って、ピットの場所を正確に見つけようとしています。ゲーム全体でくぼみと穴がどこにあるかを示した私の古いデバッグバージョンとは異なり、これはプレイヤーが訪れ、風を感じた部屋のみを表示します(1)しこりを嗅ぐ(2)または両方(3)。(プレイヤーが矢を放ってミスした場合a、wumpus位置情報を含む変数はリセットされます。)

ここに画像の説明を入力してください

イコサヘドロンの表現

注:このセクションはrev 1に基づいています

私のスター機能!私のコードにはグラフがありません。仕組みを説明するには、以下の世界地図をご覧ください。二十面体上の任意の点は、緯度0〜3および経度0〜4(または単一の数字、long*4+lat。)で表すことができます。緯度がゼロの面の中心。

プレイヤーは、次のように記号で表さ、3つの可能な軸に配向させることができます:南北-北東-南西\、北西-南東/。どの部屋でも、利用可能なこれらの各軸に1つの出口があります。表示されているディスプレイでは、プレーヤーは時計回りに完全なループを作成します。一般的に、プレイヤーがどこから来たのか、したがってどこに行くことができるのかを示すプレイヤーから識別するのは簡単です。

初心者の目には少し難しい1つのケースは、4番目のケースです。これらの極列の1つに傾斜が見られる場合、プレーヤーは傾斜の外側端に最も近い極セルから来ており、一般的に赤道に向かっています。したがって、プレーヤーは南東に面しており、オプションは15(南、右のセル)25(北東、上のセル)または35(北西、下のセル)です。

したがって、基本的には、正二十面体を5x4グリッドにマップし、セルの番号は19から0になります。移動は、下の表に従って、プレイヤーの緯度と方向に応じて、現在の位置に加算または減算することによって行われます。

プレーヤーがボードの下(西)から離れると、彼はトップ(東)側に戻り、その逆も同様です。そのため、位置はモジュロ20になります。通常、動きはascii 80(P)以下に示す文字を与える生の値に、ただし、動作に影響を与えることなく20の倍数を原則として追加できます。

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

プレーヤーの入力(2桁目を削除するために10で除算)が現在の方向に追加され、3を法として新しい方向を取得します。ほとんどの場合、これは正常に機能します。しかし、彼が極地の部屋にいて、極に向かって移動するとき、問題があります。下の地図を折り畳むと、「北東」に面した部屋から出た場合、「南東」に面した新しい広場に入るので、修正する必要があることは明らかです。これはでe=(d+i/10)*m[p%4]%3;乗算することにより行で行われm[p%4]ます。m []の最初の4つの値は、上記の機能に加えて、特性m[1]%3==m[2]%3==1とを持つように選択され m[0]%3==m[3]%3==2ます。これにより、赤道の部屋の方向はそのままになり、極の部屋に必要な修正が適用されます。

修正を行う論理的な時間は、移動後です。ただし、キャラクターを保存するには、移動の前に行われます。したがって、m []の特定の値は転置する必要があります。したがって、最後の2文字は、たとえば上の表のLT代わりにTLなります。

ここに画像の説明を入力してください

独自コード

これはrev 1コードであり、rev 2よりも難読化されていません。

これはGCC / Linuxで実行されます。Visual Studio / Windowsで実行するために必要な追加コードをコメントに含めました。それは大きな違いです!

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

}

問題と好奇心

@professorfishで言及されている点を利用しました。もしこぶと穴がランダムな場所で始まる場合、プレーヤーがランダムな場所で始まる必要はありません。プレーヤーは常に北に面した部屋19で開始します。

私は、こぶが「ピットの影響を受けない」ので、こぶが開始するか、またはピットのある部屋に入ることができることを理解しています。一般に、これは1つの点を除いて物事を単純化します。ゲームが終了したことを示す特定の変数はありません。プレーヤーがうねりや穴と一致したときに終了します。そのため、プレーヤーが勝ったとき、私は勝者のメッセージを表示しますが、ピットをプレーヤーに移動してループから抜け出します!プレイヤーにピットに入れることはできませんが、そこには不思議があり、不必要なメッセージが表示されます。

rev0programはVisual Studioで完全に動作しましたが、IDEは終了時に「変数iの周りでスタックが破損しました」と言いました。scanf関数を入れしようとしているので、これはあるintchar.デニスは、このために彼のLinuxマシン上で不正な動作を報告しました。とにかく、それはrev 1で正しい型を使用することで修正されます。

rev 0でボードを表示するための行は不格好であり、他のプラットフォームでは若干異なります。でprintf(" %c%c%c")、中央%cの表示、印刷可能な文字です。最後の%cはASCII 0またはASCII 10(\ n、Windowsではキャリッジリターン付きの改行)です。Windowsでは、コンソールで動作する文字はないようです。キャリッジリターンを与えずに1行下に移動します。最初のc%(緯度1文字の前のASCII 0またはASCII 9タブ。タブは動作が未定義であることで有名です。)先行スペースによりフォーマットが改善されます(緯度3および2文字が緯度1文字に近くなります) ) Rev 1には、\ fフォームフィード文字を使用するこの行の改訂版があるため、printfの先頭にフォーマット文字は必要ありません。これにより短くなりますが、\ fはWindowsでは機能しません。


1
私は記事が大好きです。
マイケルスターン14

LinuxでGCCでコンパイルするために行った変更が原因かどうかはわかりません(CよりもC ++評価者としてコンパイルする場合は、最初のインクルード、置換scanf_s、インクルードを削除します)が、うまく動作しません私。例えば、右(最初に戻って、その後、私が行く場合を残した)、私は私が始めたものとは別の部屋にいます。scanfstdio.h15 35
デニス・

@Dennis終了時にエラーの原因を追跡しました。これは、scanf_s(おそらく安全です!)が、32ビット整数であると想定しているものをcharに入れようとしたときに「変数iの周りのスタックを破壊する」のです。したがって、最初に提案することは、scanfが "%d"に使用する型を確認し、変数iをその型に変更することです。charの終了エラーなしの正しい答え、intの終了エラーなしの正しい答え、Microsoftタイプ__int64の間違った答え(「%lld」を入れない限り、長いlongに相当)。未使用バージョンで、ディスプレイに問題がありましたか?
レベルリバーセント14

@steveverrill:はい、両方のバージョンを試しました。のタイプiは確かに問題です。manページは言う:「dは、必要に応じて符号付き10進数の整数に対応する次のポインタはへのポインタである必要がありint型。」タイプを変更すると、問題なく機能します。
デニス14

@steveverrill:VSがどのように処理するかわかりませんが、GCC(C ++ではなくC)でコンパイルすると、多くの文字を節約できます。あなたが交換した場合含まれるのどれもが必要とされていないNULL0してscanf_sscanf、あなたは必要としないint前にmain、あなたが移動することができますiし、d(それらがデフォルトのメインの外側intとに初期化されます0)。また、を定義p=19,h=rand()%p,w=rand()%p、置換m[]*mおよびのすべてのインスタンスに対してマクロを定義できる必要がありif(...==...)puts(...);ます。
デニス14

9

GolfScript、269文字

{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が減算されたことに注意してください。部屋番号を示すデバッグ出力が必要な場合は、最初に発生した直後に次の行を追加します^

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

セッションの例(追加のデバッグ出力付き):

  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

これが最初の作業コードです。さらにゴルフをするために後で戻ってきます。
ハワード14

私のコードは現在1文字長くなっています。さらにゴルフをする方法を探しています!
ティムテック14

あなたは私の助けを必要としますが、定義することで、14個の文字を保存することができないことを{puts}:|;、置き換えることにより、5つの文字RW->ドロップすることにより、(周囲のスペースを排除することができます)と9つの文字'> 'print(質問で要求されていないようです)。
デニス14

@Dennisありがとう。あなたの提案のいくつかを確実に実装します。
ハワード14

9

JavaScript(ECMAスクリプト6) - 2197 1759 -45%= 967.45文字

このゴルフをほぼ終了しました...

完全なボーナスのために、20面体マップとメガバットを備えたGUIが含まれています。

Wumpus GUI

  • 各部屋には4つのボタンがあります:(Xピット); B(メガバット); W(Wumpus); そしてP(あなた)。
  • 現在の場所は青で表示されます。
  • ボタンは、それが表すオブジェクトがその場所にある可能性がある場合は赤、その場所に間違いがある場合は緑になります。
  • WそしてPボタンは、あなたの現在の場所に隣接した部屋でクリックすることができます。
  • 背景に勝つと緑に変わり、死ぬと背景が赤に変わります。

コード:

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)

クロージャコンパイラを使用すると、ECMA 6なしで1066が得られます。
AMK

私は、物事がどこにあるのかを推測するのに役立つグラフィカルな表現があると、どれほど簡単になるのだろうと思っていました。1+ですが、やや簡単すぎます:)
シルウェスター

9

Bash、365(最初の作業バージョン726!)

ゴルフスクリプトで追いつきますか?

@Dennisは基本的にすべてのゴルフをやってくれました。ありがとう!

プログラムは有効な入力を想定しています。有効な入力は、選択した方向(右に1、左に2、後ろに3)とそれに続くアクション(4が撃つ、5が歩く)です。

いくつかの説明

私は通常、大きな詳細な説明をしますが、これはおそらく私が煩わされるには少し複雑すぎます。

12面体グラフの各頂点は、文字(a = 1、b = 2、... t = 20)としてエンコードされます。

プレーヤーの開始位置は常に20です(そして、彼らは18に戻って立っています)。それはそれ自体は問題ではなく、プレーヤー、ピット、およびバンプの相対的な位置だけが問題になるからです。

変数 $pは、プレーヤーの場所が格納されます。$rプレイヤーの以前の場所を保存します。$wはこぶで、$h(穴の場合はH)は穴です。

コード

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

バージョン履歴

  1. 初期リリース、698文字
  2. 「風を感じている」と「こぶの臭いがする」を同時に表示できないバグを修正しました。乱数生成を機能にすることで39文字を節約しました。
  3. あなたが撃って逃した場合、こぶが動くことを思い出した。726文字。
  4. メイドgrep -oE変数を。5文字を保存しました。
  5. メイド[a-z]{3}変数を。3文字を保存しました。
  6. メイドecho変数を。5文字を保存しました。
  7. @Dennisの提案のほとんどに基づいて行動しました。72文字を保存しました。
  8. 残りのすべての提案を追加しました。68文字を保存しました。
  9. @DigitalTraumaの提案から2文字を保存しました。
  10. wumpusが右側にある場合にのみ撃つことができる主要なバグを修正しました。同じ文字数。
  11. パラメータ拡張を使用して、を使用して2文字を削除しました$m
  12. 溝を掘りgrep、少し賢くすることで、多くのチャーを剃り落としました。
  13. Cifステートメントで使用する正規表現検索関数として定義され、E「You can killed the wumpus」を出力して終了する関数として定義されます。
  14. 「ifステートメント」の再配置により1文字を保存しました。
  15. を取り除くことで多くの文字を保存し、d不要な括弧を削除しました。
  16. バグを修正。多くの文字を追加:(
  17. MOARRの節約(http://xkcd.com/1296/
  18. @Dennisの別のアイデア(いくつかの文字を節約する)と、私のmyな(ab)インダイレクションの使用(1文字を節約する)。
  19. q()のスタイル修正。
  20. 適切な出力を再追加しました

サンプル実行

「In:」は入力、「Out:は出力」です。

プレイヤーは少し歩き回り、こぶの匂いを嗅いで撃ちます。彼らは見逃し、しびれが部屋に入り込んで食べます。

で:15

で:15

で:25

で:25

で:15

Out:あなたはwumpusのにおいがします

で:14

アウト:あなたが逃した

Out:Wumpusはあなたを食べました


1
コードを少なくとも100バイト短くできると思います。1. exitは1バイトだけ長く、g=1非ゼロgおよびいくつかのelifステートメントをテストする必要がなくなります。2.の((i==35))代わりに[ $i = 35 ]およびの...&&...代わりに使用できますif ... then ... fi。3. q(){ L=({a..s});$j ${L[RANDOM%19]};}そして、n=`$k $w$m<<<$d`;w=${n:RANDOM%2+1:1}両方とも数バイトを節約します。
デニス14

1
while :;do... donefor((;;);{...に置き換え}て、3文字を節約します
デジタル外傷14

1
@professorfish:関数は、現在のstring-grep-cutアプローチよりもうまく機能すると思います。たとえば、d(){ x=npoemfgnshtoksblbtckpdpljqniorelgfhkbqraicadjaghimsmjtqecrdf;s=${x:3*30#$1-30:3};}あなたがの定義置き換えることを可能にするsnしてd $pとしd $w。さらに定義するu=${s#*$r}$s(そしてlfそれに応じて定義を調整する)場合、必要はなく$kなり$mます。83バイト節約できると思います。また、スペースq ()は不要です。
デニス14

1
@professorfish:そしてc(){ [[ $1 =~ $2 ]];}、たとえば2番目から最後の行をで定義して置き換えることにより、さらに3バイトを節約できますc $r $b||{ $j You missed;d $w;w=${s:RANDOM%2+1:1};}
デニス14

1
@professorfish:私が提案した関数の使用は3バイト短くする必要があります。あなたは後に4本の線を置き換えることにより、106の追加バイトを保存することができますb=$pd $p;u=u${s#*$r}$s、後の行read iy=${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};}とを取り払いますE()
デニス14

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

最後に、デニスのルックアップテーブルバージョンに追いつきました。このバージョンの興味深い点は、部屋のレイアウト用のルックアップテーブルがないことです。

二十面体60個の回転対称性は、 5文字A_5の交互グループと同型です。グループをコンパクトに表現するためのあらゆる種類のアプローチを試した後、最も単純な方法に戻りました。各要素は偶数パリティの順列です。グループは、2つのジェネレーターから複数の方法で生成できます。私が取っているアプローチでは、ジェネレーター3とを使用し3 1ます。これらは、私たちが生成することができ1 = 3 3 12 = 3 3 1 3 13 = 3

その方向3は2 番目の要素に対応していることに注意してください。なぜなら、あなたの後ろのドアを通過した後、そのドアは再びあなたの後ろにあるからです。方向1は、正二十面体の頂点を歩く5次の要素に対応します。(同様に要素2)。そして、組み合わせ3 1は3番目で、あなたの後ろから始まる部屋に隣接する部屋を巡回します。

そこで、方向2 3の順列と方向3の1ような方向を表す順5の順列を探しています3 1

A_5には次数2の順列が15個あり、それぞれに1(したがって3 1)の8個の候補順列があります。[4 3 2 1 0]forには明らかな魅力があります。3配列の反転はただ-1%です。3 1私が選んだ可能な仲間の順列のうち[0 1 3 4 2]、かなり短い実装を認める[~@]

非ゴルフ

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

素敵な代数的アプローチ!ただし、小さなバグが10/@3%=あり35ます。入力がの場合、長さ3の配列の4番目の要素にアクセスしようとします。
デニス14

@デニス、はい、私は寝た後に気づきました。私はすべての原価計算2.、それを固定する様々な方法を考えることができます
ピーター・テイラー

で1つの文字を取得できます9/3%@3%=
デニス14

私は現在、いくつかのより抜本的な再編を行っている7文字です。しかし、その1文字の9/代わりに10/まだ動作するので、ありがとう。
ピーターテイラー14

5

Wumpus384-129(文字列)= 255バイト

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@

オンラインでお試しください!(もちろん、TIOはあまり意味がありません。そこでプログラムを対話的に使用することはできません。STDINの命令がなくなると、プログラムはを読み取ります0 0。これはに相当し3 4ます。 Wumpusがそこに移動するか、あなたを殺すまで矢を放ちます。)

これをローカルで実行するときは、各入力の2番目の数字の後の改行がフラッシュされることを確認してください(Wumpusは数字が終わったことを判断するために必要です)。Powershellでは、ラインフィードの後に​​もう1文字入力する必要があります(どの文字でもかまいませんが、テストにはダブルラインフィードを使用しました)。

これをさらにゴルフする余地はたくさんありますが、完全に新しいレイアウトを試すには時間がかかります。最終スコアは、使用する実際の文字列にも大きく依存します。2D言語では、Nバイトの文字列はNバイトのソースコードよりもコストがかかる傾向があるためです。複数のセクションに分割する必要があります(追加の二重引用符が必要です)。極端な場合、すべての文字列を1文字(および-129〜-12)に減らすと、おそらく1トンのバイトを節約できます。

説明

最初の免責事項:言語の名前にもかかわらず、ハンプ・ザ・ワンプスの実装を特に簡単にするように設計されていません。代わりに、私は最初に三角形をテーマに言語を設計し、二十面体のデータ構造になり、そのためWumpusと呼ぶことにしました。

そのため、Wumpusは主にスタックベースですが、20面体の面の周りに配置された20個のレジスタもあります。つまり、地図を無料で表すためのデータ構造を取得します。簡単にできないのは、20面体の特定の顔を見つけることだけです。そのため、それらを検索するには、探している顔が見つかるまで「d20を転がす」必要があります。(決定論的な方法でこれを行うことは可能ですが、それはより多くのバイトを必要とします。)このような顔の検索はほぼ確実に終了します(つまり、確率1)。

上記のコードは、sanerレイアウトを使用したこの最初の実装のゴルフバージョンです。

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.

ゴルフは主にレイアウトの圧縮を伴うため、ここではこのバージョンについて説明します(コードの再構築を超えるゴルフトリックを追加するまで)。

セットアップコードから始めましょう。

1SDL2vSD70L?.;;2.

最初は、すべての面が0に設定されています。対応するフェースの1ビットを設定してwumpusをエンコードし、2ビットを設定してピットをエンコードします。このように、両方を同じ部屋に置くことができます。プレイヤーの位置は二十面体にまったく記録されず、代わりに常にアクティブな顔になります(一度にアクティブになるのは20のレジスタのうち1つだけです)。

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.

ここで、プレイヤーを入れるランダムな空の顔を見つける必要があります。

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.

次のセクションでは、プレーヤーの周囲をチェックし、適切な警告を出力します。

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

これは3回実行されるループです。毎回、右の隣人を見て、ハザードがある場合は適切な文字列を印刷してから、20面体を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.

次のセクションでは、プレーヤーから2つの数字を読み取り、プレーヤーを移動するか、矢印を撃ちます。前者は取るに足らないものであり、後者はそれほど重要ではありません。矢を射るための主な問題は、それが逃した場合です。その場合には、我々は)それを移動するwumpusのを探して行く必要があり、その後、b)は、プレイヤーの部屋に戻る、二十面体の正しい向き(「バック」は「バック」のままそうということ)。これは、プログラム全体の中で最も高価な部分です。

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

このセクションへのエントリポイントIは左側にあります。

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.

それは難しい部分でした。ここで、プレーヤーが死ぬかどうかを確認する必要があります。そうでなければ、メインループからやり直します。

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

このセクションの構造は、プレーヤーの周囲を確認するときに使用した構造と基本的に同じです。現在の顔(プレーヤーの部屋)の1ビットを確認し、設定されている場合The wumpus ate you.はプログラムを印刷して終了します。それ以外の場合は、2ビットをチェックしYou fell into the pit.、プログラムを印刷して終了するように設定します。それ以外の場合は2.、メインループの先頭に(座標で(0, 2))ジャンプして戻ります。


1

awk-大きい

これは思ったほど短くはなりませんでしたが、グラフを扱う方法が少し異なるため、とにかく未公開版を投稿しています。

私は、方向を維持する回転の下での20面体(20面多面体)が5次の交互グループ(同数の偶数の長さのサイクルを持つ5要素の順列)と同型であることを利用しました。次に、「左」と「右」としてサイクル長5の2つの順列を選択し、「戻る」としてサイクル長2の1つの順列を選択します。これらを使用して、ハミルトニアンパスを歩いて1つの部屋からグラフを作成します(2xRRRLLLRLRL、各部屋で3xRBを使用して3つの可能な方向をキャプチャします)。

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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.