追捕W


39

当我还是个小伙子的时候,孩子们会逛到电脑商店玩“狩猎泵车”,直到员工把我们赶出去。这是一个简单的游戏,可以在1970年代中期的家用计算机上进行编程,其设备非常初级,因此我认为其中有些可能不是真正的小鸡,而不是小鸡大小的微处理器。

让我们通过在现代硬件上重现游戏来唤起过去的时代。

  1. 玩家从二十面体地图上的一个随机房间开始(因此,总共有20个房间,像二十面体的面孔一样相互连接,每个房间正好有三个出口)。

  2. 乌贼开始于随机选择的不同房间。尽管玩家无法确定气味的方向,但在与其位置相邻的三个房间中的任何一个房间中,都可以检测到汗味和气味。游戏仅报告“您闻到了臭味”。

  3. 玩家携带弓箭和无数箭矢,他可以随时向自己前方的房间射击。如果wumpus在那个房间里,它就会死亡并且玩家获胜。如果wumpus不在那个房间中,它会被吓住并随机进入连接到其当前位置的三个房间中的任何一个。

  4. 一个随机选择的房间(保证不是玩家开始的房间)包含一个无底洞。如果玩家在维修区附近的任何房间中,他都会感到微风,但不知道微风来自哪个门。如果他带着小坑走进房间,他就会死去,而小熊赢了。臀部不受坑的影响。

  5. 如果玩家走进wumpus的房间,或者如果wumpus走进玩家的房间,则wumpus获胜。

  6. 玩家使用数字指定面对的方向(1 =右,2 =左,3 =向后),然后进行一个动作(4 =射箭,5 =沿指定方向行走)。

  7. 为了得分,可以将每个游戏字符串(“您感到微风”,“闻到汗味”,“您的箭没有击中任何东西”,等等)视为一个字节。不要滥用此功能将游戏代码隐藏在文本中;这只是为了与玩家互动。

  8. 减去megabat的字节数的10%,以实施megabat,它始于与玩家不同的随机房间(尽管它们可以与wumpus和/或pit共享一个房间)。如果玩家带着蝙蝠走进房间,蝙蝠将把玩家带到另一个随机选择的房间(保证不是房间里有坑或小熊),然后飞到自己的新的随机位置。在与蝙蝠相邻的三个房间中,可以听到它们吱吱作响的声音,但是不会向玩家提供声音来自哪个房间的信息。

  9. 减去35%的字节数即可实现图形界面,以显示二十面体地图,以及有关玩家迄今为止所掌握的有关坑,腹肌和蝙蝠(如果适用)位置的信息的某种指示玩家。显然,如果腹部移动或玩家被蝙蝠移动,则地图需要相应地重置。

  10. 调整后的最低字节数为准。

可以在此网站以及其他网站上找到该游戏版本的BASIC源代码(不一定符合上述规则,并且在任何情况下完全不符合要求)。


一些澄清:3.如果wumpus不在那个房间,它会被吓到并移动到三个房间之一。.因此,如果您发射箭而错过,wumpus可能会杀了您,对吗?而且,只有惊呆了,蠕动才会动,否则它会保持原状吗?6.我知道玩家的前进方向取决于他所在的房间。因此,如果他来自南方,那么他的选择将是1.东北2.西北3.南方。如果他来自北方,则相反。另外,您的规则似乎比参考程序更简单/更实用(我尚未详细调查该参考程序。)我是否正确?
级圣河

啊!我在网上的任何地方都找不到二十面体的对偶图的任何图片。
杰克M

1
@steveverrill是的,如果您惊吓了它,它可能会杀死您。如果您不惊吓它,它就不会移动。游戏中有很多变化;例如,许多版本都允许箭头盘旋并杀死您。我已经解决了。
迈克尔·斯特恩

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}
迈克尔·斯特恩

2
@JackM不,“后退”意味着转身并向后退。如果您两次单击“后退”,则最终会从起点开始。无需存储较早的游戏状态。
2014年

Answers:


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将Professorfish 的答案移植到GolfScript。得分:269

  2. 根据评论中Peter Taylor的建议采取行动。得分:250

  3. Peter Taylor 重构了我的整个代码,并帮助我压缩了查询表。得分:202

  4. 用数学方法代替了相邻房间的查找表。得分:182

  5. 重构的输入,输出和支持数学方法的函数。得分:163

彼得·泰勒(Peter Taylor)表示了极大的“感谢!”。

这个怎么运作

