1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36: #include <sys/cdefs.h>
37: #ifndef lint
38: __COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
39: The Regents of the University of California. All rights reserved.\n");
40: #endif
41:
42: #ifndef lint
43: #if 0
44: static char sccsid[] = "@(#)wump.c 8.1 (Berkeley) 5/31/93";
45: #else
46: __RCSID("$NetBSD: wump.c,v 1.17 2005/02/15 12:56:20 jsm Exp $");
47: #endif
48: #endif
49:
50:
51:
52:
53:
54:
55:
56: #include <err.h>
57: #include <sys/types.h>
58: #include <sys/file.h>
59: #include <sys/wait.h>
60: #include <stdio.h>
61: #include <stdlib.h>
62: #include <string.h>
63: #include <time.h>
64: #include <unistd.h>
65: #include "pathnames.h"
66:
67:
68:
69: #define MAX_ARROW_SHOT_DISTANCE 6
70: #define MAX_LINKS_IN_ROOM 25
71:
72: #define MAX_ROOMS_IN_CAVE 250
73: #define ROOMS_IN_CAVE 20
74: #define MIN_ROOMS_IN_CAVE 10
75:
76: #define LINKS_IN_ROOM 3
77: #define NUMBER_OF_ARROWS 5
78: #define PIT_COUNT 3
79: #define BAT_COUNT 3
80:
81: #define EASY 1
82: #define HARD 2
83:
84:
85:
86: #define plural(n) (n == 1 ? "" : "s")
87:
88:
89: struct room_record {
90: int tunnel[MAX_LINKS_IN_ROOM];
91: int has_a_pit, has_a_bat;
92: } cave[MAX_ROOMS_IN_CAVE+1];
93:
94:
95:
96:
97:
98: int player_loc = -1;
99: int wumpus_loc = -1;
100: int level = EASY;
101: int arrows_left;
102:
103: #ifdef DEBUG
104: int debug = 0;
105: #endif
106:
107: int pit_num = PIT_COUNT;
108: int bat_num = BAT_COUNT;
109: int room_num = ROOMS_IN_CAVE;
110: int link_num = LINKS_IN_ROOM;
111: int arrow_num = NUMBER_OF_ARROWS;
112:
113: char answer[20];
114:
115: int bats_nearby(void);
116: void cave_init(void);
117: void clear_things_in_cave(void);
118: void display_room_stats(void);
119: int gcd(int, int);
120: int getans(const char *);
121: void initialize_things_in_cave(void);
122: void instructions(void);
123: int int_compare(const void *, const void *);
124: void jump(int);
125: void kill_wump(void);
126: int main(int, char **);
127: int move_to(const char *);
128: void move_wump(void);
129: void no_arrows(void);
130: void pit_kill(void);
131: int pit_nearby(void);
132: void pit_survive(void);
133: int shoot(char *);
134: void shoot_self(void);
135: int take_action(void);
136: void usage(void) __attribute__((__noreturn__));
137: void wump_kill(void);
138: int wump_nearby(void);
139:
140: int
141: main(argc, argv)
142: int argc;
143: char **argv;
144: {
145: int c;
146:
147:
148: setregid(getgid(), getgid());
149:
150: #ifdef DEBUG
151: while ((c = getopt(argc, argv, "a:b:hp:r:t:d")) != -1)
152: #else
153: while ((c = getopt(argc, argv, "a:b:hp:r:t:")) != -1)
154: #endif
155: switch (c) {
156: case 'a':
157: arrow_num = atoi(optarg);
158: break;
159: case 'b':
160: bat_num = atoi(optarg);
161: break;
162: #ifdef DEBUG
163: case 'd':
164: debug = 1;
165: break;
166: #endif
167: case 'h':
168: level = HARD;
169: break;
170: case 'p':
171: pit_num = atoi(optarg);
172: break;
173: case 'r':
174: room_num = atoi(optarg);
175: if (room_num < MIN_ROOMS_IN_CAVE) {
176: (void)fprintf(stderr,
177: "No self-respecting wumpus would live in such a small cave!\n");
178: exit(1);
179: }
180: if (room_num > MAX_ROOMS_IN_CAVE) {
181: (void)fprintf(stderr,
182: "Even wumpii can't furnish caves that large!\n");
183: exit(1);
184: }
185: break;
186: case 't':
187: link_num = atoi(optarg);
188: if (link_num < 2) {
189: (void)fprintf(stderr,
190: "Wumpii like extra doors in their caves!\n");
191: exit(1);
192: }
193: break;
194: case '?':
195: default:
196: usage();
197: }
198:
199: if (link_num > MAX_LINKS_IN_ROOM ||
200: link_num > room_num - (room_num / 4)) {
201: (void)fprintf(stderr,
202: "Too many tunnels! The cave collapsed!\n(Fortunately, the wumpus escaped!)\n");
203: exit(1);
204: }
205:
206: if (level == HARD) {
207: bat_num += ((random() % (room_num / 2)) + 1);
208: pit_num += ((random() % (room_num / 2)) + 1);
209: }
210:
211: if (bat_num > room_num / 2) {
212: (void)fprintf(stderr,
213: "The wumpus refused to enter the cave, claiming it was too crowded!\n");
214: exit(1);
215: }
216:
217: if (pit_num > room_num / 2) {
218: (void)fprintf(stderr,
219: "The wumpus refused to enter the cave, claiming it was too dangerous!\n");
220: exit(1);
221: }
222:
223: instructions();
224: cave_init();
225:
226:
227: (void)printf(
228: "\nYou're in a cave with %d rooms and %d tunnels leading from each room.\n\
229: There are %d bat%s and %d pit%s scattered throughout the cave, and your\n\
230: quiver holds %d custom super anti-evil Wumpus arrows. Good luck.\n",
231: room_num, link_num, bat_num, plural(bat_num), pit_num,
232: plural(pit_num), arrow_num);
233:
234: for (;;) {
235: initialize_things_in_cave();
236: arrows_left = arrow_num;
237: do {
238: display_room_stats();
239: (void)printf("Move or shoot? (m-s) ");
240: (void)fflush(stdout);
241: if (!fgets(answer, sizeof(answer), stdin))
242: break;
243: } while (!take_action());
244:
245: if (!getans("\nCare to play another game? (y-n) "))
246: exit(0);
247: if (getans("In the same cave? (y-n) "))
248: clear_things_in_cave();
249: else
250: cave_init();
251: }
252:
253: return (0);
254: }
255:
256: void
257: display_room_stats()
258: {
259: int i;
260:
261:
262:
263:
264:
265:
266: (void)printf(
267: "\nYou are in room %d of the cave, and have %d arrow%s left.\n",
268: player_loc, arrows_left, plural(arrows_left));
269:
270: if (bats_nearby())
271: (void)printf("*rustle* *rustle* (must be bats nearby)\n");
272: if (pit_nearby())
273: (void)printf("*whoosh* (I feel a draft from some pits).\n");
274: if (wump_nearby())
275: (void)printf("*sniff* (I can smell the evil Wumpus nearby!)\n");
276:
277: (void)printf("There are tunnels to rooms %d, ",
278: cave[player_loc].tunnel[0]);
279:
280: for (i = 1; i < link_num - 1; i++)
281: if (cave[player_loc].tunnel[i] <= room_num)
282: (void)printf("%d, ", cave[player_loc].tunnel[i]);
283: (void)printf("and %d.\n", cave[player_loc].tunnel[link_num - 1]);
284: }
285:
286: int
287: take_action()
288: {
289:
290:
291:
292:
293:
294: switch (*answer) {
295: case 'M':
296: case 'm':
297: return(move_to(answer + 1));
298: case 'S':
299: case 's':
300: return(shoot(answer + 1));
301: case 'Q':
302: case 'q':
303: case 'x':
304: exit(0);
305: case '\n':
306: return(0);
307: }
308: if (random() % 15 == 1)
309: (void)printf("Que pasa?\n");
310: else
311: (void)printf("I don't understand!\n");
312: return(0);
313: }
314:
315: int
316: move_to(room_number)
317: const char *room_number;
318: {
319: int i, just_moved_by_bats, next_room, tunnel_available;
320:
321:
322:
323:
324:
325:
326:
327:
328:
329: tunnel_available = just_moved_by_bats = 0;
330: next_room = atoi(room_number);
331:
332:
333: if (next_room == room_num + 1 &&
334: cave[player_loc].tunnel[link_num-1] != next_room)
335: ++next_room;
336:
337: while (next_room < 1 || next_room > room_num + 1) {
338: if (next_room < 0 && next_room != -1)
339: (void)printf("Sorry, but we're constrained to a semi-Euclidean cave!\n");
340: if (next_room > room_num + 1)
341: (void)printf("What? The cave surely isn't quite that big!\n");
342: if (next_room == room_num + 1 &&
343: cave[player_loc].tunnel[link_num-1] != next_room) {
344: (void)printf("What? The cave isn't that big!\n");
345: ++next_room;
346: }
347: (void)printf("To which room do you wish to move? ");
348: (void)fflush(stdout);
349: if (!fgets(answer, sizeof(answer), stdin))
350: return(1);
351: next_room = atoi(answer);
352: }
353:
354:
355: tunnel_available = 0;
356: for (i = 0; i < link_num; i++)
357: if (cave[player_loc].tunnel[i] == next_room)
358: tunnel_available = 1;
359:
360: if (!tunnel_available) {
361: (void)printf("*Oof!* (You hit the wall)\n");
362: if (random() % 6 == 1) {
363: (void)printf("Your colorful comments awaken the wumpus!\n");
364: move_wump();
365: if (wumpus_loc == player_loc) {
366: wump_kill();
367: return(1);
368: }
369: }
370: return(0);
371: }
372:
373:
374: if (next_room == room_num + 1)
375: jump(next_room = (random() % room_num) + 1);
376:
377: player_loc = next_room;
378: for (;;) {
379: if (next_room == wumpus_loc) {
380: wump_kill();
381: return(1);
382: }
383: if (cave[next_room].has_a_pit) {
384: if (random() % 12 < 2) {
385: pit_survive();
386: return(0);
387: } else {
388: pit_kill();
389: return(1);
390: }
391: }
392:
393: if (cave[next_room].has_a_bat) {
394: (void)printf(
395: "*flap* *flap* *flap* (humongous bats pick you up and move you%s!)\n",
396: just_moved_by_bats ? " again": "");
397: next_room = player_loc = (random() % room_num) + 1;
398: just_moved_by_bats = 1;
399: }
400:
401: else
402: break;
403: }
404: return(0);
405: }
406:
407: int
408: shoot(room_list)
409: char *room_list;
410: {
411: int chance, next, roomcnt;
412: int j, arrow_location, link, ok;
413: char *p;
414:
415:
416:
417:
418:
419:
420:
421:
422:
423:
424:
425: arrow_location = player_loc;
426: for (roomcnt = 1;; ++roomcnt, room_list = NULL) {
427: if (!(p = strtok(room_list, " \t\n"))) {
428: if (roomcnt == 1) {
429: (void)printf(
430: "The arrow falls to the ground at your feet!\n");
431: return(0);
432: } else
433: break;
434: }
435: if (roomcnt > 5) {
436: (void)printf(
437: "The arrow wavers in its flight and and can go no further!\n");
438: break;
439: }
440: next = atoi(p);
441: for (j = 0, ok = 0; j < link_num; j++)
442: if (cave[arrow_location].tunnel[j] == next)
443: ok = 1;
444:
445: if (ok) {
446: if (next > room_num) {
447: (void)printf(
448: "A faint gleam tells you the arrow has gone through a magic tunnel!\n");
449: arrow_location = (random() % room_num) + 1;
450: } else
451: arrow_location = next;
452: } else {
453: link = (random() % link_num);
454: if (link == player_loc)
455: (void)printf(
456: "*thunk* The arrow can't find a way from %d to %d and flys back into\n\
457: your room!\n",
458: arrow_location, next);
459: else if (cave[arrow_location].tunnel[link] > room_num)
460: (void)printf(
461: "*thunk* The arrow flys randomly into a magic tunnel, thence into\n\
462: room %d!\n",
463: cave[arrow_location].tunnel[link]);
464: else
465: (void)printf(
466: "*thunk* The arrow can't find a way from %d to %d and flys randomly\n\
467: into room %d!\n",
468: arrow_location, next,
469: cave[arrow_location].tunnel[link]);
470: arrow_location = cave[arrow_location].tunnel[link];
471: break;
472: }
473: chance = random() % 10;
474: if (roomcnt == 3 && chance < 2) {
475: (void)printf(
476: "Your bowstring breaks! *twaaaaaang*\n\
477: The arrow is weakly shot and can go no further!\n");
478: break;
479: } else if (roomcnt == 4 && chance < 6) {
480: (void)printf(
481: "The arrow wavers in its flight and and can go no further!\n");
482: break;
483: }
484: }
485:
486:
487:
488:
489:
490: if (arrow_location == wumpus_loc) {
491: kill_wump();
492: return(1);
493: }
494:
495: if (arrow_location == player_loc) {
496: shoot_self();
497: return(1);
498: }
499:
500: if (!--arrows_left) {
501: no_arrows();
502: return(1);
503: }
504:
505: {
506:
507: static int lastchance = 2;
508:
509: if (random() % level == EASY ? 12 : 9 < (lastchance += 2)) {
510: move_wump();
511: if (wumpus_loc == player_loc)
512: wump_kill();
513: lastchance = random() % 3;
514:
515: }
516: }
517: return(0);
518: }
519:
520: int
521: gcd(a, b)
522: int a, b;
523: {
524: int r;
525:
526: r = a % b;
527: if (r == 0)
528: return (b);
529: return (gcd(b, r));
530: }
531:
532: void
533: cave_init()
534: {
535: int i, j, k, link;
536: int delta;
537:
538:
539:
540:
541:
542:
543:
544:
545:
546:
547: srandom((int)time((time_t *)0));
548:
549:
550: for (i = 1; i <= room_num; ++i)
551: for (j = 0; j < link_num ; ++j)
552: cave[i].tunnel[j] = -1;
553:
554:
555:
556:
557:
558:
559: do {
560: delta = (random() % (room_num - 1)) + 1;
561: } while (gcd(room_num, delta + 1) != 1);
562:
563: for (i = 1; i <= room_num; ++i) {
564: link = ((i + delta) % room_num) + 1;
565: cave[i].tunnel[0] = link;
566: cave[link].tunnel[1] = i;
567: }
568:
569: for (i = 1; i <= room_num; i++)
570: for (j = 2; j < link_num ; j++) {
571: if (cave[i].tunnel[j] != -1)
572: continue;
573: try_again: