Săn Wumpus


39

Khi tôi còn là một cậu bé, những đứa trẻ sẽ lang thang vào các cửa hàng máy tính và chơi Hunt the Wumpus cho đến khi các nhân viên đuổi chúng tôi ra. Đó là một trò chơi đơn giản, có thể lập trình trên các máy tính gia đình vào giữa những năm 1970, máy móc thô sơ đến mức thay vì các bộ vi xử lý cỡ nhỏ, tôi nghĩ rằng một số trong số chúng có thể có gà con thực sự ở đó.

Hãy gợi lên thời đại đã qua bằng cách tái tạo trò chơi trên phần cứng hiện đại.

  1. Người chơi bắt đầu trong một căn phòng ngẫu nhiên trên bản đồ icosah thờ (do đó có tổng cộng 20 phòng, được kết nối với nhau giống như các mặt của một khối hình chữ nhật và mỗi phòng có chính xác ba lối thoát).

  2. Các wumpus bắt đầu trong một phòng khác nhau được lựa chọn ngẫu nhiên. Wumpus bốc mùi, và mùi của nó có thể được phát hiện ở bất kỳ trong ba phòng liền kề với vị trí của nó, mặc dù người chơi không thể xác định được hướng của mùi. Trò chơi chỉ báo cáo "bạn ngửi thấy một cái bướu."

  3. Người chơi mang một cây cung và vô số mũi tên, anh ta có thể bắn bất cứ lúc nào vào phòng trước mặt. Nếu wumpus ở trong căn phòng đó, nó sẽ chết và người chơi sẽ thắng. Nếu wumpus không ở trong căn phòng đó, nó sẽ giật mình và di chuyển ngẫu nhiên vào bất kỳ một trong ba phòng được kết nối với vị trí hiện tại của nó.

  4. Một, phòng được chọn ngẫu nhiên (đảm bảo không phải là phòng mà người chơi bắt đầu) chứa một cái hố không đáy. Nếu người chơi ở trong bất kỳ phòng nào gần hố, anh ta cảm thấy một làn gió nhẹ, nhưng không có manh mối nào về việc gió thổi đến từ cửa nào. Nếu anh ta bước vào phòng với cái hố, anh ta chết và wumpus chiến thắng. Các wumpus không bị ảnh hưởng bởi hố.

  5. Nếu người chơi đi vào phòng của wumpus, hoặc nếu wumpus đi vào phòng của người chơi, thì wumpus sẽ thắng.

  6. Người chơi chỉ định hướng mình đang đối mặt với một số (1 = phải, 2 = trái, 3 = lùi) và sau đó là một hành động (4 = bắn một mũi tên, 5 = đi theo hướng được chỉ định).

  7. Để ghi điểm, mỗi chuỗi trò chơi ("Bạn cảm thấy dễ chịu", "Bạn ngửi thấy một cái bướu", "Mũi tên của bạn không trúng bất cứ thứ gì", v.v.) có thể được coi là một byte. Không lạm dụng điều này để ẩn mã trò chơi trong văn bản; Điều này chỉ để tương tác với người chơi.

  8. Khấu trừ 10% số byte của bạn để thực hiện megabats, bắt đầu trong một phòng ngẫu nhiên khác với người chơi (mặc dù họ có thể chia sẻ một phòng với wumpus và / hoặc hố). Nếu người chơi đi vào phòng có dơi, dơi sẽ đưa người chơi đến một phòng được chọn ngẫu nhiên khác (đảm bảo không phải là phòng có hố hoặc bướu trong đó), trước khi bay đến vị trí ngẫu nhiên mới của riêng họ. Trong ba phòng liền kề với những con dơi, chúng có thể nghe thấy tiếng rít, nhưng người chơi không được cung cấp thông tin về âm thanh phát ra từ phòng nào.

  9. Khấu trừ 35% số byte của bạn để thực hiện giao diện đồ họa hiển thị bản đồ icosah thờ và một số loại dấu hiệu thông tin mà người chơi đã biết về vị trí của hố, bướu và dơi (nếu có), liên quan đến người chơi. Rõ ràng, nếu wumpus di chuyển hoặc người chơi bị dơi di chuyển, bản đồ cần phải thiết lập lại cho phù hợp.

  10. Số byte thấp nhất, khi được điều chỉnh, sẽ thắng.

Mã nguồn BASIC cho một phiên bản của trò chơi (không nhất thiết phải tuân thủ các quy tắc ở trên và, trong mọi trường hợp, hoàn toàn không được phép) có thể được tìm thấy tại trang web này và có thể là các trang web khác.


Một số làm rõ: 3. nếu wumpus không ở trong căn phòng đó thì nó giật mình và di chuyển đến một trong BA phòng .. vì vậy nếu bạn bắn một mũi tên và bỏ lỡ, thì wumpus có thể đến và giết bạn, phải không? Và con wumpus sẽ chỉ di chuyển nếu giật mình, nếu không nó chỉ ở lại? 6. Tôi hiểu tiêu đề của người chơi được xác định bởi phòng anh ta đến. Vì vậy, nếu anh ta đến từ phía nam, các lựa chọn của anh ta sẽ là 1.northeast 2.northwest 3.south và nếu anh ta đến từ phía bắc thì điều ngược lại. Ngoài ra các quy tắc của bạn có vẻ đơn giản / golfier hơn chương trình tham khảo (mà tôi chưa điều tra chi tiết.) Tôi có đúng không?
Cấp sông St