20个房间表示为十二面体的顶点,已按以下方式分配了从0到19的数字:

十二面体图

要查找与N号房间相邻的房间并按顺时针顺序对其进行排序,我们必须考虑以下四种情况:

  • 如果N≡0 mod 4(蓝色顶点),则相邻房间为19-NN + 2 mod 20N-2 mod 20

  • 如果N≡1 mod 4(绿色顶点),则相邻房间为19-NN-4 mod 20N + 4 mod 20

  • 如果N≡2 mod 4(黄色顶点),则相邻房间为19-NN-2 mod 20N + 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 @97%3*&>...,再由1内嵌Q{19rand 97+}2*:,\:H更换,一些|*,这往往是做一个最好的办法ifB没有用,我认为可以通过使用堆栈来消除更多的变量。
彼得·泰勒

1
忘记提及另一个常见的技巧:查找表的基本转换。您可以将33个字符的字符串替换为邻接列表中的62个字符256base 20base(并可能消除一些+/- 97)。唯一的缺点是它将需要不可打印的字符。
彼得·泰勒

1
通过重构为更惯用的GS(主要使用堆栈而不是变量),我又节省了13个。还有另外十个以降低输出的美观为代价。这与我之前的评论中提到的查找表压缩不同。
彼得·泰勒

1
一点也不,我很喜欢。我只是感到失望的是,查找表方法比我打算使用的更数学的方法好得多。顺便说一句,我认为您当前的版本有一个小错误,因为如果您发射箭头,错过箭头并让乌鸦吓到您的房间,那么它只会输出You were killed by the wumpus而没有提及箭头。这就是为什么我要添加非漂亮版本。
彼得·泰勒

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步才能再次闻到臭味,所以他知道它在左边,并且确定地射击。

如果他以另一种方式循环,他会更快地找到昏迷,并且知道这与他转弯的方向相同。

在此处输入图片说明

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

为清楚起见添加了换行符。从修订版0开始的更改如下:

@Dennis非常感谢您在Windows的Cygwin Linux模拟器上推荐GCC编译器。该编译器不需要includerev 0程序中的s,它允许int变量使用默认类型,main.这是改变生活的高尔夫技巧!

此外,在Linux中运行还意味着\f确实会导致光标向下移动而不执行回车符(与Windows中仅产生可打印符号的情况不同)。这已大大缩短了打印板的printf语句。

丹尼斯(Dennis)在评论中提供了其他一些提示,这也是我自己的提示之一:检查箭头是否碰到腹部时的状态改变:if(q==w)> if(q-w)(..else ..颠倒了)

额外的图形显示可显示玩家知道的有关在哪里炼金的信息/感觉轻而易举地获得35%的奖励。(我删除了旧的调试版本,该版本显示了wumpus和孔的确切位置。可以在编辑历史记录中看到。)

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

再次感谢Dennis重构了我的代码:

Char常量m[]替换为文字(我不知道您可以为文字编制索引。)

使用堆栈变量播种随机数(取决于系统,某些系统将内存分配随机化作为一种​​安全措施。)

当显示的消息放在参数内部时,必须将宏puts替换为带有的宏,printf并带有附加代码printf(在格式字符串中没有足够的格式说明符的情况下,printf不会打印最后几个参数)这是必须采取的措施。)if取而代之||

计算放置在新宏中的玩家/ wumpus的新位置。

赢/输消息放在while循环外。if由条件运算符代替。

在行中使用条件运算符来拍摄箭头。如果玩家错过了比赛,则需要打印一条消息并调整wumpus的位置。丹尼斯(Dennis)提供了几种组合方式以及将printfwumpus位置计算成一个表达式的方法,但是我已经放弃了自己的方法。printf返回打印的字符数,其Your arrow didn't hit anything\n值为31(二进制11111)31&Q(w)==Q(w)

我对此编辑的其他贡献是消除了一些不必要的括号。

输出量

玩家已经在这里找到了Wumpus的位置,但他选择进行彻底的探索以找出坑的确切位置。不像我以前的调试版本那样,在整个游戏中都显示了坑洼和坑洞,而这只显示了玩家曾参观并感到微风(1)熔化坑洼(2)或两者兼有(3)的房间。(如果玩家a射箭而未击中,则包含wumpus位置信息的变量将被重置。)

在此处输入图片说明

二十面体代表

注意:本节基于版本1

