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ẽ.
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 include
s trong chương trình rev 0 và nó cho phép int
loạ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à \f
là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 puts
thay thế bằng macro bằng printf
và 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.) if
thay 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 while
vò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 printf
và 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. printf
trả về số lượng ký tự được in, Your arrow didn't hit anything\n
là 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 a
chứa thông tin vị trí wumpus sẽ được đặt lại.)
ĐẠ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==1
và m[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 LT
thay vì TL
mỗi bảng ở trên chẳng hạn.
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 int
và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.