Argh! Tôi không thể tìm thấy bất kỳ hình ảnh nào về đồ thị kép của một hình chữ nhật ở bất cứ đâu trên mạng.
Jack M

1
@steveverrill Vâng, nếu bạn làm hỏng nó, nó có thể đến và giết bạn. Nếu bạn không làm hỏng nó, nó sẽ không di chuyển. Có nhiều biến thể trong trò chơi; nhiều phiên bản cho phép mũi tên vòng quanh và giết bạn chẳng hạn. Tôi đã phân loại ra.
Michael Stern

3
@JackM bản đồ các mặt của một khối hình chữ nhật giống hệt với bản đồ các đỉnh của một khối mười hai mặt, và đồ thị đó có thể dễ dàng tìm thấy. Hãy thử ví dụ wolframalpha.com/input/?i=Dodecah thờGraph +edgerules hoặc lệnh Mathicala tương đương GraphData ["Dodecah thờGraph", "EdgeRules"]. Dù bằng cách nào bạn cũng nhận được {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 Không, "trở lại" ngụ ý quay lại và đi bộ trở lại con đường bạn đã đến. Nếu bạn nhấn "trở lại" hai lần, bạn sẽ kết thúc nơi bạn bắt đầu. Không cần lưu trữ các trạng thái trò chơi trước đó.
Michael Stern

Câu trả lời:


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

Điểm số đạt được bằng cách lấy số byte (290), thêm số chuỗi được sử dụng để tương tác với người dùng (6) và trừ đi độ dài kết hợp của các chuỗi đó (133). Các nguồn cấp dữ liệu là một phần của chuỗi và đóng góp vào số byte.

Các mốc quan trọng

  1. Chuyển câu trả lời của giáo sư từ Bash sang GolfScript. Điểm: 269

  2. Hành động theo đề nghị của Peter Taylor trong các ý kiến. Điểm: 250

  3. Peter Taylor đã cấu trúc lại toàn bộ mã của tôi và giúp tôi nén bảng tra cứu. Điểm: 202

  4. Thay thế bảng tra cứu của các phòng liền kề bằng một phương pháp toán học. Điểm: 182

  5. Tái cấu trúc đầu vào, đầu ra và chức năng hỗ trợ phương pháp toán học. Điểm: 163

Một bữa tiệc lớn Cảm ơn bạn! Lần đến Peter Taylor vì tất cả sự giúp đỡ của anh ấy.

Làm thế nào nó hoạt động

20 phòng được biểu diễn dưới dạng các đỉnh của một khối mười hai mặt, được gán các số từ 0 đến 19 theo kiểu sau:

Đồ thị Dodecah thờ

Để tìm các phòng liền kề với phòng N và sắp xếp chúng theo chiều kim đồng hồ, chúng tôi phải xem xét bốn trường hợp:

  • Nếu N ≡ 0 mod 4 (đỉnh màu xanh), phòng liền kề là 19 - N , N + 2 mod 20N - 2 mod 20 .

  • Nếu N ≡ 1 mod 4 (đỉnh màu xanh lá cây), phòng liền kề là 19 - N , N - 4 mod 20N + 4 mod 20 .

  • Nếu N ≡ 2 mod 4 (đỉnh màu vàng), phòng liền kề là 19 - N , N - 2 mod 20N + 2 mod 20 .

  • Nếu N ≡ 3 mod 4 (đỉnh đỏ), phòng liền kề là, 19 - N , N + 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
Bạn có thể tiết kiệm 1 in Qvới 19rand 97+; 2 trong @với 97%3*&>..., thêm 1 bằng nội tuyến Qnhư {19rand 97+}2*:,\:H, một vài bằng cách thay thế |với *, mà thường là cách tốt nhất để làm một if. Bkhông phục vụ mục đích nào và tôi nghĩ rằng một vài biến số có thể được loại bỏ bằng cách sử dụng ngăn xếp.
Peter Taylor

1
Quên đề cập đến một mẹo thường xuyên khác: chuyển đổi cơ sở cho các bảng tra cứu. Bạn có thể thay thế 62 ký tự cho danh sách kề bằng chuỗi 33 ký tự theo sau 256base 20base(và có thể cũng loại bỏ một vài +/- 97). Nhược điểm duy nhất là nó sẽ yêu cầu các ký tự không in được.
Peter Taylor

1
Tôi đã lưu thêm 13 bằng cách tái cấu trúc để trở thành GS thành ngữ hơn (chủ yếu sử dụng ngăn xếp thay vì biến); và có thêm 10 chi phí để làm cho đầu ra kém đẹp. Đó là ngoài việc nén bảng tra cứu được đề cập trong bình luận trước đây của tôi.
Peter Taylor

1
Không hề, tôi rất thích nó. Tôi chỉ thất vọng vì cách tiếp cận bảng tra cứu tốt hơn nhiều so với phương pháp toán học mà tôi dự định sử dụng. BTW Tôi nghĩ rằng phiên bản hiện tại của bạn có một lỗi nhỏ, bởi vì nếu bạn bắn một mũi tên, bỏ lỡ và làm giật mình chiếc wumpus vào phòng của bạn thì nó chỉ xuất ra You were killed by the wumpusmà không đề cập đến mũi tên bị thiếu. Đó là lý do tại sao tôi đã thêm vào phiên bản không đẹp.
Peter Taylor

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

15

REV0 C ++ (Visual Studio trên Windows) 405

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

Dưới đây là phần chơi, chứng minh rằng (với điều kiện bạn không bắt đầu ngay bên cạnh mối nguy hiểm) với cách chơi chính xác, bạn luôn có thể giành chiến thắng. Người chơi cảm thấy một làn gió nhẹ, quay lại và thực hiện một vòng hoàn toàn ngược chiều kim đồng hồ. Khi anh ta phải di chuyển chính xác 5 lần để cảm thấy một cơn gió nhẹ, anh ta biết lỗ bên phải của mình, và càng xa càng tốt. Tương tự như vậy, khi anh ta ngửi thấy mùi của bướu, không biết nó đúng hay trái, anh ta quay lại và thực hiện một vòng theo chiều kim đồng hồ. Anh ta phải mất 5 động tác để ngửi mùi wumpus một lần nữa, vì vậy anh ta biết nó ở bên trái và bắn một cách chắc chắn.

Nếu anh ta đi vòng theo cách khác, anh ta sẽ tìm thấy cái bướu sớm hơn và biết rằng nó đang ở cùng hướng mà anh ta đang rẽ.

nhập mô tả hình ảnh ở đây

REV1 C (GCC trên Cygwin), tiền thưởng 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!",)}}

Dòng mới được thêm vào cho rõ ràng. Các thay đổi từ Rev 0 như sau:

Xin chân thành cảm ơn @Dennis đã giới thiệu trình biên dịch GCC trên trình giả lập Cygwin Linux cho Windows. Trình biên dịch này không yêu cầu includes trong chương trình rev 0 và nó cho phép intloại mặc định cho các biến và main.Đây là một mẹo chơi gôn thay đổi cuộc sống!

Ngoài ra, chạy trong Linux có nghĩa là \flàm cho con trỏ di chuyển xuống mà không thực hiện quay trở lại vận chuyển (không giống như trong Windows nơi nó chỉ tạo ra một biểu tượng có thể in được.) Điều này đã cho phép rút ngắn đáng kể câu lệnh printf in bảng

Một số lời khuyên bổ sung từ Dennis trong các nhận xét và một trong những ý kiến ​​của riêng tôi: thay đổi tình trạng khi kiểm tra xem mũi tên có đâm vào bướu không : if(q==w)> if(q-w)(..else .. bị đảo ngược)

Bổ sung màn hình hiển thị đồ họa hiển thị thông tin mà người chơi biết về vị trí của một cái bướu / làn gió để nhận phần thưởng 35%. (Tôi đã xóa phiên bản gỡ lỗi cũ của cái này cho thấy vị trí chính xác của wumpus và lỗ. Nó có thể được nhìn thấy trong lịch sử chỉnh sửa.)

REV2 C (GCC trên Cygwin), tiền thưởng 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ột lần nữa xin cảm ơn Dennis vì đã cấu trúc lại mã của tôi:

Char m[]thay thế bằng chữ (tôi không biết bạn có thể lập chỉ mục theo nghĩa đen.)

Việc gieo các số ngẫu nhiên với biến stack (phụ thuộc vào hệ thống, một số hệ thống phân bổ bộ nhớ ngẫu nhiên như một biện pháp bảo mật.)

Macro được putsthay thế bằng macro bằng printfvà mã bổ sung phải được thực thi khi thông báo được hiển thị được đặt bên trong các printfđối số (lợi thế của mặt mà printf không in một vài đối số cuối cùng nếu không có đủ định dạng định dạng trong chuỗi định dạng.) ifthay thế bởi||

Tính toán vị trí mới của người chơi / wumpus được đặt bên trong macro mới.

Tin nhắn thắng / thua được đặt bên ngoài whilevòng lặp. ifđược thay thế bởi toán tử có điều kiện.

Sử dụng toán tử có điều kiện trong dòng để bắn mũi tên. Nếu người chơi bỏ lỡ, điều này đòi hỏi cả việc in một tin nhắn và điều chỉnh vị trí wumpus. Dennis đưa ra một vài cách kết hợp printfvà tính toán vị trí của wumpus thành một biểu thức duy nhất, nhưng tôi đã đi với một trong những cách của riêng tôi. printftrả về số lượng ký tự được in, Your arrow didn't hit anything\nlà 31 (nhị phân 1111.) Vì vậy , 31&Q(w)==Q(w).

Đóng góp khác của tôi cho chỉnh sửa này đã được loại bỏ một số dấu ngoặc không cần thiết.

Đầu ra

Ở đây, người chơi đã tìm thấy Wumpus ở đâu, nhưng chọn khám phá kỹ lưỡng để tìm ra chính xác nơi hố cũng vậy. Không giống như phiên bản gỡ lỗi cũ của tôi cho thấy nơi có bướu và hố trong suốt trò chơi, phần này chỉ hiển thị các phòng mà người chơi đã truy cập và cảm thấy một làn gió (1) đánh tan bướu (2) hoặc cả hai (3). (Nếu người chơi bắn một mũi tên và bỏ lỡ, biến achứa thông tin vị trí wumpus sẽ được đặt lại.)

nhập mô tả hình ảnh ở đây

ĐẠI DIỆN ICOSAHEDRON

Lưu ý: phần này dựa trên rev 1

Tính năng ngôi sao của tôi! Không có biểu đồ trong mã của tôi. Để giải thích cách thức hoạt động, xem bản đồ thế giới bên dưới. Bất kỳ điểm nào trên khối thiên thể đều có thể được biểu thị bằng vĩ độ 0-3 và kinh độ 0-4 (hoặc một số duy nhất long*4+lat.) Đường kinh độ được đánh dấu trên bản đồ chỉ đi qua các mặt có kinh độ 0 và đường vĩ độ đi qua tâm của các mặt có vĩ độ bằng không.

Người chơi có thể được định hướng trên 3 trục có thể, được biểu thị bằng các biểu tượng như sau: bắc-nam -đông bắc-tây \bắc-đông nam /. Trong bất kỳ phòng nào, anh ta có chính xác một lối ra trên mỗi trục này có sẵn cho anh ta. Trong màn hình hiển thị, người chơi thực hiện một vòng lặp theo chiều kim đồng hồ hoàn chỉnh. Nhìn chung, rất dễ để xác định từ người chơi đánh dấu nơi anh ta đến, và do đó anh ta được phép đi đến đâu.

Một trường hợp hơi khó đối với mắt không quen thuộc là trường hợp thứ tư. Khi bạn nhìn thấy một góc nghiêng ở một trong các hàng cực này, người chơi đã đến từ tế bào cực gần đầu bên ngoài của xiên và nhìn chung về phía xích đạo. Do đó, người chơi đang quay mặt về hướng đông nam và các tùy chọn của anh ta là: 15 (SOUTH, ô bên phải) 25 (phía bắcEAST, ô phía trên) hoặc 35 (phía bắc, ô bên dưới.)

Vì vậy, về cơ bản, tôi ánh xạ icosahedron vào lưới 5x4, với các ô được đánh số từ 19 đến 0 theo thứ tự chúng được in. Việc di chuyển được thực hiện bằng cách thêm hoặc bớt từ vị trí hiện tại, tùy thuộc vào vĩ độ và hướng của người chơi, theo bảng bên dưới.

Nếu người chơi đi xuống dưới cùng (phía tây) của bảng, anh ta quay trở lại ở phía trên (phía đông) và ngược lại, do đó, vị trí của anh ta được lấy modulo 20. Nói chung, các bước di chuyển được mã hóa thành m [] bằng cách thêm ascii 80 ( P) với giá trị thô cho các ký tự hiển thị bên dưới, nhưng về nguyên tắc, có thể thêm bất kỳ bội số nào của 20 mà không ảnh hưởng đến hoạt động.

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

Đầu vào của người chơi (chia cho 10 để loại bỏ chữ số thứ hai) được thêm vào hướng hiện tại của anh ta và lấy modulo 3 để có hướng đi mới. Điều này hoạt động tốt trong phần lớn các trường hợp. Tuy nhiên, có một vấn đề khi anh ta ở trong một căn phòng cực và di chuyển về phía cực. Sẽ rõ ràng khi gấp bản đồ bên dưới rằng nếu anh ta rời khỏi căn phòng hướng về "phía đông bắc", anh ta sẽ đi vào quảng trường mới đối diện với "phía đông nam" vì vậy phải điều chỉnh. Điều này được thực hiện trong dòng e=(d+i/10)*m[p%4]%3;bằng cách nhân với m[p%4]. Bốn giá trị đầu tiên của m [] được chọn sao cho ngoài chức năng của chúng ở trên, chúng còn có đặc tính m[1]%3==m[2]%3==1m[0]%3==m[3]%3==2. Điều này để lại hướng một mình cho các phòng xích đạo và áp dụng sự điều chỉnh cần thiết cho các phòng cực.

Thời gian hợp lý để thực hiện chỉnh sửa sẽ là sau khi di chuyển. Tuy nhiên, để lưu các ký tự, nó được thực hiện trước khi di chuyển. Do đó, các giá trị nhất định trong m [] phải được hoán vị. Vì vậy, 2 ký tự cuối cùng LTthay vì TLmỗi bảng ở trên chẳng hạn.

nhập mô tả hình ảnh ở đây

MÃ SỐ UNGOLFED

đây là mã rev 1, ít bị xáo trộn hơn rev 2.

Điều này sẽ chạy trên GCC / Linux. Tôi đã đưa vào các ý kiến ​​mã bổ sung cần thiết để làm cho nó chạy trên Visual studio / Windows. Đó là một sự khác biệt lớn!

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

}