我的明星特色!我的代码中没有图形。要说明其工作原理,请参见下面的世界地图。二十面体上的任何点都可以由纬度0-3和经度0-4(或单个数字,long*4+lat。)表示。地图上标记的经度线仅穿过那些经度为零的面,而纬度线则通过纬度为零的脸部中心。

玩家可以在3个可能的轴上定向,用以下符号表示:北-北-东北-西南\西北-东南/。在任何给定的房间中,他在每个可用轴上都只有一个出口。在显示的显示中,播放器完成一个完整的顺时针循环。通常,很容易从玩家身上识别出他来自何处,并因此允许他去哪里。

对于初学者来说有点困难的一种情况是第四种。当您在这些极坐标行之一中看到一个斜率时,播放器来自最靠近该斜率外端的极坐标单元,并且通常面向赤道。因此,玩家面对东南,他的选择是:15(SOUTH,右边的单元格)25(northEAST,上面的单元格)或35(northWEST,下面的单元格)。

因此,基本上,我将二十面体映射到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

玩家的输入(被10除以除去第二个数字)被添加到他的当前方向,并取模3以得到他的新方向。在大多数情况下,这都可以正常工作。但是,当他在极地室内并向杆子方向移动时会出现问题。折叠下面的地图时,很明显,如果他离开面向“东北”的房间,他将进入面向“东南”的新正方形,因此必须进行更正。这是e=(d+i/10)*m[p%4]%3;通过乘以来完成的m[p%4]。选择m []的前四个值,以便除了上面的函数外,它们还具有m[1]%3==m[2]%3==1和的特性 m[0]%3==m[3]%3==2。这将方向留给赤道房间,并对极地房间进行必要的校正。

进行校正的逻辑时间是在移动之后。但是,要保存字符,必须在移动之前完成。因此,必须对m []中的某些值进行转置。因此,例如,上面的表LT不是最后2个字符TL

在此处输入图片说明

取消代码

这是1版代码,比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提到的观点,如果wumpus和pit在随机的地方开始,那么玩家就不需要在随机的地方开始。玩家总是从面向北的房间19开始。

我了解,由于wumpus不受“坑的影响”,因此wumpus可以开始进入或进入坑所在的房间。总的来说,这简化了一点。我没有具体的变量来表明游戏已经结束;当玩家与乌鸦或坑重合时结束。因此,当玩家获胜时,我会显示获胜消息,但将维修区移至玩家以跳出循环!我无法将玩家放进维修区,因为可能有wumpus,我会收到有关我不想要的wumpus的消息。

rev0程序在Visual Studio中运行完美,但是IDE在退出时说“变量i周围的堆栈损坏”。这是因为scanf函数正试图把一个intchar.丹尼斯报道了他的Linux机器上,因为这种不正确的行为。无论如何,通过在修订版1中使用正确的类型来修复它。

在rev 0中显示木板的那行很笨拙,在其他平台上看起来略有不同。在printf(" %c%c%c")中间%c是显示的可打印字符。最后一个%c是ASCII 0或ASCII 10(\ n,在Windows中为带回车符的换行符。)在Windows中,似乎没有可在控制台中使用的字符,它将下降一行而不给出回车符。如果有的话,我不需要第一个c%(纬度1字符之前的ASCII 0或ASCII 9制表符。众所周知,制表符的行为未定义。)前导空格可改善格式设置(将纬度3和2字符放入更接近纬度1字符) 修订版1对此行进行了修订,该行使用\ f换页符,因此在printf的开头不需要格式字符。这使它更短,但是\ f在Windows中不起作用。


1
我喜欢这篇文章。
Michael Stern 2014年

我不确定这是否是因为我必须进行修改才能在Linux上使用GCC进行编译(删除第一个include,如果我以C ++而不是C的身份进行编译,请替换scanf_sscanfinclude stdio.h),但是它不适用于我。例如,我向左,然后回到正确的开头(15 35),我在不同的房间比我在开始的人。
丹尼斯

@Dennis我已经跟踪了退出时错误的来源。它是scanf_s(据说很安全!),当它试图将我认为是32位整数的字符放入char中时,它“破坏了变量i周围的堆栈”。因此,我建议的第一件事是检查scanf用于“%d”的类型,并将变量i更改为该类型。我得到正确的答案w /退出错误为char,正确的答案w / o退出错误为int,以及Microsoft类型__int64的错误答案(等同于long long,除非我输入“%lld”。)非高尔夫版本,您的显示器有问题吗?
水平河圣