VẤN ĐỀ VÀ HIỆN TẠI

Tôi đã tận dụng điểm được đề cập bởi @professorfish, nếu wumpus và pit bắt đầu ở những nơi ngẫu nhiên, không cần người chơi bắt đầu ở một nơi ngẫu nhiên. Người chơi luôn bắt đầu ở phòng 19 hướng về phía bắc.

Tôi hiểu rằng vì bướu "không bị ảnh hưởng bởi hố" nên bướu có thể bắt đầu hoặc vào phòng nơi có hố. Nói chung, điều này đơn giản hóa mọi thứ trừ một điểm. Tôi không có biến cụ thể để chỉ ra trò chơi kết thúc; nó kết thúc khi người chơi trùng với wumpus hoặc hố. Vì vậy, khi người chơi chiến thắng, tôi sẽ hiển thị thông báo chiến thắng nhưng di chuyển hố đến người chơi để thoát khỏi vòng lặp! Tôi không thể đặt người chơi vào hố vì cái bướu có thể ở đó và tôi sẽ nhận được một tin nhắn về cái bướu mà tôi không muốn.

Chương trình rev0pro hoạt động hoàn hảo trong studio hình ảnh, nhưng IDE cho biết "stack bị hỏng xung quanh biến i" khi thoát. Điều này là do scanf đang cố gắng đưa intvào một char.Dennis báo cáo hành vi không chính xác trên máy Linux của mình vì điều này. Dù sao nó đã được sửa bằng cách sử dụng đúng loại trong rev 1.