@steveverrill:是的,我尝试过两个版本。问题的类型i确实是问题。该男子页说:“ d匹配是一个符号十进制整数; next指针必须是一个指向INT ”。更改类型可以使其正常工作。
丹尼斯

@steveverrill:我不知道VS如何处理事情,但是如果您使用GCC(作为C而不是C ++)进行编译,则可以节省很多字符。的包括如果更换需要无NULL0scanf_sscanf,你不需要int之前main,你可以移动id主外(它们默认int并初始化0)。另外,您可以定义p=19,h=rand()%p,w=rand()%p,替换m[]*m,并且应该可以为的所有实例定义一个宏if(...==...)puts(...);
丹尼斯

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

这是第一个工作代码。稍后再回来打高尔夫球。
霍华德

我的代码当前长1个字符。我正在寻找进一步打高尔夫球的任何可能的方式!
Timtech

并不是您需要我的帮助,但是您可以通过定义来节省14 {puts}:|;个字符,用R和替换W->(允许消除周围的空间)可以节省5个字符,而通过删除可以节省9个字符'> 'print(问题似乎不是必需的)。
丹尼斯

@丹尼斯,谢谢。我一定会执行您的一些建议。
霍华德

9

的JavaScript(ECMAScript的6) - 2197 1759 -45%= 967.45字符

打高尔夫球几乎完成了...

包括带有二十面体地图的GUI和Mega-Bat,可获取全部奖金。

Wumpus GUI

  • 每个房间有4个按钮:(X坑);B(巨型蝙蝠);W(Wumpus);和P(您)。
  • 您当前的位置显示为蓝色。
  • 如果按钮所代表的对象可能在该位置,则按钮将显示为红色;如果按钮绝对不在该位置,则按钮将显示为绿色。
  • WP按钮可以单击只在靠近您的当前位置的房间。
  • 如果赢了,背景变成绿色,如果死了,背景变成红色。

码:

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 2014年

我想知道,如果您有图形表示形式来帮助推断事物的位置,那么会容易得多。1+,但是有点太简单了:)
Sylwester 2014年

9

Bash 365(第一个工作版本726!)

赶上高尔夫吗?

@Dennis基本上已经为我完成了所有打高尔夫球。谢谢!

该程序假定输入有效。有效输入是您选择的方向(1代表右,2代表左,3代表向后),然后是您的动作(4代表射击,5代表行走)。

一些解释

我通常会做大量详细的解释,但这对于我来说可能太复杂了。

十二面体图上的每个顶点都被编码为一个字母(a = 1,b = 2,... t = 20)。

玩家的起始位置始终为20(他们的后背站立到18),因为这本身并不重要,所以仅玩家,基坑和臀部的相对位置很重要。