Dòng hiển thị bảng trong rev 0 là vụng về và xuất hiện hơi khác nhau trên các nền tảng khác. Ở printf(" %c%c%c")giữa% c là ký tự có thể in được hiển thị. % C cuối cùng là ASCII 0 hoặc ASCII 10 (\ n, dòng mới có trả lại vận chuyển trong Windows.) Dường như không có ký tự nào trong Windows hoạt động trong bảng điều khiển, sẽ đi xuống một dòng mà không trả lại vận chuyển. Nếu có, tôi sẽ không cần tab c% đầu tiên (tab ASCII 0 hoặc ASCII 9 trước ký tự vĩ độ 1. Các tab không được xác định rõ ràng trong hành vi của chúng.) Không gian hàng đầu cải thiện định dạng (đặt các ký tự 3 và 2 vĩ độ gần hơn 1 .) Rev 1 có một bản tóm tắt của dòng này sử dụng ký tự \ f formfeed và do đó không cần ký tự định dạng khi bắt đầu printf. Điều này làm cho nó ngắn hơn, nhưng \ f không hoạt động trong Windows.


1
Tôi yêu các bài viết.
Michael Stern

Tôi không chắc chắn nếu đó là vì những thay đổi tôi đã phải làm để biên dịch nó với GCC trên Linux (loại bỏ các bao gồm đầu tiên, thay thế scanf_svới scanfvà bao gồm stdio.hnếu tôi biên dịch như C ++ Rater hơn so với C), nhưng nó không hoàn toàn làm việc cho tôi. Ví dụ: nếu tôi đi bên trái, sau đó quay lại bên phải vào lúc bắt đầu ( 15 35), tôi đang ở một phòng khác với phòng tôi đã bắt đầu.
Dennis