该变量$p存储玩家的位置。$r存储玩家的先前位置。$w是wumpus,$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. 修复了一个重大错误,该错误仅在右侧时才可以拍摄。相同的字符数。
  11. 使用参数扩展功能使用刮除2个字符$m
  12. 抛弃许多杂物grep,变得更明智。
  13. 定义C为在if语句中使用的正则表达式搜索功能,并E定义为打印“您杀死了wumpus”并退出的功能。
  14. 通过“ if语句”重排保存了1个字符。
  15. 通过消除节省了大量字符d,并删除了不必要的括号。
  16. 修正错误。增加了很多字符:(
  17. MOARR节省(http://xkcd.com/1296/
  18. @Dennis的另一个想法(节省了几个字符),以及我狡猾(滥用)的间接使用方式(节省了1个字符)。
  19. q()的样式修复。
  20. 重新添加适当的输出

样品运行

输入“输入:”,“输出:输出”。

玩家徘徊了一下,闻到了臭味,然后射击。他们想念,而乌鸦进入他们的房间吃饭。

在:15

在:15

在:25

在:25

在:15

出:你闻到了乌贼味

在:14

出:您错过了

出:乌鸦吃了你


1
我认为您可以使代码至少短100个字节。1. exit仅比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}都节省了几个字节。
丹尼斯

1
更换while :;do... donefor((;;);{... }的3字符储蓄
数字创伤

1
@professorfish:我认为一个函数会比当前的string-grep-cut方法更好。例如,d(){ x=npoemfgnshtoksblbtckpdpljqniorelgfhkbqraicadjaghimsmjtqecrdf;s=${x:3*30#$1-30:3};}可以让您更换的定义s,并nd $pd $w。如果您还定义u=${s#*$r}$s(和调整的定义lf相应的),你就不需要$k$m了。我认为可以节省83个字节。另外,q ()不需要空格。
丹尼斯

1
@professorfish:并且可以通过定义c(){ [[ $1 =~ $2 ]];}和替换(例如倒数第二行)来节省3个额外的字节c $r $b||{ $j You missed;d $w;w=${s:RANDOM%2+1:1};}
丹尼斯

1
@professorfish:使用我建议的功能应缩短3个字节。您可以通过替换b=$pwith d $p;u=u${s#*$r}$s之后的四行,read iwith 之后的行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};}并删除掉它们来节省106个额外的字节E()
丹尼斯

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

最终赶上了Dennis的查找表版本,从中借用了很多内容。这个版本的有趣之处在于它没有用于房间布局的查找表。

二十面体60个旋转对称与 5个字母A_5上的交替基团同构。在尝试了各种方法来紧凑地表示组之后,我回到最简单的方法:每个元素都是偶数奇偶校验的排列。该组可以通过两种以上的方式由两个生成器生成:我采用的方法是使用生成器33 1。这些使我们能够产生1 = 3 3 12 = 3 3 1 3 13 = 3

观察到该方向3对应于第2阶元素,因为在经过您身后的门之后,该门又在您身后。方向1对应于5阶元素,绕二十面体的顶点走动。(类似元素2)。组合3 1的阶数为3,因为它在围绕着您的房间开始的房间周围循环。

因此,我们正在寻找2阶的排列来表示方向,3并寻找5阶的排列来表示方向,1使得其3 1为3阶。

A_5中有15个2阶置换,每个置换有8个候选置换1(因此3 1)。这里有一个明显的吸引力[4 3 2 1 0]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%=如果输入为,则尝试访问长度为3的数组的第四个元素35
丹尼斯

@丹尼斯,是的,我意识到我上床睡觉了。我能想到的修复它的各种方式,所有花费2
彼得·泰勒

您可以用收回一个字符9/3%@3%=
丹尼斯

我目前有7个角色,需要进行一些激烈的重组。但是那个1个字符9/而不是10/仍然有效,所以谢谢。
彼得·泰勒

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移动到那里或杀死您。)

在本地运行此命令时,请确保刷新每个输入的第二个数字之后的换行符(因为Wumpus需要它来确定该数字已结束)。在Powershell中,我不知何故需要在换行符后再输入一个字符以使其正常工作(不管哪个字符,但我只是使用双换行符进行测试)。

进一步打高尔夫球有很大的空间,但是尝试全新的布局需要一段时间。最终分数还很大程度上取决于我使用的实际字符串,因为在2D语言中,一串N字节的字符串往往比N字节的源代码花费更多的成本,因为它对代码布局造成了很大的限制,并且您经常需要将其分为多个部分(产生额外的双引号)。在极端情况下,如果我将每个字符串缩减为一个字母(将-129缩减为-12),则可能会节省大量字节。

说明

首先是一个免责声明:尽管使用了该语言的名称,但它的设计目的并不是使实施“ 猎杀鲸鱼”特别容易。相反,我首先围绕三角形的主题设计了该语言,最后得到了二十面体数据结构,并因此决定将其命名为Wumpus。

是的,虽然Wumpus主要是基于堆栈的,但它也有20个寄存器,它们排列在二十面体的周围。这意味着,我们获得了一个免费的数据结构来表示地图。我们唯一不容易做的就是在二十面体上找到特定的面孔,因此要搜索它们,我们需要“滚动d20”,直到最终找到想要的面孔​​。(有可能以确定性的方式执行此操作,但这将花费更多的字节。)搜索这样的面部几乎可以肯定终止(即,概率为1),因此在实践中永远不会一直在进行搜索。

上面的代码是第一个实现的精简版,其布局更为合理:

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个寄存器之一处于活动状态)。

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次。每次,我们查看正确的邻居,如果有危险,请打印适当的字符串,然后将二十面体旋转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.

下一节将从播放器中读取两个数字,然后移动播放器或发射箭头。前者微不足道,而后者则微不足道。射箭的主要问题是射中箭的情况。在这种情况下,我们a)需要去寻找将其移动的肚皮,然后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.

ew,那是困难的部分。现在我们只需要检查玩家是否死亡,或者从主循环开始:

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面多面体)与5级交替组(5个元素排列具有偶数个偶数长度周期)同构。然后,我选择两个循环长度为5的排列作为“左”和“右”,并选择一个循环长度为2的排列作为“后”。使用这些,我通过沿着汉密尔顿路径(一个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);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.