@Dennis Tôi đã theo dõi nguồn gốc của lỗi khi thoát. đó là scanf_s (được cho là an toàn!), "làm hỏng ngăn xếp xung quanh biến i" khi nó cố gắng đặt cái mà tôi giả sử là số nguyên 32 bit vào một char. Vì vậy, điều đầu tiên tôi muốn đề xuất là kiểm tra loại mà scanf sử dụng cho "% d" và thay đổi biến i thành loại đó. Tôi nhận được câu trả lời đúng w / exit error cho char, câu trả lời đúng w / o error exit cho int và câu trả lời sai với kiểu Microsoft __int64 (tương đương dài, trừ khi tôi đặt "% lld".) phiên bản không được chỉnh sửa và bạn có gặp vấn đề gì với màn hình không?
Cấp sông St

@steveverrill: Vâng, tôi đã thử cả hai phiên bản. Các loại ithực sự là vấn đề. Các trang người đàn ông nói: " d Trận một số nguyên thập phân tùy chọn đã ký kết; con trỏ tới phải là một con trỏ đến int ." Thay đổi loại làm cho nó hoạt động tốt.
Dennis

@steveverrill: Tôi không biết cách VS xử lý mọi thứ, nhưng nếu bạn biên dịch bằng GCC (như C, không phải C ++), bạn có thể tiết kiệm rất nhiều ký tự. Không cần bao gồm nếu bạn thay thế NULLbằng 0scanf_sbằng scanf, bạn không cần inttrước đó mainvà bạn có thể di chuyển ivà ra dngoài chính (chúng mặc định intvà được khởi tạo thành 0). Ngoài ra, bạn có thể xác định p=19,h=rand()%p,w=rand()%p, thay thế m[]bằng *mvà nên có thể xác định một macro cho tất cả các trường hợp if(...==...)puts(...);.
Dennis

9

GolfScript, 269 ký tự

{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

Lưu ý rằng 163 đã được trừ vào số ký tự cho các chuỗi được mã hóa cứng. Nếu bạn muốn đầu ra gỡ lỗi chỉ ra số phòng, hãy thêm dòng sau ngay sau lần xuất hiện đầu tiên của ^:

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

Một phiên ví dụ (có đầu ra gỡ lỗi bổ sung):

  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

Đây là mã làm việc đầu tiên. Trở lại sau để chơi gôn nhiều hơn.
Howard

Mã của tôi hiện dài hơn 1 ký tự. Tôi đang tìm kiếm bất kỳ cách nào có thể để chơi golf hơn nữa!
Timtech

Không phải là bạn cần sự giúp đỡ của tôi, nhưng bạn có thể lưu 14 ký tự bằng cách xác định {puts}:|;, 5 ký tự bằng cách thay thế RWbằng ->(cho phép loại bỏ khoảng trống xung quanh) và 9 ký tự bằng cách bỏ '> 'print(câu hỏi dường như không bắt buộc).
Dennis

@Dennis Cảm ơn bạn. Tôi chắc chắn sẽ thực hiện một số đề xuất của bạn.
Howard

9

JavaScript (ECMAScript 6) - 2197 1759 -45% = 967,45 Ký tự

Gần như đã hoàn thành việc đánh gôn này ...

Bao gồm một GUI với Bản đồ Icosah và Dơi Mega cho phần thưởng đầy đủ.

GUI Wumpus

  • Mỗi phòng có 4 nút: X(Hố); B(Mega-Bat); W(Wumpus); và P(Bạn).
  • Vị trí hiện tại của bạn có màu xanh lam.
  • Các nút được tô màu đỏ nếu đối tượng mà nó đại diện có thể ở vị trí đó và màu xanh lá cây nếu nó chắc chắn không ở vị trí đó.
  • Các nút Wvà chỉ Pcó thể được bấm trong các phòng liền kề với vị trí hiện tại của bạn.
  • Nếu bạn thắng nền sẽ chuyển sang màu xanh lá cây và nếu bạn chết thì nền sẽ chuyển sang màu đỏ.

Mã số:

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)

Bạn nhận được 1066 mà không có ECMA 6 bằng trình biên dịch đóng.
AMK

Tôi đã tự hỏi sẽ dễ dàng hơn thế nào khi bạn có một biểu diễn đồ họa để giúp khấu trừ mọi thứ ở đâu. 1+ nhưng nó hơi quá dễ dàng :)
Sylwester

9

Bash, 365 (phiên bản làm việc đầu tiên 726!)

BẮT ĐẦU VỚI GOLFSCRIPT?

@Dennis về cơ bản đã thực hiện tất cả việc chơi golf cho tôi. Cảm ơn!

Chương trình giả định đầu vào hợp lệ. Đầu vào hợp lệ là hướng bạn chọn (1 cho bên phải, 2 cho bên trái, 3 cho quay lại) theo sau là hành động của bạn (4 để bắn, 5 để đi bộ).

Một số giải thích

Tôi thường làm những lời giải thích dài dòng, nhưng điều này có lẽ hơi phức tạp để tôi bị làm phiền.

Mỗi đỉnh trên biểu đồ khối mười hai mặt được mã hóa dưới dạng một chữ cái (a = 1, b = 2, ... t = 20).

Vị trí bắt đầu của người chơi luôn là 20 (và họ đang đứng quay lưng về 18), vì bản thân điều đó không quan trọng, chỉ có các vị trí tương đối của người chơi, hố và bướu.

Biến $plưu trữ vị trí của người chơi. $rlưu trữ vị trí trước đó của người chơi. $wlà wumpus và $h(H cho lỗ) là 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};};}

Lịch sử phiên bản

  1. Phát hành lần đầu, 698 ký tự
  2. Đã sửa lỗi trong đó "Bạn cảm thấy một làn gió nhẹ" và "Bạn ngửi thấy mùi bướu" không thể hiển thị cùng một lúc; đã lưu 39 ký tự bằng cách tạo một số ngẫu nhiên một hàm.
  3. Hãy nhớ rằng wumpus di chuyển nếu bạn bắn và bỏ lỡ. 726 ký tự.
  4. Thực hiện grep -oEmột biến. Lưu 5 ký tự.
  5. Thực hiện [a-z]{3}một biến. Lưu 3 ký tự.
  6. Thực hiện echomột biến. Lưu 5 ký tự.
  7. Đã hành động trên hầu hết các đề xuất của @Dennis. Lưu 72 ký tự.
  8. Đã thêm tất cả các đề xuất còn lại. Lưu 68 ký tự.
  9. Đã lưu 2 ký tự từ đề xuất của @DigitalTrauma.
  10. Đã sửa một lỗi lớn trong đó bạn chỉ có thể bắn wumpus nếu nó ở bên phải. Số lượng nhân vật giống nhau.
  11. Sử dụng mở rộng tham số để cạo 2 ký tự bằng cách sử dụng $m.
  12. Cạo đi rất nhiều ký tự bằng cách bỏ đi grepvà trở nên hợp lý hơn một chút.
  13. Được xác định Clà một hàm tìm kiếm regrec để sử dụng trong các câu lệnh if và Enhư là một chức năng in "Bạn đã giết chết cái bướu" và thoát ra.
  14. Đã lưu 1 char bằng cách sắp xếp lại "if statement".
  15. Đã lưu rất nhiều ký tự bằng cách loại bỏ dvà loại bỏ các dấu ngoặc không cần thiết.
  16. Đã sửa lỗi. Đã thêm rất nhiều ký tự :(
  17. TIẾT KIỆM MOARR ( http://xkcd.com/1296/ )
  18. Một ý tưởng khác của @Dennis (tiết kiệm một vài ký tự) và cách sử dụng xảo quyệt (ab) xảo quyệt của tôi (tiết kiệm 1 char).
  19. Sửa kiểu cho q ().
  20. thêm lại đầu ra thích hợp

Chạy mẫu

"Trong:" là đầu vào, "Ra: là đầu ra".

Người chơi đi loanh quanh một chút, ngửi mùi wumpus và bắn. Họ nhớ, và con wumpus đi vào phòng của họ và ăn chúng.

Trong: 15

Trong: 15

Trong: 25

Trong: 25

Trong: 15

Hết: Bạn ngửi thấy mùi bướu

Trong: 14

Hết: Bạn đã bỏ lỡ

Out: The wumpus ăn bạn


1
Tôi nghĩ bạn có thể làm cho mã của mình ngắn hơn ít nhất 100 byte. 1. exitchỉ dài hơn một byte g=1và nó loại bỏ sự cần thiết phải kiểm tra khác không gvà một số elifcâu lệnh. 2. Bạn có thể sử dụng ((i==35))thay vì [ $i = 35 ]...&&...thay vì if ... then ... fi. 3. q(){ L=({a..s});$j ${L[RANDOM%19]};}n=`$k $w$m<<<$d`;w=${n:RANDOM%2+1:1}cả hai đều tiết kiệm một vài byte.
Dennis

1
Thay thế while :;do... donebằng for((;;);{... }để tiết kiệm 3 char
Chấn thương kỹ thuật số

1
@professorfish: Tôi nghĩ rằng một hàm sẽ hoạt động tốt hơn so với cách tiếp cận cắt chuỗi hiện tại. Ví dụ, d(){ x=npoemfgnshtoksblbtckpdpljqniorelgfhkbqraicadjaghimsmjtqecrdf;s=${x:3*30#$1-30:3};}sẽ cho phép bạn thay thế các định nghĩa về snbằng d $pd $w. Nếu bạn xác định hơn nữa u=${s#*$r}$s(và điều chỉnh các định nghĩa của lfphù hợp), bạn sẽ không cần $k$mnữa. Tiết kiệm 83 byte, tôi nghĩ vậy. Ngoài ra, không gian trong q ()là không cần thiết.
Dennis

1
@professorfish: Và bạn có thể lưu thêm 3 byte bằng cách xác định c(){ [[ $1 =~ $2 ]];}và thay thế, ví dụ: dòng thứ hai đến dòng cuối cùng c $r $b||{ $j You missed;d $w;w=${s:RANDOM%2+1:1};}.
Dennis

1
@professorfish: Sử dụng hàm tôi đề xuất nên ngắn hơn 3 byte. Bạn có thể lưu 106 byte bổ sung bằng cách thay thế bốn dòng sau b=$pbằng d $p;u=u${s#*$r}$s, các dòng sau read ibằng 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};}và loại bỏ 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];

Cuối cùng cũng bắt kịp phiên bản bảng tra cứu của Dennis, từ đó nó mượn khá nhiều. Điều thú vị của phiên bản này là nó không có bảng tra cứu bố trí phòng.

Các 60 đối xứng quay của một icosahedron là đẳng cấu với nhóm xen kẽ trên 5 chữ cái, A_5. Sau khi thử tất cả các cách tiếp cận để đại diện cho nhóm một cách gọn gàng, tôi đã trở lại với cách đơn giản nhất: mỗi yếu tố là một hoán vị chẵn lẻ. Nhóm có thể được tạo từ hai máy phát điện theo nhiều cách: cách tiếp cận tôi đang sử dụng máy phát điện 33 1. Điều này cho phép chúng ta tạo ra 1 = 3 3 1, 2 = 3 3 1 3 13 = 3.

Quan sát hướng đó 3tương ứng với một yếu tố của trật tự 2, bởi vì sau khi đi qua cánh cửa phía sau bạn, cánh cửa đó lại ở phía sau bạn. Hướng 1tương ứng với một yếu tố của trật tự 5, đi xung quanh một đỉnh của khối hình chữ nhật. (Yếu tố tương tự 2). Và sự kết hợp 3 1theo thứ tự 3, vì nó xoay quanh các phòng liền kề với phòng bắt đầu phía sau bạn.

Vì vậy, chúng tôi đang tìm kiếm một hoán vị của thứ tự 2 để thể hiện hướng 3và hoán vị của thứ tự 5 để đại diện cho hướng 1đó 3 1là thứ tự 3.

Có 15 hoán vị của bậc 2 trong A_5 và với mỗi hoán vị có 8 hoán vị ứng cử viên cho 1(và do đó cho 3 1). Có một sức hấp dẫn rõ ràng để [4 3 2 1 0]cho 3: đảo ngược một mảng chỉ là -1%. Trong số các hoán vị đồng hành có thể có của nó, 3 1tôi đã chọn [0 1 3 4 2], nó thừa nhận việc thực hiện khá ngắn như [~@].

Bị đánh cắp

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

Cách tiếp cận đại số tốt đẹp! Có một lỗi nhỏ: 10/@3%=cố gắng truy cập phần tử thứ tư của một mảng có độ dài 3 nếu đầu vào là 35.
Dennis

@Dennis, vâng, tôi nhận ra sau khi tôi đi ngủ. Tôi có thể nghĩ ra nhiều cách sửa chữa khác nhau, tất cả đều tốn kém 2.
Peter Taylor

Bạn có thể nhận được một char trở lại với 9/3%@3%=.
Dennis

Tôi hiện đang có 7 cơ hội với một số cơ cấu mạnh mẽ hơn. Nhưng 1 char 9/thay vì 10/vẫn hoạt động, cảm ơn.
Peter Taylor

5

Wumpus , 384 - 129 (chuỗi) = 255 byte

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

Hãy thử trực tuyến! (Tất nhiên, TIO không có nhiều ý nghĩa, bởi vì bạn không thể sử dụng chương trình một cách tương tác ở đó và một khi chương trình hết hướng dẫn trên STDIN, nó sẽ đọc 0 0, tương đương với 3 4, vì vậy bạn sẽ kết thúc bắn mũi tên cho đến khi Wumpus di chuyển đến đó hoặc giết chết bạn.)

Khi chạy cục bộ này, hãy đảm bảo rằng nguồn cấp dữ liệu sau số thứ hai của mỗi đầu vào bị xóa (vì Wumpus cần nó để xác định rằng số đó đã kết thúc). Trong Powershell, bằng cách nào đó tôi cần nhập thêm một ký tự sau nguồn cấp dữ liệu để làm cho nó hoạt động (không quan trọng là nhân vật nào, nhưng tôi chỉ sử dụng các nguồn cấp dữ liệu kép để thử nghiệm).

Có rất nhiều chỗ để chơi gôn hơn nữa, nhưng thử bố cục hoàn toàn mới mất một thời gian. Điểm số cuối cùng cũng phụ thuộc rất nhiều vào các chuỗi thực tế tôi sử dụng, bởi vì trong ngôn ngữ 2D, một chuỗi N byte có xu hướng khiến bạn tốn nhiều hơn N byte mã nguồn, bởi vì nó đặt ra các ràng buộc đáng kể đối với bố cục mã và bạn thường cần chia nó thành nhiều phần (phát sinh thêm dấu ngoặc kép). Cuối cùng, nếu tôi giảm mỗi chuỗi thành một chữ cái (và -129 xuống -12), có lẽ tôi sẽ tiết kiệm được một tấn byte.

Giải trình

Đầu tiên là từ chối trách nhiệm: mặc dù tên của ngôn ngữ, nó không được thiết kế để thực hiện Hunt the Wumpus đặc biệt dễ dàng. Thay vào đó, lần đầu tiên tôi thiết kế ngôn ngữ xung quanh chủ đề hình tam giác, kết thúc với cấu trúc dữ liệu icosah thờ và quyết định gọi nó là Wumpus vì điều đó.

Vì vậy, yeah, trong khi Wumpus chủ yếu dựa trên stack, nó cũng có 20 thanh ghi được sắp xếp xung quanh các mặt của một icosahedron. Điều đó có nghĩa là, chúng tôi có được cấu trúc dữ liệu để thể hiện bản đồ miễn phí. Điều duy nhất chúng ta không thể làm một cách dễ dàng là tìm các khuôn mặt cụ thể trên icosahedron, vì vậy để tìm kiếm chúng, chúng ta cần "cuộn d20" cho đến khi chúng ta kết thúc trên khuôn mặt mà chúng ta đang tìm kiếm. (Có thể thực hiện việc này theo cách xác định, nhưng sẽ tốn nhiều byte hơn.) Tìm kiếm các khuôn mặt như thế này chấm dứt gần như chắc chắn (ví dụ với xác suất 1), vì vậy việc tìm kiếm chạy mãi mãi không phải là vấn đề đáng lo ngại trong thực tế).

Đoạn mã trên là phiên bản được đánh gôn của triển khai đầu tiên này với bố cục 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.

Vì việc chơi golf chủ yếu liên quan đến việc nén bố cục, nên bây giờ tôi sẽ chỉ giải thích phiên bản này (cho đến khi tôi thêm bất kỳ thủ thuật đánh gôn nào vượt ra ngoài việc tái cấu trúc mã).

Hãy bắt đầu với mã thiết lập:

1SDL2vSD70L?.;;2.

Ban đầu, tất cả các mặt được đặt thành 0 . Chúng ta sẽ mã hóa wumpus bằng cách đặt 1 bit của mặt tương ứng và hố bằng cách đặt 2 bit. Bằng cách này, cả hai có thể ở trong cùng một phòng. Vị trí của người chơi sẽ không được ghi lại trên icosahedron, thay vào đó, nó sẽ luôn luôn hoạt động (chỉ một trong số 20 thanh ghi hoạt động tại một thời điểm).

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.

Bây giờ chúng ta cần tìm một khuôn mặt trống ngẫu nhiên để đưa người chơi vào.

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.

Phần tiếp theo này kiểm tra môi trường xung quanh của người chơi và in các cảnh báo thích hợp:

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

Đây là một vòng lặp mà chúng tôi chạy qua 3 lần. Mỗi lần, chúng tôi nhìn vào hàng xóm bên phải, in (các) chuỗi thích hợp nếu có nguy hiểm và sau đó xoay icosahedron thêm 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.

Phần tiếp theo đọc hai số từ người chơi và sau đó di chuyển người chơi hoặc bắn một mũi tên. Cái trước là tầm thường, cái sau ít như vậy. Vấn đề chính để bắn mũi tên là trường hợp nó bỏ lỡ. Trong trường hợp đó, chúng tôi a) cần phải tìm kiếm cái bướu để di chuyển nó, và sau đó b) trở về phòng của người chơi hướng chính xác của icosahedron (để "trở lại" vẫn "quay lại"). Đây là phần đắt nhất của toàn bộ chương trình.

    }&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ểm vào phần này là Iở bên trá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.

Phew, đó là phần khó khăn. Bây giờ chúng ta chỉ cần kiểm tra xem người chơi có chết hay không và bắt đầu lại vòng lặp chính:

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

Cấu trúc của phần này về cơ bản giống với cấu trúc chúng tôi đã sử dụng khi kiểm tra môi trường xung quanh người chơi: chúng tôi kiểm tra 1 bit của khuôn mặt hiện tại (phòng của người chơi) và nếu nó được đặt, chúng tôi sẽ in The wumpus ate you.và chấm dứt chương trình. Mặt khác, chúng tôi kiểm tra 2 bit và thiết lập chúng tôi sẽ in You fell into the pit.và chấm dứt chương trình. Mặt khác, chúng ta đạt được 2.bước nhảy trở lại điểm bắt đầu của vòng lặp chính (tại tọa độ (0, 2)).


1

ôi - lớn

Điều này đã không diễn ra ngắn như tôi mong đợi, nhưng tôi đã thực hiện một cách tiếp cận hơi khác để xử lý biểu đồ, vì vậy dù sao tôi cũng đang đăng phiên bản không có bản quyền.

Tôi đã lợi dụng thực tế là một icosahedron (khối đa diện 20 mặt) theo hướng quay bảo toàn hướng là đẳng hình với nhóm xen kẽ bậc 5 (hoán vị 5 phần tử có số chu kỳ chẵn dài). Sau đó tôi chọn hai hoán vị có độ dài chu kỳ 5 là "trái" và "phải" và tôi chọn một hoán vị có độ dài chu kỳ 2 là "trở lại". Sử dụng những thứ này, tôi xây dựng biểu đồ từ một phòng bằng cách đi theo đường dẫn Hamilton (2xRRRLLLRLRL, sử dụng 3xRB trong mỗi phòng để chụp 3 hướng có thể).

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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.